Merge "Annotate with @NonNull DefaultLifecycleObserver" into oc-mr1-support-27.0-dev
diff --git a/annotations/api/current.txt b/annotations/api/current.txt
index c52f7e1..901e8f7 100644
--- a/annotations/api/current.txt
+++ b/annotations/api/current.txt
@@ -93,6 +93,9 @@
   public abstract class MenuRes implements java.lang.annotation.Annotation {
   }
 
+  public abstract class NavigationRes implements java.lang.annotation.Annotation {
+  }
+
   public abstract class NonNull implements java.lang.annotation.Annotation {
   }
 
diff --git a/annotations/src/android/support/annotation/NavigationRes.java b/annotations/src/android/support/annotation/NavigationRes.java
new file mode 100644
index 0000000..a051026
--- /dev/null
+++ b/annotations/src/android/support/annotation/NavigationRes.java
@@ -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.
+ */
+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.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 navigation resource reference (e.g. {@code R.navigation.flow}).
+ */
+@Documented
+@Retention(CLASS)
+@Target({METHOD, PARAMETER, FIELD, LOCAL_VARIABLE})
+public @interface NavigationRes {
+}
diff --git a/buildSrc/src/main/java/android/support/LibraryVersions.java b/buildSrc/src/main/java/android/support/LibraryVersions.java
index dbc9da6..710a7d3 100644
--- a/buildSrc/src/main/java/android/support/LibraryVersions.java
+++ b/buildSrc/src/main/java/android/support/LibraryVersions.java
@@ -48,7 +48,7 @@
     /**
      * Version code for Lifecycle libs that are required by the support library
      */
-    public static final Version LIFECYCLES_CORE = new Version("1.0.1");
+    public static final Version LIFECYCLES_CORE = new Version("1.0.2");
 
     /**
      * Version code for Lifecycle runtime libs that are required by the support library
diff --git a/compat/Android.mk b/compat/Android.mk
index cd62336..e16bba6 100644
--- a/compat/Android.mk
+++ b/compat/Android.mk
@@ -25,10 +25,10 @@
 LOCAL_USE_AAPT2 := true
 LOCAL_MODULE := android-support-compat
 LOCAL_SDK_VERSION := $(SUPPORT_CURRENT_SDK_VERSION)
-LOCAL_AIDL_INCLUDES := $(LOCAL_PATH)/java
+LOCAL_AIDL_INCLUDES := $(LOCAL_PATH)/src/main/java
 LOCAL_SRC_FILES := \
-    $(call all-java-files-under,java) \
-    $(call all-Iaidl-files-under,java)
+    $(call all-java-files-under,src/main/java) \
+    $(call all-Iaidl-files-under,src/main/java)
 LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
 LOCAL_SHARED_ANDROID_LIBRARIES := \
     android-support-annotations
diff --git a/compat/api/current.txt b/compat/api/current.txt
index c603a03..8f48f36 100644
--- a/compat/api/current.txt
+++ b/compat/api/current.txt
@@ -700,6 +700,13 @@
     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;
     method public static android.graphics.Typeface getFont(android.content.Context, int) throws android.content.res.Resources.NotFoundException;
+    method public static void getFont(android.content.Context, int, android.support.v4.content.res.ResourcesCompat.FontCallback, android.os.Handler) throws android.content.res.Resources.NotFoundException;
+  }
+
+  public static abstract class ResourcesCompat.FontCallback {
+    ctor public ResourcesCompat.FontCallback();
+    method public abstract void onFontRetrievalFailed(int);
+    method public abstract void onFontRetrieved(android.graphics.Typeface);
   }
 
 }
@@ -962,6 +969,7 @@
     field public static final int FAIL_REASON_FONT_UNAVAILABLE = 2; // 0x2
     field public static final int FAIL_REASON_MALFORMED_QUERY = 3; // 0x3
     field public static final int FAIL_REASON_PROVIDER_NOT_FOUND = -1; // 0xffffffff
+    field public static final int FAIL_REASON_SECURITY_VIOLATION = -4; // 0xfffffffc
     field public static final int FAIL_REASON_WRONG_CERTIFICATES = -2; // 0xfffffffe
   }
 
diff --git a/compat/build.gradle b/compat/build.gradle
index 66ae6f3..4d869b8 100644
--- a/compat/build.gradle
+++ b/compat/build.gradle
@@ -19,8 +19,7 @@
     }
 
     sourceSets {
-        main.java.srcDirs = ['java']
-        main.aidl.srcDirs = ['java']
+        main.aidl.srcDirs = ['src/main/java']
         main.res.srcDirs 'res', 'res-public'
     }
 
diff --git a/compat/java/android/support/v4/content/res/ResourcesCompat.java b/compat/java/android/support/v4/content/res/ResourcesCompat.java
deleted file mode 100644
index 43d78d0..0000000
--- a/compat/java/android/support/v4/content/res/ResourcesCompat.java
+++ /dev/null
@@ -1,262 +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 static android.os.Build.VERSION.SDK_INT;
-import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
-
-import android.content.Context;
-import android.content.res.ColorStateList;
-import android.content.res.Resources;
-import android.content.res.Resources.NotFoundException;
-import android.content.res.Resources.Theme;
-import android.content.res.XmlResourceParser;
-import android.graphics.Typeface;
-import android.graphics.drawable.Drawable;
-import android.support.annotation.ColorInt;
-import android.support.annotation.ColorRes;
-import android.support.annotation.DrawableRes;
-import android.support.annotation.FontRes;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.annotation.RestrictTo;
-import android.support.v4.content.res.FontResourcesParserCompat.FamilyResourceEntry;
-import android.support.v4.graphics.TypefaceCompat;
-import android.util.Log;
-import android.util.TypedValue;
-import android.widget.TextView;
-
-import org.xmlpull.v1.XmlPullParserException;
-
-import java.io.IOException;
-
-/**
- * Helper for accessing features in {@link android.content.res.Resources}.
- */
-public final class ResourcesCompat {
-    private static final String TAG = "ResourcesCompat";
-
-    /**
-     * Return a drawable object associated with a particular resource ID and
-     * styled for the specified theme. Various types of objects will be
-     * returned depending on the underlying resource -- for example, a solid
-     * color, PNG image, scalable image, etc.
-     * <p>
-     * Prior to API level 21, the theme will not be applied and this method
-     * simply calls through to {@link Resources#getDrawable(int)}.
-     *
-     * @param id The desired resource identifier, as generated by the aapt
-     *           tool. This integer encodes the package, type, and resource
-     *           entry. The value 0 is an invalid identifier.
-     * @param theme The theme used to style the drawable attributes, may be
-     *              {@code null}.
-     * @return Drawable An object that can be used to draw this resource.
-     * @throws NotFoundException Throws NotFoundException if the given ID does
-     *         not exist.
-     */
-    @Nullable
-    @SuppressWarnings("deprecation")
-    public static Drawable getDrawable(@NonNull Resources res, @DrawableRes int id,
-            @Nullable Theme theme) throws NotFoundException {
-        if (SDK_INT >= 21) {
-            return res.getDrawable(id, theme);
-        } else {
-            return res.getDrawable(id);
-        }
-    }
-
-
-    /**
-     * Return a drawable object associated with a particular resource ID for
-     * the given screen density in DPI and styled for the specified theme.
-     * <p>
-     * Prior to API level 15, the theme and density will not be applied and
-     * this method simply calls through to {@link Resources#getDrawable(int)}.
-     * <p>
-     * Prior to API level 21, the theme will not be applied and this method
-     * calls through to Resources#getDrawableForDensity(int, int).
-     *
-     * @param id The desired resource identifier, as generated by the aapt
-     *           tool. This integer encodes the package, type, and resource
-     *           entry. The value 0 is an invalid identifier.
-     * @param density The desired screen density indicated by the resource as
-     *                found in {@link android.util.DisplayMetrics}.
-     * @param theme The theme used to style the drawable attributes, may be
-     *              {@code null}.
-     * @return Drawable An object that can be used to draw this resource.
-     * @throws NotFoundException Throws NotFoundException if the given ID does
-     *         not exist.
-     */
-    @Nullable
-    @SuppressWarnings("deprecation")
-    public static Drawable getDrawableForDensity(@NonNull Resources res, @DrawableRes int id,
-            int density, @Nullable Theme theme) throws NotFoundException {
-        if (SDK_INT >= 21) {
-            return res.getDrawableForDensity(id, density, theme);
-        } else if (SDK_INT >= 15) {
-            return res.getDrawableForDensity(id, density);
-        } else {
-            return res.getDrawable(id);
-        }
-    }
-
-    /**
-     * Returns a themed color integer associated with a particular resource ID.
-     * If the resource holds a complex {@link ColorStateList}, then the default
-     * color from the set is returned.
-     * <p>
-     * Prior to API level 23, the theme will not be applied and this method
-     * calls through to {@link Resources#getColor(int)}.
-     *
-     * @param id The desired resource identifier, as generated by the aapt
-     *           tool. This integer encodes the package, type, and resource
-     *           entry. The value 0 is an invalid identifier.
-     * @param theme The theme used to style the color attributes, may be
-     *              {@code null}.
-     * @return A single color value in the form {@code 0xAARRGGBB}.
-     * @throws NotFoundException Throws NotFoundException if the given ID does
-     *         not exist.
-     */
-    @ColorInt
-    @SuppressWarnings("deprecation")
-    public static int getColor(@NonNull Resources res, @ColorRes int id, @Nullable Theme theme)
-            throws NotFoundException {
-        if (SDK_INT >= 23) {
-            return res.getColor(id, theme);
-        } else {
-            return res.getColor(id);
-        }
-    }
-
-    /**
-     * Returns a themed color state list associated with a particular resource
-     * ID. The resource may contain either a single raw color value or a
-     * complex {@link ColorStateList} holding multiple possible colors.
-     * <p>
-     * Prior to API level 23, the theme will not be applied and this method
-     * calls through to {@link Resources#getColorStateList(int)}.
-     *
-     * @param id The desired resource identifier of a {@link ColorStateList},
-     *           as generated by the aapt tool. This integer encodes the
-     *           package, type, and resource entry. The value 0 is an invalid
-     *           identifier.
-     * @param theme The theme used to style the color attributes, may be
-     *              {@code null}.
-     * @return A themed ColorStateList object containing either a single solid
-     *         color or multiple colors that can be selected based on a state.
-     * @throws NotFoundException Throws NotFoundException if the given ID does
-     *         not exist.
-     */
-    @Nullable
-    @SuppressWarnings("deprecation")
-    public static ColorStateList getColorStateList(@NonNull Resources res, @ColorRes int id,
-            @Nullable Theme theme) throws NotFoundException {
-        if (SDK_INT >= 23) {
-            return res.getColorStateList(id, theme);
-        } else {
-            return res.getColorStateList(id);
-        }
-    }
-
-    /**
-     * Returns a font Typeface associated with a particular resource ID.
-     * <p>
-     * Prior to API level 23, font resources with more than one font in a family will only load the
-     * first font in that family.
-     *
-     * @param context A context to retrieve the Resources from.
-     * @param id The desired resource identifier of a {@link Typeface},
-     *           as generated by the aapt tool. This integer encodes the
-     *           package, type, and resource entry. The value 0 is an invalid
-     *           identifier.
-     * @return A font Typeface object.
-     * @throws NotFoundException Throws NotFoundException if the given ID does
-     *         not exist.
-     */
-    @Nullable
-    public static Typeface getFont(@NonNull Context context, @FontRes int id)
-            throws NotFoundException {
-        if (context.isRestricted()) {
-            return null;
-        }
-        return loadFont(context, id, new TypedValue(), Typeface.NORMAL, null);
-    }
-
-    /** @hide */
-    @RestrictTo(LIBRARY_GROUP)
-    public static Typeface getFont(@NonNull Context context, @FontRes int id, TypedValue value,
-            int style, @Nullable TextView targetView) throws NotFoundException {
-        if (context.isRestricted()) {
-            return null;
-        }
-        return loadFont(context, id, value, style, targetView);
-    }
-
-    private static Typeface loadFont(@NonNull Context context, int id, TypedValue value,
-            int style, @Nullable TextView targetView) {
-        final Resources resources = context.getResources();
-        resources.getValue(id, value, true);
-        Typeface typeface = loadFont(context, resources, value, id, style, targetView);
-        if (typeface != null) {
-            return typeface;
-        }
-        throw new NotFoundException("Font resource ID #0x"
-                + Integer.toHexString(id));
-    }
-
-    private static Typeface loadFont(
-            @NonNull Context context, Resources wrapper, TypedValue value, int id, int style,
-            @Nullable TextView targetView) {
-        if (value.string == null) {
-            throw new NotFoundException("Resource \"" + wrapper.getResourceName(id) + "\" ("
-                    + Integer.toHexString(id) + ") is not a Font: " + value);
-        }
-
-        final String file = value.string.toString();
-        if (!file.startsWith("res/")) {
-            // Early exit if the specified string is unlikely to the resource path.
-            return null;
-        }
-
-        Typeface cached = TypefaceCompat.findFromCache(wrapper, id, style);
-        if (cached != null) {
-            return cached;
-        }
-
-        try {
-            if (file.toLowerCase().endsWith(".xml")) {
-                final XmlResourceParser rp = wrapper.getXml(id);
-                final FamilyResourceEntry familyEntry =
-                        FontResourcesParserCompat.parse(rp, wrapper);
-                if (familyEntry == null) {
-                    Log.e(TAG, "Failed to find font-family tag");
-                    return null;
-                }
-                return TypefaceCompat.createFromResourcesFamilyXml(
-                        context, familyEntry, wrapper, id, style, targetView);
-            }
-            return TypefaceCompat.createFromResourcesFontFile(context, wrapper, id, file, style);
-        } catch (XmlPullParserException e) {
-            Log.e(TAG, "Failed to parse xml resource " + file, e);
-        } catch (IOException e) {
-            Log.e(TAG, "Failed to read xml resource " + file, e);
-        }
-        return null;
-    }
-
-    private ResourcesCompat() {}
-}
diff --git a/compat/res/values/attrs.xml b/compat/res/values/attrs.xml
index 1833794..fd4049b 100644
--- a/compat/res/values/attrs.xml
+++ b/compat/res/values/attrs.xml
@@ -32,7 +32,12 @@
         documentation for these values. -->
         <attr name="fontProviderCerts" format="reference" />
         <!-- The strategy to be used when fetching font data from a font provider in XML layouts.
-          -->
+        This attribute is ignored when the resource is loaded from code, as it is equivalent to the
+        choice of API between {@link
+        android.support.v4.content.res.ResourcesCompat#getFont(Context, int)} (blocking) and
+        {@link
+        android.support.v4.content.res.ResourcesCompat#getFont(Context, int, FontCallback, Handler)}
+        (async). -->
         <attr name="fontProviderFetchStrategy">
             <!-- The blocking font fetch works as follows.
               First, check the local cache, then if the requested font is not cached, request the
diff --git a/compat/java/android/support/v4/accessibilityservice/AccessibilityServiceInfoCompat.java b/compat/src/main/java/android/support/v4/accessibilityservice/AccessibilityServiceInfoCompat.java
similarity index 100%
rename from compat/java/android/support/v4/accessibilityservice/AccessibilityServiceInfoCompat.java
rename to compat/src/main/java/android/support/v4/accessibilityservice/AccessibilityServiceInfoCompat.java
diff --git a/compat/java/android/support/v4/accessibilityservice/package.html b/compat/src/main/java/android/support/v4/accessibilityservice/package.html
similarity index 100%
rename from compat/java/android/support/v4/accessibilityservice/package.html
rename to compat/src/main/java/android/support/v4/accessibilityservice/package.html
diff --git a/compat/java/android/support/v4/app/ActivityCompat.java b/compat/src/main/java/android/support/v4/app/ActivityCompat.java
similarity index 100%
rename from compat/java/android/support/v4/app/ActivityCompat.java
rename to compat/src/main/java/android/support/v4/app/ActivityCompat.java
diff --git a/compat/java/android/support/v4/app/ActivityManagerCompat.java b/compat/src/main/java/android/support/v4/app/ActivityManagerCompat.java
similarity index 100%
rename from compat/java/android/support/v4/app/ActivityManagerCompat.java
rename to compat/src/main/java/android/support/v4/app/ActivityManagerCompat.java
diff --git a/compat/java/android/support/v4/app/ActivityOptionsCompat.java b/compat/src/main/java/android/support/v4/app/ActivityOptionsCompat.java
similarity index 100%
rename from compat/java/android/support/v4/app/ActivityOptionsCompat.java
rename to compat/src/main/java/android/support/v4/app/ActivityOptionsCompat.java
diff --git a/compat/java/android/support/v4/app/AlarmManagerCompat.java b/compat/src/main/java/android/support/v4/app/AlarmManagerCompat.java
similarity index 100%
rename from compat/java/android/support/v4/app/AlarmManagerCompat.java
rename to compat/src/main/java/android/support/v4/app/AlarmManagerCompat.java
diff --git a/compat/java/android/support/v4/app/AppOpsManagerCompat.java b/compat/src/main/java/android/support/v4/app/AppOpsManagerCompat.java
similarity index 100%
rename from compat/java/android/support/v4/app/AppOpsManagerCompat.java
rename to compat/src/main/java/android/support/v4/app/AppOpsManagerCompat.java
diff --git a/compat/java/android/support/v4/app/BundleCompat.java b/compat/src/main/java/android/support/v4/app/BundleCompat.java
similarity index 100%
rename from compat/java/android/support/v4/app/BundleCompat.java
rename to compat/src/main/java/android/support/v4/app/BundleCompat.java
diff --git a/compat/java/android/support/v4/app/INotificationSideChannel.aidl b/compat/src/main/java/android/support/v4/app/INotificationSideChannel.aidl
similarity index 100%
rename from compat/java/android/support/v4/app/INotificationSideChannel.aidl
rename to compat/src/main/java/android/support/v4/app/INotificationSideChannel.aidl
diff --git a/compat/java/android/support/v4/app/JobIntentService.java b/compat/src/main/java/android/support/v4/app/JobIntentService.java
similarity index 100%
rename from compat/java/android/support/v4/app/JobIntentService.java
rename to compat/src/main/java/android/support/v4/app/JobIntentService.java
diff --git a/compat/java/android/support/v4/app/NotificationBuilderWithBuilderAccessor.java b/compat/src/main/java/android/support/v4/app/NotificationBuilderWithBuilderAccessor.java
similarity index 100%
rename from compat/java/android/support/v4/app/NotificationBuilderWithBuilderAccessor.java
rename to compat/src/main/java/android/support/v4/app/NotificationBuilderWithBuilderAccessor.java
diff --git a/compat/java/android/support/v4/app/NotificationCompat.java b/compat/src/main/java/android/support/v4/app/NotificationCompat.java
similarity index 100%
rename from compat/java/android/support/v4/app/NotificationCompat.java
rename to compat/src/main/java/android/support/v4/app/NotificationCompat.java
diff --git a/compat/java/android/support/v4/app/NotificationCompatBuilder.java b/compat/src/main/java/android/support/v4/app/NotificationCompatBuilder.java
similarity index 100%
rename from compat/java/android/support/v4/app/NotificationCompatBuilder.java
rename to compat/src/main/java/android/support/v4/app/NotificationCompatBuilder.java
diff --git a/compat/java/android/support/v4/app/NotificationCompatExtras.java b/compat/src/main/java/android/support/v4/app/NotificationCompatExtras.java
similarity index 100%
rename from compat/java/android/support/v4/app/NotificationCompatExtras.java
rename to compat/src/main/java/android/support/v4/app/NotificationCompatExtras.java
diff --git a/compat/java/android/support/v4/app/NotificationCompatJellybean.java b/compat/src/main/java/android/support/v4/app/NotificationCompatJellybean.java
similarity index 100%
rename from compat/java/android/support/v4/app/NotificationCompatJellybean.java
rename to compat/src/main/java/android/support/v4/app/NotificationCompatJellybean.java
diff --git a/compat/java/android/support/v4/app/NotificationCompatSideChannelService.java b/compat/src/main/java/android/support/v4/app/NotificationCompatSideChannelService.java
similarity index 100%
rename from compat/java/android/support/v4/app/NotificationCompatSideChannelService.java
rename to compat/src/main/java/android/support/v4/app/NotificationCompatSideChannelService.java
diff --git a/compat/java/android/support/v4/app/NotificationManagerCompat.java b/compat/src/main/java/android/support/v4/app/NotificationManagerCompat.java
similarity index 100%
rename from compat/java/android/support/v4/app/NotificationManagerCompat.java
rename to compat/src/main/java/android/support/v4/app/NotificationManagerCompat.java
diff --git a/compat/java/android/support/v4/app/RemoteInput.java b/compat/src/main/java/android/support/v4/app/RemoteInput.java
similarity index 100%
rename from compat/java/android/support/v4/app/RemoteInput.java
rename to compat/src/main/java/android/support/v4/app/RemoteInput.java
diff --git a/compat/java/android/support/v4/app/RemoteInputCompatBase.java b/compat/src/main/java/android/support/v4/app/RemoteInputCompatBase.java
similarity index 100%
rename from compat/java/android/support/v4/app/RemoteInputCompatBase.java
rename to compat/src/main/java/android/support/v4/app/RemoteInputCompatBase.java
diff --git a/compat/java/android/support/v4/app/ServiceCompat.java b/compat/src/main/java/android/support/v4/app/ServiceCompat.java
similarity index 100%
rename from compat/java/android/support/v4/app/ServiceCompat.java
rename to compat/src/main/java/android/support/v4/app/ServiceCompat.java
diff --git a/compat/java/android/support/v4/app/ShareCompat.java b/compat/src/main/java/android/support/v4/app/ShareCompat.java
similarity index 100%
rename from compat/java/android/support/v4/app/ShareCompat.java
rename to compat/src/main/java/android/support/v4/app/ShareCompat.java
diff --git a/compat/java/android/support/v4/app/SharedElementCallback.java b/compat/src/main/java/android/support/v4/app/SharedElementCallback.java
similarity index 100%
rename from compat/java/android/support/v4/app/SharedElementCallback.java
rename to compat/src/main/java/android/support/v4/app/SharedElementCallback.java
diff --git a/compat/java/android/support/v4/app/SupportActivity.java b/compat/src/main/java/android/support/v4/app/SupportActivity.java
similarity index 100%
rename from compat/java/android/support/v4/app/SupportActivity.java
rename to compat/src/main/java/android/support/v4/app/SupportActivity.java
diff --git a/compat/java/android/support/v4/app/package.html b/compat/src/main/java/android/support/v4/app/package.html
similarity index 100%
rename from compat/java/android/support/v4/app/package.html
rename to compat/src/main/java/android/support/v4/app/package.html
diff --git a/compat/java/android/support/v4/content/ContentResolverCompat.java b/compat/src/main/java/android/support/v4/content/ContentResolverCompat.java
similarity index 100%
rename from compat/java/android/support/v4/content/ContentResolverCompat.java
rename to compat/src/main/java/android/support/v4/content/ContentResolverCompat.java
diff --git a/compat/java/android/support/v4/content/ContextCompat.java b/compat/src/main/java/android/support/v4/content/ContextCompat.java
similarity index 100%
rename from compat/java/android/support/v4/content/ContextCompat.java
rename to compat/src/main/java/android/support/v4/content/ContextCompat.java
diff --git a/compat/java/android/support/v4/content/IntentCompat.java b/compat/src/main/java/android/support/v4/content/IntentCompat.java
similarity index 100%
rename from compat/java/android/support/v4/content/IntentCompat.java
rename to compat/src/main/java/android/support/v4/content/IntentCompat.java
diff --git a/compat/java/android/support/v4/content/SharedPreferencesCompat.java b/compat/src/main/java/android/support/v4/content/SharedPreferencesCompat.java
similarity index 100%
rename from compat/java/android/support/v4/content/SharedPreferencesCompat.java
rename to compat/src/main/java/android/support/v4/content/SharedPreferencesCompat.java
diff --git a/compat/java/android/support/v4/content/package.html b/compat/src/main/java/android/support/v4/content/package.html
similarity index 100%
rename from compat/java/android/support/v4/content/package.html
rename to compat/src/main/java/android/support/v4/content/package.html
diff --git a/compat/java/android/support/v4/content/pm/ActivityInfoCompat.java b/compat/src/main/java/android/support/v4/content/pm/ActivityInfoCompat.java
similarity index 100%
rename from compat/java/android/support/v4/content/pm/ActivityInfoCompat.java
rename to compat/src/main/java/android/support/v4/content/pm/ActivityInfoCompat.java
diff --git a/compat/java/android/support/v4/content/pm/ShortcutInfoCompat.java b/compat/src/main/java/android/support/v4/content/pm/ShortcutInfoCompat.java
similarity index 100%
rename from compat/java/android/support/v4/content/pm/ShortcutInfoCompat.java
rename to compat/src/main/java/android/support/v4/content/pm/ShortcutInfoCompat.java
diff --git a/compat/java/android/support/v4/content/pm/ShortcutManagerCompat.java b/compat/src/main/java/android/support/v4/content/pm/ShortcutManagerCompat.java
similarity index 100%
rename from compat/java/android/support/v4/content/pm/ShortcutManagerCompat.java
rename to compat/src/main/java/android/support/v4/content/pm/ShortcutManagerCompat.java
diff --git a/compat/java/android/support/v4/content/pm/package.html b/compat/src/main/java/android/support/v4/content/pm/package.html
similarity index 100%
rename from compat/java/android/support/v4/content/pm/package.html
rename to compat/src/main/java/android/support/v4/content/pm/package.html
diff --git a/compat/java/android/support/v4/content/res/ConfigurationHelper.java b/compat/src/main/java/android/support/v4/content/res/ConfigurationHelper.java
similarity index 100%
rename from compat/java/android/support/v4/content/res/ConfigurationHelper.java
rename to compat/src/main/java/android/support/v4/content/res/ConfigurationHelper.java
diff --git a/compat/java/android/support/v4/content/res/FontResourcesParserCompat.java b/compat/src/main/java/android/support/v4/content/res/FontResourcesParserCompat.java
similarity index 100%
rename from compat/java/android/support/v4/content/res/FontResourcesParserCompat.java
rename to compat/src/main/java/android/support/v4/content/res/FontResourcesParserCompat.java
diff --git a/compat/src/main/java/android/support/v4/content/res/ResourcesCompat.java b/compat/src/main/java/android/support/v4/content/res/ResourcesCompat.java
new file mode 100644
index 0000000..4c70ce9
--- /dev/null
+++ b/compat/src/main/java/android/support/v4/content/res/ResourcesCompat.java
@@ -0,0 +1,417 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF 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.os.Build.VERSION.SDK_INT;
+import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
+
+import android.content.Context;
+import android.content.res.ColorStateList;
+import android.content.res.Resources;
+import android.content.res.Resources.NotFoundException;
+import android.content.res.Resources.Theme;
+import android.content.res.XmlResourceParser;
+import android.graphics.Typeface;
+import android.graphics.drawable.Drawable;
+import android.os.Handler;
+import android.os.Looper;
+import android.support.annotation.ColorInt;
+import android.support.annotation.ColorRes;
+import android.support.annotation.DrawableRes;
+import android.support.annotation.FontRes;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.annotation.RestrictTo;
+import android.support.v4.content.res.FontResourcesParserCompat.FamilyResourceEntry;
+import android.support.v4.graphics.TypefaceCompat;
+import android.support.v4.provider.FontsContractCompat.FontRequestCallback;
+import android.support.v4.provider.FontsContractCompat.FontRequestCallback.FontRequestFailReason;
+import android.support.v4.util.Preconditions;
+import android.util.Log;
+import android.util.TypedValue;
+
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+
+/**
+ * Helper for accessing features in {@link android.content.res.Resources}.
+ */
+public final class ResourcesCompat {
+    private static final String TAG = "ResourcesCompat";
+
+    /**
+     * Return a drawable object associated with a particular resource ID and
+     * styled for the specified theme. Various types of objects will be
+     * returned depending on the underlying resource -- for example, a solid
+     * color, PNG image, scalable image, etc.
+     * <p>
+     * Prior to API level 21, the theme will not be applied and this method
+     * simply calls through to {@link Resources#getDrawable(int)}.
+     *
+     * @param id The desired resource identifier, as generated by the aapt
+     *           tool. This integer encodes the package, type, and resource
+     *           entry. The value 0 is an invalid identifier.
+     * @param theme The theme used to style the drawable attributes, may be
+     *              {@code null}.
+     * @return Drawable An object that can be used to draw this resource.
+     * @throws NotFoundException Throws NotFoundException if the given ID does
+     *         not exist.
+     */
+    @Nullable
+    @SuppressWarnings("deprecation")
+    public static Drawable getDrawable(@NonNull Resources res, @DrawableRes int id,
+            @Nullable Theme theme) throws NotFoundException {
+        if (SDK_INT >= 21) {
+            return res.getDrawable(id, theme);
+        } else {
+            return res.getDrawable(id);
+        }
+    }
+
+
+    /**
+     * Return a drawable object associated with a particular resource ID for
+     * the given screen density in DPI and styled for the specified theme.
+     * <p>
+     * Prior to API level 15, the theme and density will not be applied and
+     * this method simply calls through to {@link Resources#getDrawable(int)}.
+     * <p>
+     * Prior to API level 21, the theme will not be applied and this method
+     * calls through to Resources#getDrawableForDensity(int, int).
+     *
+     * @param id The desired resource identifier, as generated by the aapt
+     *           tool. This integer encodes the package, type, and resource
+     *           entry. The value 0 is an invalid identifier.
+     * @param density The desired screen density indicated by the resource as
+     *                found in {@link android.util.DisplayMetrics}.
+     * @param theme The theme used to style the drawable attributes, may be
+     *              {@code null}.
+     * @return Drawable An object that can be used to draw this resource.
+     * @throws NotFoundException Throws NotFoundException if the given ID does
+     *         not exist.
+     */
+    @Nullable
+    @SuppressWarnings("deprecation")
+    public static Drawable getDrawableForDensity(@NonNull Resources res, @DrawableRes int id,
+            int density, @Nullable Theme theme) throws NotFoundException {
+        if (SDK_INT >= 21) {
+            return res.getDrawableForDensity(id, density, theme);
+        } else if (SDK_INT >= 15) {
+            return res.getDrawableForDensity(id, density);
+        } else {
+            return res.getDrawable(id);
+        }
+    }
+
+    /**
+     * Returns a themed color integer associated with a particular resource ID.
+     * If the resource holds a complex {@link ColorStateList}, then the default
+     * color from the set is returned.
+     * <p>
+     * Prior to API level 23, the theme will not be applied and this method
+     * calls through to {@link Resources#getColor(int)}.
+     *
+     * @param id The desired resource identifier, as generated by the aapt
+     *           tool. This integer encodes the package, type, and resource
+     *           entry. The value 0 is an invalid identifier.
+     * @param theme The theme used to style the color attributes, may be
+     *              {@code null}.
+     * @return A single color value in the form {@code 0xAARRGGBB}.
+     * @throws NotFoundException Throws NotFoundException if the given ID does
+     *         not exist.
+     */
+    @ColorInt
+    @SuppressWarnings("deprecation")
+    public static int getColor(@NonNull Resources res, @ColorRes int id, @Nullable Theme theme)
+            throws NotFoundException {
+        if (SDK_INT >= 23) {
+            return res.getColor(id, theme);
+        } else {
+            return res.getColor(id);
+        }
+    }
+
+    /**
+     * Returns a themed color state list associated with a particular resource
+     * ID. The resource may contain either a single raw color value or a
+     * complex {@link ColorStateList} holding multiple possible colors.
+     * <p>
+     * Prior to API level 23, the theme will not be applied and this method
+     * calls through to {@link Resources#getColorStateList(int)}.
+     *
+     * @param id The desired resource identifier of a {@link ColorStateList},
+     *           as generated by the aapt tool. This integer encodes the
+     *           package, type, and resource entry. The value 0 is an invalid
+     *           identifier.
+     * @param theme The theme used to style the color attributes, may be
+     *              {@code null}.
+     * @return A themed ColorStateList object containing either a single solid
+     *         color or multiple colors that can be selected based on a state.
+     * @throws NotFoundException Throws NotFoundException if the given ID does
+     *         not exist.
+     */
+    @Nullable
+    @SuppressWarnings("deprecation")
+    public static ColorStateList getColorStateList(@NonNull Resources res, @ColorRes int id,
+            @Nullable Theme theme) throws NotFoundException {
+        if (SDK_INT >= 23) {
+            return res.getColorStateList(id, theme);
+        } else {
+            return res.getColorStateList(id);
+        }
+    }
+
+    /**
+     * Returns a font Typeface associated with a particular resource ID.
+     * <p>
+     * This method will block the calling thread to retrieve the requested font, including if it
+     * is from a font provider. If you wish to not have this behavior, use
+     * {@link #getFont(Context, int, FontCallback, Handler)} instead.
+     * <p>
+     * Prior to API level 23, font resources with more than one font in a family will only load the
+     * font closest to a regular weight typeface.
+     *
+     * @param context A context to retrieve the Resources from.
+     * @param id The desired resource identifier of a {@link Typeface},
+     *           as generated by the aapt tool. This integer encodes the
+     *           package, type, and resource entry. The value 0 is an invalid
+     *           identifier.
+     * @return A font Typeface object.
+     * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
+     *
+     * @see #getFont(Context, int, FontCallback, Handler)
+     */
+    @Nullable
+    public static Typeface getFont(@NonNull Context context, @FontRes int id)
+            throws NotFoundException {
+        if (context.isRestricted()) {
+            return null;
+        }
+        return loadFont(context, id, new TypedValue(), Typeface.NORMAL, null /* callback */,
+                null /* handler */, false /* isXmlRequest */);
+    }
+
+    /**
+     * Interface used to receive asynchronous font fetching events.
+     */
+    public abstract static class FontCallback {
+
+        /**
+         * Called when an asynchronous font was finished loading.
+         *
+         * @param typeface The font that was loaded.
+         */
+        public abstract void onFontRetrieved(@NonNull Typeface typeface);
+
+        /**
+         * Called when an asynchronous font failed to load.
+         *
+         * @param reason The reason the font failed to load. One of
+         *      {@link FontRequestFailReason#FAIL_REASON_PROVIDER_NOT_FOUND},
+         *      {@link FontRequestFailReason#FAIL_REASON_WRONG_CERTIFICATES},
+         *      {@link FontRequestFailReason#FAIL_REASON_FONT_LOAD_ERROR},
+         *      {@link FontRequestFailReason#FAIL_REASON_SECURITY_VIOLATION},
+         *      {@link FontRequestFailReason#FAIL_REASON_FONT_NOT_FOUND},
+         *      {@link FontRequestFailReason#FAIL_REASON_FONT_UNAVAILABLE} or
+         *      {@link FontRequestFailReason#FAIL_REASON_MALFORMED_QUERY}.
+         */
+        public abstract void onFontRetrievalFailed(@FontRequestFailReason int reason);
+
+        /**
+         * Call {@link #onFontRetrieved(Typeface)} on the handler given, or the Ui Thread if it is
+         * null.
+         * @hide
+         */
+        @RestrictTo(LIBRARY_GROUP)
+        public final void callbackSuccessAsync(final Typeface typeface, @Nullable Handler handler) {
+            if (handler == null) {
+                handler = new Handler(Looper.getMainLooper());
+            }
+            handler.post(new Runnable() {
+                @Override
+                public void run() {
+                    onFontRetrieved(typeface);
+                }
+            });
+        }
+
+        /**
+         * Call {@link #onFontRetrievalFailed(int)} on the handler given, or the Ui Thread if it is
+         * null.
+         * @hide
+         */
+        @RestrictTo(LIBRARY_GROUP)
+        public final void callbackFailAsync(
+                @FontRequestFailReason final int reason, @Nullable Handler handler) {
+            if (handler == null) {
+                handler = new Handler(Looper.getMainLooper());
+            }
+            handler.post(new Runnable() {
+                @Override
+                public void run() {
+                    onFontRetrievalFailed(reason);
+                }
+            });
+        }
+    }
+
+    /**
+     * Returns a font Typeface associated with a particular resource ID asynchronously.
+     * <p>
+     * Prior to API level 23, font resources with more than one font in a family will only load the
+     * font closest to a regular weight typeface.
+     * </p>
+     *
+     * @param context A context to retrieve the Resources from.
+     * @param id The desired resource identifier of a {@link Typeface}, as generated by the aapt
+     *           tool. This integer encodes the package, type, and resource entry. The value 0 is an
+     *           invalid identifier.
+     * @param fontCallback A callback to receive async fetching of this font. The callback will be
+     *           triggered on the UI thread.
+     * @param handler A handler for the thread the callback should be called on. If null, the
+     *           callback will be called on the UI thread.
+     * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
+     */
+    public static void getFont(@NonNull Context context, @FontRes int id,
+            @NonNull FontCallback fontCallback, @Nullable Handler handler)
+            throws NotFoundException {
+        Preconditions.checkNotNull(fontCallback);
+        if (context.isRestricted()) {
+            fontCallback.callbackFailAsync(
+                    FontRequestCallback.FAIL_REASON_SECURITY_VIOLATION, handler);
+            return;
+        }
+        loadFont(context, id, new TypedValue(), Typeface.NORMAL, fontCallback, handler,
+                false /* isXmlRequest */);
+    }
+
+    /**
+     * Used by TintTypedArray.
+     *
+     * @hide
+     */
+    @RestrictTo(LIBRARY_GROUP)
+    public static Typeface getFont(@NonNull Context context, @FontRes int id, TypedValue value,
+            int style) throws NotFoundException {
+        if (context.isRestricted()) {
+            return null;
+        }
+        return loadFont(context, id, value, style, null /* callback */, null /* handler */,
+                true /* isXmlRequest */);
+    }
+
+    /**
+     *
+     * @param context The Context to get Resources from
+     * @param id The Resource id to load
+     * @param value A TypedValue to use in the fetching
+     * @param style The font style to load
+     * @param fontCallback A callback to trigger when the font is fetched or an error occurs
+     * @param handler A handler to the thread the callback should be called on
+     * @param isRequestFromLayoutInflator Whether this request originated from XML. This is used to
+     *                     determine if we use or ignore the fontProviderFetchStrategy attribute in
+     *                     font provider XML fonts.
+     * @return
+     */
+    private static Typeface loadFont(@NonNull Context context, int id, TypedValue value,
+            int style, @Nullable FontCallback fontCallback, @Nullable Handler handler,
+            boolean isRequestFromLayoutInflator) {
+        final Resources resources = context.getResources();
+        resources.getValue(id, value, true);
+        Typeface typeface = loadFont(context, resources, value, id, style, fontCallback, handler,
+                isRequestFromLayoutInflator);
+        if (typeface == null && fontCallback == null) {
+            throw new NotFoundException("Font resource ID #0x"
+                    + Integer.toHexString(id) + " could not be retrieved.");
+        }
+        return typeface;
+    }
+
+    /**
+     * Load the given font. This method will always return null for asynchronous requests, which
+     * provide a fontCallback, as there is no immediate result. When the callback is not provided,
+     * the request is treated as synchronous and fails if async loading is required.
+     */
+    private static Typeface loadFont(
+            @NonNull Context context, Resources wrapper, TypedValue value, int id, int style,
+            @Nullable FontCallback fontCallback, @Nullable Handler handler,
+            boolean isRequestFromLayoutInflator) {
+        if (value.string == null) {
+            throw new NotFoundException("Resource \"" + wrapper.getResourceName(id) + "\" ("
+                    + Integer.toHexString(id) + ") is not a Font: " + value);
+        }
+
+        final String file = value.string.toString();
+        if (!file.startsWith("res/")) {
+            // Early exit if the specified string is unlikely to be a resource path.
+            if (fontCallback != null) {
+                fontCallback.callbackFailAsync(
+                        FontRequestCallback.FAIL_REASON_FONT_LOAD_ERROR, handler);
+            }
+            return null;
+        }
+        Typeface typeface = TypefaceCompat.findFromCache(wrapper, id, style);
+
+        if (typeface != null) {
+            if (fontCallback != null) {
+                fontCallback.callbackSuccessAsync(typeface, handler);
+            }
+            return typeface;
+        }
+
+        try {
+            if (file.toLowerCase().endsWith(".xml")) {
+                final XmlResourceParser rp = wrapper.getXml(id);
+                final FamilyResourceEntry familyEntry =
+                        FontResourcesParserCompat.parse(rp, wrapper);
+                if (familyEntry == null) {
+                    Log.e(TAG, "Failed to find font-family tag");
+                    if (fontCallback != null) {
+                        fontCallback.callbackFailAsync(
+                                FontRequestCallback.FAIL_REASON_FONT_LOAD_ERROR, handler);
+                    }
+                    return null;
+                }
+                return TypefaceCompat.createFromResourcesFamilyXml(context, familyEntry, wrapper,
+                        id, style, fontCallback, handler, isRequestFromLayoutInflator);
+            }
+            typeface = TypefaceCompat.createFromResourcesFontFile(
+                    context, wrapper, id, file, style);
+            if (fontCallback != null) {
+                if (typeface != null) {
+                    fontCallback.callbackSuccessAsync(typeface, handler);
+                } else {
+                    fontCallback.callbackFailAsync(
+                            FontRequestCallback.FAIL_REASON_FONT_LOAD_ERROR, handler);
+                }
+            }
+            return typeface;
+        } catch (XmlPullParserException e) {
+            Log.e(TAG, "Failed to parse xml resource " + file, e);
+        } catch (IOException e) {
+            Log.e(TAG, "Failed to read xml resource " + file, e);
+        }
+        if (fontCallback != null) {
+            fontCallback.callbackFailAsync(
+                    FontRequestCallback.FAIL_REASON_FONT_LOAD_ERROR, handler);
+        }
+        return null;
+    }
+
+    private ResourcesCompat() {}
+}
diff --git a/compat/java/android/support/v4/content/res/TypedArrayUtils.java b/compat/src/main/java/android/support/v4/content/res/TypedArrayUtils.java
similarity index 100%
rename from compat/java/android/support/v4/content/res/TypedArrayUtils.java
rename to compat/src/main/java/android/support/v4/content/res/TypedArrayUtils.java
diff --git a/compat/java/android/support/v4/database/DatabaseUtilsCompat.java b/compat/src/main/java/android/support/v4/database/DatabaseUtilsCompat.java
similarity index 100%
rename from compat/java/android/support/v4/database/DatabaseUtilsCompat.java
rename to compat/src/main/java/android/support/v4/database/DatabaseUtilsCompat.java
diff --git a/compat/java/android/support/v4/database/package.html b/compat/src/main/java/android/support/v4/database/package.html
similarity index 100%
rename from compat/java/android/support/v4/database/package.html
rename to compat/src/main/java/android/support/v4/database/package.html
diff --git a/compat/java/android/support/v4/graphics/BitmapCompat.java b/compat/src/main/java/android/support/v4/graphics/BitmapCompat.java
similarity index 100%
rename from compat/java/android/support/v4/graphics/BitmapCompat.java
rename to compat/src/main/java/android/support/v4/graphics/BitmapCompat.java
diff --git a/compat/java/android/support/v4/graphics/PaintCompat.java b/compat/src/main/java/android/support/v4/graphics/PaintCompat.java
similarity index 100%
rename from compat/java/android/support/v4/graphics/PaintCompat.java
rename to compat/src/main/java/android/support/v4/graphics/PaintCompat.java
diff --git a/compat/java/android/support/v4/graphics/PathParser.java b/compat/src/main/java/android/support/v4/graphics/PathParser.java
similarity index 100%
rename from compat/java/android/support/v4/graphics/PathParser.java
rename to compat/src/main/java/android/support/v4/graphics/PathParser.java
diff --git a/compat/java/android/support/v4/graphics/TypefaceCompat.java b/compat/src/main/java/android/support/v4/graphics/TypefaceCompat.java
similarity index 79%
rename from compat/java/android/support/v4/graphics/TypefaceCompat.java
rename to compat/src/main/java/android/support/v4/graphics/TypefaceCompat.java
index b142a5f..3c55df6 100644
--- a/compat/java/android/support/v4/graphics/TypefaceCompat.java
+++ b/compat/src/main/java/android/support/v4/graphics/TypefaceCompat.java
@@ -23,16 +23,18 @@
 import android.graphics.Typeface;
 import android.os.Build;
 import android.os.CancellationSignal;
+import android.os.Handler;
 import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
 import android.support.annotation.RestrictTo;
+import android.support.v4.content.res.FontResourcesParserCompat;
 import android.support.v4.content.res.FontResourcesParserCompat.FamilyResourceEntry;
 import android.support.v4.content.res.FontResourcesParserCompat.FontFamilyFilesResourceEntry;
 import android.support.v4.content.res.FontResourcesParserCompat.ProviderResourceEntry;
+import android.support.v4.content.res.ResourcesCompat;
 import android.support.v4.provider.FontsContractCompat;
 import android.support.v4.provider.FontsContractCompat.FontInfo;
 import android.support.v4.util.LruCache;
-import android.widget.TextView;
 
 /**
  * Helper for accessing features in {@link Typeface}.
@@ -108,16 +110,31 @@
     public static Typeface createFromResourcesFamilyXml(
             @NonNull Context context, @NonNull FamilyResourceEntry entry,
             @NonNull Resources resources, int id, int style,
-            @Nullable TextView targetView) {
+            @Nullable ResourcesCompat.FontCallback fontCallback, @Nullable Handler handler,
+            boolean isRequestFromLayoutInflator) {
         Typeface typeface;
         if (entry instanceof ProviderResourceEntry) {
             ProviderResourceEntry providerEntry = (ProviderResourceEntry) entry;
-            typeface = FontsContractCompat.getFontSync(context,
-                    providerEntry.getRequest(), targetView, providerEntry.getFetchStrategy(),
-                    providerEntry.getTimeout(), style);
+            final boolean isBlocking = isRequestFromLayoutInflator
+                    ? providerEntry.getFetchStrategy()
+                    == FontResourcesParserCompat.FETCH_STRATEGY_BLOCKING
+                    : fontCallback == null;
+            final int timeout = isRequestFromLayoutInflator ? providerEntry.getTimeout()
+                    : FontResourcesParserCompat.INFINITE_TIMEOUT_VALUE;
+            typeface = FontsContractCompat.getFontSync(context, providerEntry.getRequest(),
+                    fontCallback, handler, isBlocking, timeout, style);
         } else {
             typeface = sTypefaceCompatImpl.createFromFontFamilyFilesResourceEntry(
                     context, (FontFamilyFilesResourceEntry) entry, resources, style);
+            if (fontCallback != null) {
+                if (typeface != null) {
+                    fontCallback.callbackSuccessAsync(typeface, handler);
+                } else {
+                    fontCallback.callbackFailAsync(
+                            FontsContractCompat.FontRequestCallback.FAIL_REASON_FONT_LOAD_ERROR,
+                            handler);
+                }
+            }
         }
         if (typeface != null) {
             sTypefaceCache.put(createResourceUid(resources, id, style), typeface);
@@ -135,7 +152,8 @@
         Typeface typeface = sTypefaceCompatImpl.createFromResourcesFontFile(
                 context, resources, id, path, style);
         if (typeface != null) {
-            sTypefaceCache.put(createResourceUid(resources, id, style), typeface);
+            final String resourceUid = createResourceUid(resources, id, style);
+            sTypefaceCache.put(resourceUid, typeface);
         }
         return typeface;
     }
diff --git a/compat/java/android/support/v4/graphics/TypefaceCompatApi21Impl.java b/compat/src/main/java/android/support/v4/graphics/TypefaceCompatApi21Impl.java
similarity index 100%
rename from compat/java/android/support/v4/graphics/TypefaceCompatApi21Impl.java
rename to compat/src/main/java/android/support/v4/graphics/TypefaceCompatApi21Impl.java
diff --git a/compat/java/android/support/v4/graphics/TypefaceCompatApi24Impl.java b/compat/src/main/java/android/support/v4/graphics/TypefaceCompatApi24Impl.java
similarity index 97%
rename from compat/java/android/support/v4/graphics/TypefaceCompatApi24Impl.java
rename to compat/src/main/java/android/support/v4/graphics/TypefaceCompatApi24Impl.java
index a107859..89a6ec4 100644
--- a/compat/java/android/support/v4/graphics/TypefaceCompatApi24Impl.java
+++ b/compat/src/main/java/android/support/v4/graphics/TypefaceCompatApi24Impl.java
@@ -145,7 +145,8 @@
                 return null;
             }
         }
-        return createFromFamiliesWithDefault(family);
+        final Typeface typeface = createFromFamiliesWithDefault(family);
+        return Typeface.create(typeface, style);
     }
 
     @Override
diff --git a/compat/java/android/support/v4/graphics/TypefaceCompatApi26Impl.java b/compat/src/main/java/android/support/v4/graphics/TypefaceCompatApi26Impl.java
similarity index 98%
rename from compat/java/android/support/v4/graphics/TypefaceCompatApi26Impl.java
rename to compat/src/main/java/android/support/v4/graphics/TypefaceCompatApi26Impl.java
index c7066c8..972aa5d 100644
--- a/compat/java/android/support/v4/graphics/TypefaceCompatApi26Impl.java
+++ b/compat/src/main/java/android/support/v4/graphics/TypefaceCompatApi26Impl.java
@@ -273,7 +273,8 @@
         if (!freeze(fontFamily)) {
             return null;
         }
-        return createFromFamiliesWithDefault(fontFamily);
+        final Typeface typeface = createFromFamiliesWithDefault(fontFamily);
+        return Typeface.create(typeface, style);
     }
 
     /**
diff --git a/compat/java/android/support/v4/graphics/TypefaceCompatBaseImpl.java b/compat/src/main/java/android/support/v4/graphics/TypefaceCompatBaseImpl.java
similarity index 100%
rename from compat/java/android/support/v4/graphics/TypefaceCompatBaseImpl.java
rename to compat/src/main/java/android/support/v4/graphics/TypefaceCompatBaseImpl.java
diff --git a/compat/java/android/support/v4/graphics/TypefaceCompatUtil.java b/compat/src/main/java/android/support/v4/graphics/TypefaceCompatUtil.java
similarity index 100%
rename from compat/java/android/support/v4/graphics/TypefaceCompatUtil.java
rename to compat/src/main/java/android/support/v4/graphics/TypefaceCompatUtil.java
diff --git a/compat/java/android/support/v4/graphics/drawable/DrawableCompat.java b/compat/src/main/java/android/support/v4/graphics/drawable/DrawableCompat.java
similarity index 100%
rename from compat/java/android/support/v4/graphics/drawable/DrawableCompat.java
rename to compat/src/main/java/android/support/v4/graphics/drawable/DrawableCompat.java
diff --git a/compat/java/android/support/v4/graphics/drawable/DrawableWrapper.java b/compat/src/main/java/android/support/v4/graphics/drawable/DrawableWrapper.java
similarity index 100%
rename from compat/java/android/support/v4/graphics/drawable/DrawableWrapper.java
rename to compat/src/main/java/android/support/v4/graphics/drawable/DrawableWrapper.java
diff --git a/compat/java/android/support/v4/graphics/drawable/DrawableWrapperApi14.java b/compat/src/main/java/android/support/v4/graphics/drawable/DrawableWrapperApi14.java
similarity index 100%
rename from compat/java/android/support/v4/graphics/drawable/DrawableWrapperApi14.java
rename to compat/src/main/java/android/support/v4/graphics/drawable/DrawableWrapperApi14.java
diff --git a/compat/java/android/support/v4/graphics/drawable/DrawableWrapperApi19.java b/compat/src/main/java/android/support/v4/graphics/drawable/DrawableWrapperApi19.java
similarity index 100%
rename from compat/java/android/support/v4/graphics/drawable/DrawableWrapperApi19.java
rename to compat/src/main/java/android/support/v4/graphics/drawable/DrawableWrapperApi19.java
diff --git a/compat/java/android/support/v4/graphics/drawable/DrawableWrapperApi21.java b/compat/src/main/java/android/support/v4/graphics/drawable/DrawableWrapperApi21.java
similarity index 100%
rename from compat/java/android/support/v4/graphics/drawable/DrawableWrapperApi21.java
rename to compat/src/main/java/android/support/v4/graphics/drawable/DrawableWrapperApi21.java
diff --git a/compat/java/android/support/v4/graphics/drawable/IconCompat.java b/compat/src/main/java/android/support/v4/graphics/drawable/IconCompat.java
similarity index 100%
rename from compat/java/android/support/v4/graphics/drawable/IconCompat.java
rename to compat/src/main/java/android/support/v4/graphics/drawable/IconCompat.java
diff --git a/compat/java/android/support/v4/graphics/drawable/TintAwareDrawable.java b/compat/src/main/java/android/support/v4/graphics/drawable/TintAwareDrawable.java
similarity index 100%
rename from compat/java/android/support/v4/graphics/drawable/TintAwareDrawable.java
rename to compat/src/main/java/android/support/v4/graphics/drawable/TintAwareDrawable.java
diff --git a/compat/java/android/support/v4/hardware/display/DisplayManagerCompat.java b/compat/src/main/java/android/support/v4/hardware/display/DisplayManagerCompat.java
similarity index 100%
rename from compat/java/android/support/v4/hardware/display/DisplayManagerCompat.java
rename to compat/src/main/java/android/support/v4/hardware/display/DisplayManagerCompat.java
diff --git a/compat/java/android/support/v4/hardware/fingerprint/FingerprintManagerCompat.java b/compat/src/main/java/android/support/v4/hardware/fingerprint/FingerprintManagerCompat.java
similarity index 100%
rename from compat/java/android/support/v4/hardware/fingerprint/FingerprintManagerCompat.java
rename to compat/src/main/java/android/support/v4/hardware/fingerprint/FingerprintManagerCompat.java
diff --git a/compat/java/android/support/v4/internal/package-info.java b/compat/src/main/java/android/support/v4/internal/package-info.java
similarity index 100%
rename from compat/java/android/support/v4/internal/package-info.java
rename to compat/src/main/java/android/support/v4/internal/package-info.java
diff --git a/compat/java/android/support/v4/internal/view/SupportMenu.java b/compat/src/main/java/android/support/v4/internal/view/SupportMenu.java
similarity index 100%
rename from compat/java/android/support/v4/internal/view/SupportMenu.java
rename to compat/src/main/java/android/support/v4/internal/view/SupportMenu.java
diff --git a/compat/java/android/support/v4/internal/view/SupportMenuItem.java b/compat/src/main/java/android/support/v4/internal/view/SupportMenuItem.java
similarity index 100%
rename from compat/java/android/support/v4/internal/view/SupportMenuItem.java
rename to compat/src/main/java/android/support/v4/internal/view/SupportMenuItem.java
diff --git a/compat/java/android/support/v4/internal/view/SupportSubMenu.java b/compat/src/main/java/android/support/v4/internal/view/SupportSubMenu.java
similarity index 100%
rename from compat/java/android/support/v4/internal/view/SupportSubMenu.java
rename to compat/src/main/java/android/support/v4/internal/view/SupportSubMenu.java
diff --git a/compat/java/android/support/v4/net/ConnectivityManagerCompat.java b/compat/src/main/java/android/support/v4/net/ConnectivityManagerCompat.java
similarity index 100%
rename from compat/java/android/support/v4/net/ConnectivityManagerCompat.java
rename to compat/src/main/java/android/support/v4/net/ConnectivityManagerCompat.java
diff --git a/compat/java/android/support/v4/net/DatagramSocketWrapper.java b/compat/src/main/java/android/support/v4/net/DatagramSocketWrapper.java
similarity index 100%
rename from compat/java/android/support/v4/net/DatagramSocketWrapper.java
rename to compat/src/main/java/android/support/v4/net/DatagramSocketWrapper.java
diff --git a/compat/java/android/support/v4/net/TrafficStatsCompat.java b/compat/src/main/java/android/support/v4/net/TrafficStatsCompat.java
similarity index 100%
rename from compat/java/android/support/v4/net/TrafficStatsCompat.java
rename to compat/src/main/java/android/support/v4/net/TrafficStatsCompat.java
diff --git a/compat/java/android/support/v4/os/BuildCompat.java b/compat/src/main/java/android/support/v4/os/BuildCompat.java
similarity index 100%
rename from compat/java/android/support/v4/os/BuildCompat.java
rename to compat/src/main/java/android/support/v4/os/BuildCompat.java
diff --git a/compat/java/android/support/v4/os/CancellationSignal.java b/compat/src/main/java/android/support/v4/os/CancellationSignal.java
similarity index 100%
rename from compat/java/android/support/v4/os/CancellationSignal.java
rename to compat/src/main/java/android/support/v4/os/CancellationSignal.java
diff --git a/compat/java/android/support/v4/os/ConfigurationCompat.java b/compat/src/main/java/android/support/v4/os/ConfigurationCompat.java
similarity index 100%
rename from compat/java/android/support/v4/os/ConfigurationCompat.java
rename to compat/src/main/java/android/support/v4/os/ConfigurationCompat.java
diff --git a/compat/java/android/support/v4/os/EnvironmentCompat.java b/compat/src/main/java/android/support/v4/os/EnvironmentCompat.java
similarity index 100%
rename from compat/java/android/support/v4/os/EnvironmentCompat.java
rename to compat/src/main/java/android/support/v4/os/EnvironmentCompat.java
diff --git a/compat/java/android/support/v4/os/IResultReceiver.aidl b/compat/src/main/java/android/support/v4/os/IResultReceiver.aidl
similarity index 100%
rename from compat/java/android/support/v4/os/IResultReceiver.aidl
rename to compat/src/main/java/android/support/v4/os/IResultReceiver.aidl
diff --git a/compat/java/android/support/v4/os/LocaleHelper.java b/compat/src/main/java/android/support/v4/os/LocaleHelper.java
similarity index 100%
rename from compat/java/android/support/v4/os/LocaleHelper.java
rename to compat/src/main/java/android/support/v4/os/LocaleHelper.java
diff --git a/compat/java/android/support/v4/os/LocaleListCompat.java b/compat/src/main/java/android/support/v4/os/LocaleListCompat.java
similarity index 100%
rename from compat/java/android/support/v4/os/LocaleListCompat.java
rename to compat/src/main/java/android/support/v4/os/LocaleListCompat.java
diff --git a/compat/java/android/support/v4/os/LocaleListHelper.java b/compat/src/main/java/android/support/v4/os/LocaleListHelper.java
similarity index 100%
rename from compat/java/android/support/v4/os/LocaleListHelper.java
rename to compat/src/main/java/android/support/v4/os/LocaleListHelper.java
diff --git a/compat/java/android/support/v4/os/LocaleListInterface.java b/compat/src/main/java/android/support/v4/os/LocaleListInterface.java
similarity index 100%
rename from compat/java/android/support/v4/os/LocaleListInterface.java
rename to compat/src/main/java/android/support/v4/os/LocaleListInterface.java
diff --git a/compat/java/android/support/v4/os/OperationCanceledException.java b/compat/src/main/java/android/support/v4/os/OperationCanceledException.java
similarity index 100%
rename from compat/java/android/support/v4/os/OperationCanceledException.java
rename to compat/src/main/java/android/support/v4/os/OperationCanceledException.java
diff --git a/compat/java/android/support/v4/os/ParcelableCompat.java b/compat/src/main/java/android/support/v4/os/ParcelableCompat.java
similarity index 100%
rename from compat/java/android/support/v4/os/ParcelableCompat.java
rename to compat/src/main/java/android/support/v4/os/ParcelableCompat.java
diff --git a/compat/java/android/support/v4/os/ParcelableCompatCreatorCallbacks.java b/compat/src/main/java/android/support/v4/os/ParcelableCompatCreatorCallbacks.java
similarity index 100%
rename from compat/java/android/support/v4/os/ParcelableCompatCreatorCallbacks.java
rename to compat/src/main/java/android/support/v4/os/ParcelableCompatCreatorCallbacks.java
diff --git a/compat/java/android/support/v4/os/ResultReceiver.aidl b/compat/src/main/java/android/support/v4/os/ResultReceiver.aidl
similarity index 100%
rename from compat/java/android/support/v4/os/ResultReceiver.aidl
rename to compat/src/main/java/android/support/v4/os/ResultReceiver.aidl
diff --git a/compat/java/android/support/v4/os/ResultReceiver.java b/compat/src/main/java/android/support/v4/os/ResultReceiver.java
similarity index 100%
rename from compat/java/android/support/v4/os/ResultReceiver.java
rename to compat/src/main/java/android/support/v4/os/ResultReceiver.java
diff --git a/compat/java/android/support/v4/os/TraceCompat.java b/compat/src/main/java/android/support/v4/os/TraceCompat.java
similarity index 100%
rename from compat/java/android/support/v4/os/TraceCompat.java
rename to compat/src/main/java/android/support/v4/os/TraceCompat.java
diff --git a/compat/java/android/support/v4/os/UserManagerCompat.java b/compat/src/main/java/android/support/v4/os/UserManagerCompat.java
similarity index 100%
rename from compat/java/android/support/v4/os/UserManagerCompat.java
rename to compat/src/main/java/android/support/v4/os/UserManagerCompat.java
diff --git a/compat/java/android/support/v4/os/package.html b/compat/src/main/java/android/support/v4/os/package.html
similarity index 100%
rename from compat/java/android/support/v4/os/package.html
rename to compat/src/main/java/android/support/v4/os/package.html
diff --git a/compat/java/android/support/v4/provider/FontRequest.java b/compat/src/main/java/android/support/v4/provider/FontRequest.java
similarity index 100%
rename from compat/java/android/support/v4/provider/FontRequest.java
rename to compat/src/main/java/android/support/v4/provider/FontRequest.java
diff --git a/compat/java/android/support/v4/provider/FontsContractCompat.java b/compat/src/main/java/android/support/v4/provider/FontsContractCompat.java
similarity index 88%
rename from compat/java/android/support/v4/provider/FontsContractCompat.java
rename to compat/src/main/java/android/support/v4/provider/FontsContractCompat.java
index 3511f3a..9ef1b0b 100644
--- a/compat/java/android/support/v4/provider/FontsContractCompat.java
+++ b/compat/src/main/java/android/support/v4/provider/FontsContractCompat.java
@@ -17,7 +17,6 @@
 package android.support.v4.provider;
 
 import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
-import static android.support.v4.content.res.FontResourcesParserCompat.FetchStrategy;
 
 import android.annotation.SuppressLint;
 import android.content.ContentResolver;
@@ -46,17 +45,16 @@
 import android.support.annotation.RestrictTo;
 import android.support.annotation.VisibleForTesting;
 import android.support.v4.content.res.FontResourcesParserCompat;
+import android.support.v4.content.res.ResourcesCompat;
 import android.support.v4.graphics.TypefaceCompat;
 import android.support.v4.graphics.TypefaceCompatUtil;
 import android.support.v4.provider.SelfDestructiveThread.ReplyCallback;
 import android.support.v4.util.LruCache;
 import android.support.v4.util.Preconditions;
 import android.support.v4.util.SimpleArrayMap;
-import android.widget.TextView;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
-import java.lang.ref.WeakReference;
 import java.nio.ByteBuffer;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -166,11 +164,11 @@
     // space open for new provider codes, these should all be negative numbers.
     /** @hide */
     @RestrictTo(LIBRARY_GROUP)
-    public static final int RESULT_CODE_PROVIDER_NOT_FOUND = -1;
+    /* package */ static final int RESULT_CODE_PROVIDER_NOT_FOUND = -1;
     /** @hide */
     @RestrictTo(LIBRARY_GROUP)
-    public static final int RESULT_CODE_WRONG_CERTIFICATES = -2;
-    // Note -3 is used by Typeface to indicate the font failed to load.
+    /* package */ static final int RESULT_CODE_WRONG_CERTIFICATES = -2;
+    // Note -3 is used by FontRequestCallback to indicate the font failed to load.
 
     private static final LruCache<String, Typeface> sTypefaceCache = new LruCache<>(16);
 
@@ -179,51 +177,87 @@
             new SelfDestructiveThread("fonts", Process.THREAD_PRIORITY_BACKGROUND,
                     BACKGROUND_THREAD_KEEP_ALIVE_DURATION_MS);
 
-    private static Typeface getFontInternal(final Context context, final FontRequest request,
+    @NonNull
+    private static TypefaceResult getFontInternal(final Context context, final FontRequest request,
             int style) {
         FontFamilyResult result;
         try {
             result = fetchFonts(context, null /* CancellationSignal */, request);
         } catch (PackageManager.NameNotFoundException e) {
-            return null;
+            return new TypefaceResult(null, FontRequestCallback.FAIL_REASON_PROVIDER_NOT_FOUND);
         }
         if (result.getStatusCode() == FontFamilyResult.STATUS_OK) {
-            return TypefaceCompat.createFromFontInfo(context, null /* CancellationSignal */,
-                    result.getFonts(), style);
+            final Typeface typeface = TypefaceCompat.createFromFontInfo(
+                    context, null /* CancellationSignal */, result.getFonts(), style);
+            return new TypefaceResult(typeface, typeface != null
+                    ? FontRequestCallback.RESULT_OK
+                    : FontRequestCallback.FAIL_REASON_FONT_LOAD_ERROR);
         }
-        return null;
+        int resultCode = result.getStatusCode() == FontFamilyResult.STATUS_WRONG_CERTIFICATES
+                ? FontRequestCallback.FAIL_REASON_WRONG_CERTIFICATES
+                : FontRequestCallback.FAIL_REASON_FONT_LOAD_ERROR;
+        return new TypefaceResult(null, resultCode);
     }
 
     private static final Object sLock = new Object();
     @GuardedBy("sLock")
-    private static final SimpleArrayMap<String, ArrayList<ReplyCallback<Typeface>>>
+    private static final SimpleArrayMap<String, ArrayList<ReplyCallback<TypefaceResult>>>
             sPendingReplies = new SimpleArrayMap<>();
 
+    private static final class TypefaceResult {
+        final Typeface mTypeface;
+        @FontRequestCallback.FontRequestFailReason final int mResult;
+
+        TypefaceResult(@Nullable Typeface typeface,
+                @FontRequestCallback.FontRequestFailReason int result) {
+            mTypeface = typeface;
+            mResult = result;
+        }
+    }
+
+    /**
+     * Used for tests, should not be used otherwise.
+     * @hide
+     **/
+    @RestrictTo(LIBRARY_GROUP)
+    public static final void resetCache() {
+        sTypefaceCache.evictAll();
+    }
+
     /** @hide */
     @RestrictTo(LIBRARY_GROUP)
     public static Typeface getFontSync(final Context context, final FontRequest request,
-            final @Nullable TextView targetView, @FetchStrategy int strategy, int timeout,
+            final @Nullable ResourcesCompat.FontCallback fontCallback,
+            final @Nullable Handler handler, boolean isBlockingFetch, int timeout,
             final int style) {
         final String id = request.getIdentifier() + "-" + style;
         Typeface cached = sTypefaceCache.get(id);
         if (cached != null) {
+            if (fontCallback != null) {
+                fontCallback.onFontRetrieved(cached);
+            }
             return cached;
         }
 
-        final boolean isBlockingFetch =
-                strategy == FontResourcesParserCompat.FETCH_STRATEGY_BLOCKING;
-
         if (isBlockingFetch && timeout == FontResourcesParserCompat.INFINITE_TIMEOUT_VALUE) {
             // Wait forever. No need to post to the thread.
-            return getFontInternal(context, request, style);
+            TypefaceResult typefaceResult = getFontInternal(context, request, style);
+            if (fontCallback != null) {
+                if (typefaceResult.mResult == FontFamilyResult.STATUS_OK) {
+                    fontCallback.callbackSuccessAsync(typefaceResult.mTypeface, handler);
+                } else {
+                    fontCallback.callbackFailAsync(typefaceResult.mResult, handler);
+                }
+            }
+            return typefaceResult.mTypeface;
         }
 
-        final Callable<Typeface> fetcher = new Callable<Typeface>() {
+        final Callable<TypefaceResult> fetcher = new Callable<TypefaceResult>() {
             @Override
-            public Typeface call() throws Exception {
-                Typeface typeface = getFontInternal(context, request, style);
-                if (typeface != null) {
-                    sTypefaceCache.put(id, typeface);
+            public TypefaceResult call() throws Exception {
+                TypefaceResult typeface = getFontInternal(context, request, style);
+                if (typeface.mTypeface != null) {
+                    sTypefaceCache.put(id, typeface.mTypeface);
                 }
                 return typeface;
             }
@@ -231,37 +265,42 @@
 
         if (isBlockingFetch) {
             try {
-                return sBackgroundThread.postAndWait(fetcher, timeout);
+                return sBackgroundThread.postAndWait(fetcher, timeout).mTypeface;
             } catch (InterruptedException e) {
                 return null;
             }
         } else {
-            final WeakReference<TextView> textViewWeak = new WeakReference<TextView>(targetView);
-            final ReplyCallback<Typeface> reply = new ReplyCallback<Typeface>() {
-                @Override
-                public void onReply(final Typeface typeface) {
-                    final TextView textView = textViewWeak.get();
-                    if (textView != null) {
-                        targetView.setTypeface(typeface, style);
-                    }
-                }
-            };
+            final ReplyCallback<TypefaceResult> reply = fontCallback == null ? null
+                    : new ReplyCallback<TypefaceResult>() {
+                        @Override
+                        public void onReply(final TypefaceResult typeface) {
+                            if (typeface.mResult == FontFamilyResult.STATUS_OK) {
+                                fontCallback.callbackSuccessAsync(typeface.mTypeface, handler);
+                            } else {
+                                fontCallback.callbackFailAsync(typeface.mResult, handler);
+                            }
+                        }
+                    };
 
             synchronized (sLock) {
                 if (sPendingReplies.containsKey(id)) {
                     // Already requested. Do not request the same provider again and insert the
                     // reply to the queue instead.
-                    sPendingReplies.get(id).add(reply);
+                    if (reply != null) {
+                        sPendingReplies.get(id).add(reply);
+                    }
                     return null;
                 }
-                ArrayList<ReplyCallback<Typeface>> pendingReplies = new ArrayList<>();
-                pendingReplies.add(reply);
-                sPendingReplies.put(id, pendingReplies);
+                if (reply != null) {
+                    ArrayList<ReplyCallback<TypefaceResult>> pendingReplies = new ArrayList<>();
+                    pendingReplies.add(reply);
+                    sPendingReplies.put(id, pendingReplies);
+                }
             }
-            sBackgroundThread.postAndReply(fetcher, new ReplyCallback<Typeface>() {
+            sBackgroundThread.postAndReply(fetcher, new ReplyCallback<TypefaceResult>() {
                 @Override
-                public void onReply(final Typeface typeface) {
-                    final ArrayList<ReplyCallback<Typeface>> replies;
+                public void onReply(final TypefaceResult typeface) {
+                    final ArrayList<ReplyCallback<TypefaceResult>> replies;
                     synchronized (sLock) {
                         replies = sPendingReplies.get(id);
                         sPendingReplies.remove(id);
@@ -269,7 +308,7 @@
                     for (int i = 0; i < replies.size(); ++i) {
                         replies.get(i).onReply(typeface);
                     }
-                };
+                }
             });
             return null;
         }
@@ -292,8 +331,9 @@
          * @param weight An integer that indicates the font weight.
          * @param italic A boolean that indicates the font is italic style or not.
          * @param resultCode A boolean that indicates the font contents is ready.
+         *
+         * @hide
          */
-        /** @hide */
         @RestrictTo(LIBRARY_GROUP)
         public FontInfo(@NonNull Uri uri, @IntRange(from = 0) int ttcIndex,
                 @IntRange(from = 1, to = 1000) int weight,
@@ -396,6 +436,9 @@
      * Interface used to receive asynchronously fetched typefaces.
      */
     public static class FontRequestCallback {
+        /** @hide */
+        @RestrictTo(LIBRARY_GROUP)
+        public static final int RESULT_OK = Columns.RESULT_CODE_OK;
         /**
          * Constant returned by {@link #onTypefaceRequestFailed(int)} signaling that the given
          * provider was not found on the device.
@@ -412,6 +455,11 @@
          */
         public static final int FAIL_REASON_FONT_LOAD_ERROR = -3;
         /**
+         * Constant that signals that the font was not loaded due to security issues. This usually
+         * means the font was attempted to load on a restricted context.
+         */
+        public static final int FAIL_REASON_SECURITY_VIOLATION = -4;
+        /**
          * Constant returned by {@link #onTypefaceRequestFailed(int)} signaling that the font
          * provider did not return any results for the given query.
          */
@@ -431,9 +479,10 @@
         @RestrictTo(LIBRARY_GROUP)
         @IntDef({ FAIL_REASON_PROVIDER_NOT_FOUND, FAIL_REASON_FONT_LOAD_ERROR,
                 FAIL_REASON_FONT_NOT_FOUND, FAIL_REASON_FONT_UNAVAILABLE,
-                FAIL_REASON_MALFORMED_QUERY, FAIL_REASON_WRONG_CERTIFICATES })
+                FAIL_REASON_MALFORMED_QUERY, FAIL_REASON_WRONG_CERTIFICATES,
+                FAIL_REASON_SECURITY_VIOLATION, RESULT_OK })
         @Retention(RetentionPolicy.SOURCE)
-        @interface FontRequestFailReason {}
+        public @interface FontRequestFailReason {}
 
         public FontRequestCallback() {}
 
diff --git a/compat/java/android/support/v4/provider/SelfDestructiveThread.java b/compat/src/main/java/android/support/v4/provider/SelfDestructiveThread.java
similarity index 99%
rename from compat/java/android/support/v4/provider/SelfDestructiveThread.java
rename to compat/src/main/java/android/support/v4/provider/SelfDestructiveThread.java
index 885799b..7cfe1f8 100644
--- a/compat/java/android/support/v4/provider/SelfDestructiveThread.java
+++ b/compat/src/main/java/android/support/v4/provider/SelfDestructiveThread.java
@@ -129,7 +129,7 @@
 
     /**
      * Execute the specific callable object on this thread and call the reply callback on the
-     * calling thread once it finishs.
+     * calling thread once it finishes.
      */
     public <T> void postAndReply(final Callable<T> callable, final ReplyCallback<T> reply) {
         final Handler callingHandler = new Handler();
diff --git a/compat/java/android/support/v4/text/BidiFormatter.java b/compat/src/main/java/android/support/v4/text/BidiFormatter.java
similarity index 100%
rename from compat/java/android/support/v4/text/BidiFormatter.java
rename to compat/src/main/java/android/support/v4/text/BidiFormatter.java
diff --git a/compat/java/android/support/v4/text/ICUCompat.java b/compat/src/main/java/android/support/v4/text/ICUCompat.java
similarity index 100%
rename from compat/java/android/support/v4/text/ICUCompat.java
rename to compat/src/main/java/android/support/v4/text/ICUCompat.java
diff --git a/compat/java/android/support/v4/text/TextDirectionHeuristicCompat.java b/compat/src/main/java/android/support/v4/text/TextDirectionHeuristicCompat.java
similarity index 100%
rename from compat/java/android/support/v4/text/TextDirectionHeuristicCompat.java
rename to compat/src/main/java/android/support/v4/text/TextDirectionHeuristicCompat.java
diff --git a/compat/java/android/support/v4/text/TextDirectionHeuristicsCompat.java b/compat/src/main/java/android/support/v4/text/TextDirectionHeuristicsCompat.java
similarity index 100%
rename from compat/java/android/support/v4/text/TextDirectionHeuristicsCompat.java
rename to compat/src/main/java/android/support/v4/text/TextDirectionHeuristicsCompat.java
diff --git a/compat/java/android/support/v4/text/TextUtilsCompat.java b/compat/src/main/java/android/support/v4/text/TextUtilsCompat.java
similarity index 100%
rename from compat/java/android/support/v4/text/TextUtilsCompat.java
rename to compat/src/main/java/android/support/v4/text/TextUtilsCompat.java
diff --git a/compat/java/android/support/v4/text/util/LinkifyCompat.java b/compat/src/main/java/android/support/v4/text/util/LinkifyCompat.java
similarity index 100%
rename from compat/java/android/support/v4/text/util/LinkifyCompat.java
rename to compat/src/main/java/android/support/v4/text/util/LinkifyCompat.java
diff --git a/compat/java/android/support/v4/util/ArrayMap.java b/compat/src/main/java/android/support/v4/util/ArrayMap.java
similarity index 100%
rename from compat/java/android/support/v4/util/ArrayMap.java
rename to compat/src/main/java/android/support/v4/util/ArrayMap.java
diff --git a/compat/java/android/support/v4/util/ArraySet.java b/compat/src/main/java/android/support/v4/util/ArraySet.java
similarity index 100%
rename from compat/java/android/support/v4/util/ArraySet.java
rename to compat/src/main/java/android/support/v4/util/ArraySet.java
diff --git a/compat/java/android/support/v4/util/AtomicFile.java b/compat/src/main/java/android/support/v4/util/AtomicFile.java
similarity index 100%
rename from compat/java/android/support/v4/util/AtomicFile.java
rename to compat/src/main/java/android/support/v4/util/AtomicFile.java
diff --git a/compat/java/android/support/v4/util/CircularArray.java b/compat/src/main/java/android/support/v4/util/CircularArray.java
similarity index 100%
rename from compat/java/android/support/v4/util/CircularArray.java
rename to compat/src/main/java/android/support/v4/util/CircularArray.java
diff --git a/compat/java/android/support/v4/util/CircularIntArray.java b/compat/src/main/java/android/support/v4/util/CircularIntArray.java
similarity index 100%
rename from compat/java/android/support/v4/util/CircularIntArray.java
rename to compat/src/main/java/android/support/v4/util/CircularIntArray.java
diff --git a/compat/java/android/support/v4/util/ContainerHelpers.java b/compat/src/main/java/android/support/v4/util/ContainerHelpers.java
similarity index 100%
rename from compat/java/android/support/v4/util/ContainerHelpers.java
rename to compat/src/main/java/android/support/v4/util/ContainerHelpers.java
diff --git a/compat/java/android/support/v4/util/DebugUtils.java b/compat/src/main/java/android/support/v4/util/DebugUtils.java
similarity index 100%
rename from compat/java/android/support/v4/util/DebugUtils.java
rename to compat/src/main/java/android/support/v4/util/DebugUtils.java
diff --git a/compat/java/android/support/v4/util/LogWriter.java b/compat/src/main/java/android/support/v4/util/LogWriter.java
similarity index 100%
rename from compat/java/android/support/v4/util/LogWriter.java
rename to compat/src/main/java/android/support/v4/util/LogWriter.java
diff --git a/compat/java/android/support/v4/util/LongSparseArray.java b/compat/src/main/java/android/support/v4/util/LongSparseArray.java
similarity index 100%
rename from compat/java/android/support/v4/util/LongSparseArray.java
rename to compat/src/main/java/android/support/v4/util/LongSparseArray.java
diff --git a/compat/java/android/support/v4/util/LruCache.java b/compat/src/main/java/android/support/v4/util/LruCache.java
similarity index 100%
rename from compat/java/android/support/v4/util/LruCache.java
rename to compat/src/main/java/android/support/v4/util/LruCache.java
diff --git a/compat/java/android/support/v4/util/MapCollections.java b/compat/src/main/java/android/support/v4/util/MapCollections.java
similarity index 100%
rename from compat/java/android/support/v4/util/MapCollections.java
rename to compat/src/main/java/android/support/v4/util/MapCollections.java
diff --git a/compat/java/android/support/v4/util/ObjectsCompat.java b/compat/src/main/java/android/support/v4/util/ObjectsCompat.java
similarity index 100%
rename from compat/java/android/support/v4/util/ObjectsCompat.java
rename to compat/src/main/java/android/support/v4/util/ObjectsCompat.java
diff --git a/compat/java/android/support/v4/util/Pair.java b/compat/src/main/java/android/support/v4/util/Pair.java
similarity index 100%
rename from compat/java/android/support/v4/util/Pair.java
rename to compat/src/main/java/android/support/v4/util/Pair.java
diff --git a/compat/java/android/support/v4/util/PatternsCompat.java b/compat/src/main/java/android/support/v4/util/PatternsCompat.java
similarity index 100%
rename from compat/java/android/support/v4/util/PatternsCompat.java
rename to compat/src/main/java/android/support/v4/util/PatternsCompat.java
diff --git a/compat/java/android/support/v4/util/Pools.java b/compat/src/main/java/android/support/v4/util/Pools.java
similarity index 100%
rename from compat/java/android/support/v4/util/Pools.java
rename to compat/src/main/java/android/support/v4/util/Pools.java
diff --git a/compat/java/android/support/v4/util/Preconditions.java b/compat/src/main/java/android/support/v4/util/Preconditions.java
similarity index 100%
rename from compat/java/android/support/v4/util/Preconditions.java
rename to compat/src/main/java/android/support/v4/util/Preconditions.java
diff --git a/compat/java/android/support/v4/util/SimpleArrayMap.java b/compat/src/main/java/android/support/v4/util/SimpleArrayMap.java
similarity index 100%
rename from compat/java/android/support/v4/util/SimpleArrayMap.java
rename to compat/src/main/java/android/support/v4/util/SimpleArrayMap.java
diff --git a/compat/java/android/support/v4/util/SparseArrayCompat.java b/compat/src/main/java/android/support/v4/util/SparseArrayCompat.java
similarity index 100%
rename from compat/java/android/support/v4/util/SparseArrayCompat.java
rename to compat/src/main/java/android/support/v4/util/SparseArrayCompat.java
diff --git a/compat/java/android/support/v4/util/TimeUtils.java b/compat/src/main/java/android/support/v4/util/TimeUtils.java
similarity index 100%
rename from compat/java/android/support/v4/util/TimeUtils.java
rename to compat/src/main/java/android/support/v4/util/TimeUtils.java
diff --git a/compat/java/android/support/v4/util/package.html b/compat/src/main/java/android/support/v4/util/package.html
similarity index 100%
rename from compat/java/android/support/v4/util/package.html
rename to compat/src/main/java/android/support/v4/util/package.html
diff --git a/compat/java/android/support/v4/view/AccessibilityDelegateCompat.java b/compat/src/main/java/android/support/v4/view/AccessibilityDelegateCompat.java
similarity index 100%
rename from compat/java/android/support/v4/view/AccessibilityDelegateCompat.java
rename to compat/src/main/java/android/support/v4/view/AccessibilityDelegateCompat.java
diff --git a/compat/java/android/support/v4/view/ActionProvider.java b/compat/src/main/java/android/support/v4/view/ActionProvider.java
similarity index 100%
rename from compat/java/android/support/v4/view/ActionProvider.java
rename to compat/src/main/java/android/support/v4/view/ActionProvider.java
diff --git a/compat/java/android/support/v4/view/GestureDetectorCompat.java b/compat/src/main/java/android/support/v4/view/GestureDetectorCompat.java
similarity index 100%
rename from compat/java/android/support/v4/view/GestureDetectorCompat.java
rename to compat/src/main/java/android/support/v4/view/GestureDetectorCompat.java
diff --git a/compat/java/android/support/v4/view/GravityCompat.java b/compat/src/main/java/android/support/v4/view/GravityCompat.java
similarity index 100%
rename from compat/java/android/support/v4/view/GravityCompat.java
rename to compat/src/main/java/android/support/v4/view/GravityCompat.java
diff --git a/compat/java/android/support/v4/view/InputDeviceCompat.java b/compat/src/main/java/android/support/v4/view/InputDeviceCompat.java
similarity index 100%
rename from compat/java/android/support/v4/view/InputDeviceCompat.java
rename to compat/src/main/java/android/support/v4/view/InputDeviceCompat.java
diff --git a/compat/java/android/support/v4/view/LayoutInflaterCompat.java b/compat/src/main/java/android/support/v4/view/LayoutInflaterCompat.java
similarity index 100%
rename from compat/java/android/support/v4/view/LayoutInflaterCompat.java
rename to compat/src/main/java/android/support/v4/view/LayoutInflaterCompat.java
diff --git a/compat/java/android/support/v4/view/LayoutInflaterFactory.java b/compat/src/main/java/android/support/v4/view/LayoutInflaterFactory.java
similarity index 100%
rename from compat/java/android/support/v4/view/LayoutInflaterFactory.java
rename to compat/src/main/java/android/support/v4/view/LayoutInflaterFactory.java
diff --git a/compat/java/android/support/v4/view/MarginLayoutParamsCompat.java b/compat/src/main/java/android/support/v4/view/MarginLayoutParamsCompat.java
similarity index 100%
rename from compat/java/android/support/v4/view/MarginLayoutParamsCompat.java
rename to compat/src/main/java/android/support/v4/view/MarginLayoutParamsCompat.java
diff --git a/compat/java/android/support/v4/view/MenuCompat.java b/compat/src/main/java/android/support/v4/view/MenuCompat.java
similarity index 100%
rename from compat/java/android/support/v4/view/MenuCompat.java
rename to compat/src/main/java/android/support/v4/view/MenuCompat.java
diff --git a/compat/java/android/support/v4/view/MenuItemCompat.java b/compat/src/main/java/android/support/v4/view/MenuItemCompat.java
similarity index 100%
rename from compat/java/android/support/v4/view/MenuItemCompat.java
rename to compat/src/main/java/android/support/v4/view/MenuItemCompat.java
diff --git a/compat/java/android/support/v4/view/MotionEventCompat.java b/compat/src/main/java/android/support/v4/view/MotionEventCompat.java
similarity index 100%
rename from compat/java/android/support/v4/view/MotionEventCompat.java
rename to compat/src/main/java/android/support/v4/view/MotionEventCompat.java
diff --git a/compat/java/android/support/v4/view/NestedScrollingChild.java b/compat/src/main/java/android/support/v4/view/NestedScrollingChild.java
similarity index 100%
rename from compat/java/android/support/v4/view/NestedScrollingChild.java
rename to compat/src/main/java/android/support/v4/view/NestedScrollingChild.java
diff --git a/compat/java/android/support/v4/view/NestedScrollingChild2.java b/compat/src/main/java/android/support/v4/view/NestedScrollingChild2.java
similarity index 100%
rename from compat/java/android/support/v4/view/NestedScrollingChild2.java
rename to compat/src/main/java/android/support/v4/view/NestedScrollingChild2.java
diff --git a/compat/java/android/support/v4/view/NestedScrollingParent.java b/compat/src/main/java/android/support/v4/view/NestedScrollingParent.java
similarity index 100%
rename from compat/java/android/support/v4/view/NestedScrollingParent.java
rename to compat/src/main/java/android/support/v4/view/NestedScrollingParent.java
diff --git a/compat/java/android/support/v4/view/NestedScrollingParent2.java b/compat/src/main/java/android/support/v4/view/NestedScrollingParent2.java
similarity index 100%
rename from compat/java/android/support/v4/view/NestedScrollingParent2.java
rename to compat/src/main/java/android/support/v4/view/NestedScrollingParent2.java
diff --git a/compat/java/android/support/v4/view/OnApplyWindowInsetsListener.java b/compat/src/main/java/android/support/v4/view/OnApplyWindowInsetsListener.java
similarity index 100%
rename from compat/java/android/support/v4/view/OnApplyWindowInsetsListener.java
rename to compat/src/main/java/android/support/v4/view/OnApplyWindowInsetsListener.java
diff --git a/compat/java/android/support/v4/view/PointerIconCompat.java b/compat/src/main/java/android/support/v4/view/PointerIconCompat.java
similarity index 100%
rename from compat/java/android/support/v4/view/PointerIconCompat.java
rename to compat/src/main/java/android/support/v4/view/PointerIconCompat.java
diff --git a/compat/java/android/support/v4/view/ScaleGestureDetectorCompat.java b/compat/src/main/java/android/support/v4/view/ScaleGestureDetectorCompat.java
similarity index 100%
rename from compat/java/android/support/v4/view/ScaleGestureDetectorCompat.java
rename to compat/src/main/java/android/support/v4/view/ScaleGestureDetectorCompat.java
diff --git a/compat/java/android/support/v4/view/ScrollingView.java b/compat/src/main/java/android/support/v4/view/ScrollingView.java
similarity index 100%
rename from compat/java/android/support/v4/view/ScrollingView.java
rename to compat/src/main/java/android/support/v4/view/ScrollingView.java
diff --git a/compat/java/android/support/v4/view/TintableBackgroundView.java b/compat/src/main/java/android/support/v4/view/TintableBackgroundView.java
similarity index 100%
rename from compat/java/android/support/v4/view/TintableBackgroundView.java
rename to compat/src/main/java/android/support/v4/view/TintableBackgroundView.java
diff --git a/compat/java/android/support/v4/view/VelocityTrackerCompat.java b/compat/src/main/java/android/support/v4/view/VelocityTrackerCompat.java
similarity index 100%
rename from compat/java/android/support/v4/view/VelocityTrackerCompat.java
rename to compat/src/main/java/android/support/v4/view/VelocityTrackerCompat.java
diff --git a/compat/java/android/support/v4/view/ViewCompat.java b/compat/src/main/java/android/support/v4/view/ViewCompat.java
similarity index 100%
rename from compat/java/android/support/v4/view/ViewCompat.java
rename to compat/src/main/java/android/support/v4/view/ViewCompat.java
diff --git a/compat/java/android/support/v4/view/ViewConfigurationCompat.java b/compat/src/main/java/android/support/v4/view/ViewConfigurationCompat.java
similarity index 100%
rename from compat/java/android/support/v4/view/ViewConfigurationCompat.java
rename to compat/src/main/java/android/support/v4/view/ViewConfigurationCompat.java
diff --git a/compat/java/android/support/v4/view/ViewGroupCompat.java b/compat/src/main/java/android/support/v4/view/ViewGroupCompat.java
similarity index 100%
rename from compat/java/android/support/v4/view/ViewGroupCompat.java
rename to compat/src/main/java/android/support/v4/view/ViewGroupCompat.java
diff --git a/compat/java/android/support/v4/view/ViewParentCompat.java b/compat/src/main/java/android/support/v4/view/ViewParentCompat.java
similarity index 100%
rename from compat/java/android/support/v4/view/ViewParentCompat.java
rename to compat/src/main/java/android/support/v4/view/ViewParentCompat.java
diff --git a/compat/java/android/support/v4/view/ViewPropertyAnimatorCompat.java b/compat/src/main/java/android/support/v4/view/ViewPropertyAnimatorCompat.java
similarity index 100%
rename from compat/java/android/support/v4/view/ViewPropertyAnimatorCompat.java
rename to compat/src/main/java/android/support/v4/view/ViewPropertyAnimatorCompat.java
diff --git a/compat/java/android/support/v4/view/ViewPropertyAnimatorListener.java b/compat/src/main/java/android/support/v4/view/ViewPropertyAnimatorListener.java
similarity index 100%
rename from compat/java/android/support/v4/view/ViewPropertyAnimatorListener.java
rename to compat/src/main/java/android/support/v4/view/ViewPropertyAnimatorListener.java
diff --git a/compat/java/android/support/v4/view/ViewPropertyAnimatorListenerAdapter.java b/compat/src/main/java/android/support/v4/view/ViewPropertyAnimatorListenerAdapter.java
similarity index 100%
rename from compat/java/android/support/v4/view/ViewPropertyAnimatorListenerAdapter.java
rename to compat/src/main/java/android/support/v4/view/ViewPropertyAnimatorListenerAdapter.java
diff --git a/compat/java/android/support/v4/view/ViewPropertyAnimatorUpdateListener.java b/compat/src/main/java/android/support/v4/view/ViewPropertyAnimatorUpdateListener.java
similarity index 100%
rename from compat/java/android/support/v4/view/ViewPropertyAnimatorUpdateListener.java
rename to compat/src/main/java/android/support/v4/view/ViewPropertyAnimatorUpdateListener.java
diff --git a/compat/java/android/support/v4/view/WindowCompat.java b/compat/src/main/java/android/support/v4/view/WindowCompat.java
similarity index 100%
rename from compat/java/android/support/v4/view/WindowCompat.java
rename to compat/src/main/java/android/support/v4/view/WindowCompat.java
diff --git a/compat/java/android/support/v4/view/WindowInsetsCompat.java b/compat/src/main/java/android/support/v4/view/WindowInsetsCompat.java
similarity index 100%
rename from compat/java/android/support/v4/view/WindowInsetsCompat.java
rename to compat/src/main/java/android/support/v4/view/WindowInsetsCompat.java
diff --git a/compat/java/android/support/v4/view/accessibility/AccessibilityEventCompat.java b/compat/src/main/java/android/support/v4/view/accessibility/AccessibilityEventCompat.java
similarity index 100%
rename from compat/java/android/support/v4/view/accessibility/AccessibilityEventCompat.java
rename to compat/src/main/java/android/support/v4/view/accessibility/AccessibilityEventCompat.java
diff --git a/compat/java/android/support/v4/view/accessibility/AccessibilityManagerCompat.java b/compat/src/main/java/android/support/v4/view/accessibility/AccessibilityManagerCompat.java
similarity index 100%
rename from compat/java/android/support/v4/view/accessibility/AccessibilityManagerCompat.java
rename to compat/src/main/java/android/support/v4/view/accessibility/AccessibilityManagerCompat.java
diff --git a/compat/java/android/support/v4/view/accessibility/AccessibilityNodeInfoCompat.java b/compat/src/main/java/android/support/v4/view/accessibility/AccessibilityNodeInfoCompat.java
similarity index 100%
rename from compat/java/android/support/v4/view/accessibility/AccessibilityNodeInfoCompat.java
rename to compat/src/main/java/android/support/v4/view/accessibility/AccessibilityNodeInfoCompat.java
diff --git a/compat/java/android/support/v4/view/accessibility/AccessibilityNodeProviderCompat.java b/compat/src/main/java/android/support/v4/view/accessibility/AccessibilityNodeProviderCompat.java
similarity index 100%
rename from compat/java/android/support/v4/view/accessibility/AccessibilityNodeProviderCompat.java
rename to compat/src/main/java/android/support/v4/view/accessibility/AccessibilityNodeProviderCompat.java
diff --git a/compat/java/android/support/v4/view/accessibility/AccessibilityRecordCompat.java b/compat/src/main/java/android/support/v4/view/accessibility/AccessibilityRecordCompat.java
similarity index 100%
rename from compat/java/android/support/v4/view/accessibility/AccessibilityRecordCompat.java
rename to compat/src/main/java/android/support/v4/view/accessibility/AccessibilityRecordCompat.java
diff --git a/compat/java/android/support/v4/view/accessibility/AccessibilityWindowInfoCompat.java b/compat/src/main/java/android/support/v4/view/accessibility/AccessibilityWindowInfoCompat.java
similarity index 100%
rename from compat/java/android/support/v4/view/accessibility/AccessibilityWindowInfoCompat.java
rename to compat/src/main/java/android/support/v4/view/accessibility/AccessibilityWindowInfoCompat.java
diff --git a/compat/java/android/support/v4/view/accessibility/package.html b/compat/src/main/java/android/support/v4/view/accessibility/package.html
similarity index 100%
rename from compat/java/android/support/v4/view/accessibility/package.html
rename to compat/src/main/java/android/support/v4/view/accessibility/package.html
diff --git a/compat/java/android/support/v4/view/animation/PathInterpolatorApi14.java b/compat/src/main/java/android/support/v4/view/animation/PathInterpolatorApi14.java
similarity index 100%
rename from compat/java/android/support/v4/view/animation/PathInterpolatorApi14.java
rename to compat/src/main/java/android/support/v4/view/animation/PathInterpolatorApi14.java
diff --git a/compat/java/android/support/v4/view/animation/PathInterpolatorCompat.java b/compat/src/main/java/android/support/v4/view/animation/PathInterpolatorCompat.java
similarity index 100%
rename from compat/java/android/support/v4/view/animation/PathInterpolatorCompat.java
rename to compat/src/main/java/android/support/v4/view/animation/PathInterpolatorCompat.java
diff --git a/compat/java/android/support/v4/view/package.html b/compat/src/main/java/android/support/v4/view/package.html
similarity index 100%
rename from compat/java/android/support/v4/view/package.html
rename to compat/src/main/java/android/support/v4/view/package.html
diff --git a/compat/java/android/support/v4/widget/AutoSizeableTextView.java b/compat/src/main/java/android/support/v4/widget/AutoSizeableTextView.java
similarity index 100%
rename from compat/java/android/support/v4/widget/AutoSizeableTextView.java
rename to compat/src/main/java/android/support/v4/widget/AutoSizeableTextView.java
diff --git a/compat/java/android/support/v4/widget/CompoundButtonCompat.java b/compat/src/main/java/android/support/v4/widget/CompoundButtonCompat.java
similarity index 100%
rename from compat/java/android/support/v4/widget/CompoundButtonCompat.java
rename to compat/src/main/java/android/support/v4/widget/CompoundButtonCompat.java
diff --git a/compat/java/android/support/v4/widget/EdgeEffectCompat.java b/compat/src/main/java/android/support/v4/widget/EdgeEffectCompat.java
similarity index 100%
rename from compat/java/android/support/v4/widget/EdgeEffectCompat.java
rename to compat/src/main/java/android/support/v4/widget/EdgeEffectCompat.java
diff --git a/compat/java/android/support/v4/widget/ImageViewCompat.java b/compat/src/main/java/android/support/v4/widget/ImageViewCompat.java
similarity index 100%
rename from compat/java/android/support/v4/widget/ImageViewCompat.java
rename to compat/src/main/java/android/support/v4/widget/ImageViewCompat.java
diff --git a/compat/java/android/support/v4/widget/ListPopupWindowCompat.java b/compat/src/main/java/android/support/v4/widget/ListPopupWindowCompat.java
similarity index 100%
rename from compat/java/android/support/v4/widget/ListPopupWindowCompat.java
rename to compat/src/main/java/android/support/v4/widget/ListPopupWindowCompat.java
diff --git a/compat/java/android/support/v4/widget/ListViewCompat.java b/compat/src/main/java/android/support/v4/widget/ListViewCompat.java
similarity index 100%
rename from compat/java/android/support/v4/widget/ListViewCompat.java
rename to compat/src/main/java/android/support/v4/widget/ListViewCompat.java
diff --git a/compat/java/android/support/v4/widget/PopupMenuCompat.java b/compat/src/main/java/android/support/v4/widget/PopupMenuCompat.java
similarity index 100%
rename from compat/java/android/support/v4/widget/PopupMenuCompat.java
rename to compat/src/main/java/android/support/v4/widget/PopupMenuCompat.java
diff --git a/compat/java/android/support/v4/widget/PopupWindowCompat.java b/compat/src/main/java/android/support/v4/widget/PopupWindowCompat.java
similarity index 100%
rename from compat/java/android/support/v4/widget/PopupWindowCompat.java
rename to compat/src/main/java/android/support/v4/widget/PopupWindowCompat.java
diff --git a/compat/java/android/support/v4/widget/ScrollerCompat.java b/compat/src/main/java/android/support/v4/widget/ScrollerCompat.java
similarity index 100%
rename from compat/java/android/support/v4/widget/ScrollerCompat.java
rename to compat/src/main/java/android/support/v4/widget/ScrollerCompat.java
diff --git a/compat/java/android/support/v4/widget/TextViewCompat.java b/compat/src/main/java/android/support/v4/widget/TextViewCompat.java
similarity index 100%
rename from compat/java/android/support/v4/widget/TextViewCompat.java
rename to compat/src/main/java/android/support/v4/widget/TextViewCompat.java
diff --git a/compat/java/android/support/v4/widget/TintableCompoundButton.java b/compat/src/main/java/android/support/v4/widget/TintableCompoundButton.java
similarity index 100%
rename from compat/java/android/support/v4/widget/TintableCompoundButton.java
rename to compat/src/main/java/android/support/v4/widget/TintableCompoundButton.java
diff --git a/compat/java/android/support/v4/widget/TintableImageSourceView.java b/compat/src/main/java/android/support/v4/widget/TintableImageSourceView.java
similarity index 100%
rename from compat/java/android/support/v4/widget/TintableImageSourceView.java
rename to compat/src/main/java/android/support/v4/widget/TintableImageSourceView.java
diff --git a/compat/java/android/support/v4/widget/package.html b/compat/src/main/java/android/support/v4/widget/package.html
similarity index 100%
rename from compat/java/android/support/v4/widget/package.html
rename to compat/src/main/java/android/support/v4/widget/package.html
diff --git a/compat/tests/java/android/support/v4/content/res/FontResourcesParserCompatTest.java b/compat/tests/java/android/support/v4/content/res/FontResourcesParserCompatTest.java
index e7f40cf..fb41792 100644
--- a/compat/tests/java/android/support/v4/content/res/FontResourcesParserCompatTest.java
+++ b/compat/tests/java/android/support/v4/content/res/FontResourcesParserCompatTest.java
@@ -98,10 +98,10 @@
         assertNotNull(result);
         ProviderResourceEntry providerEntry = (ProviderResourceEntry) result;
         FontRequest request = providerEntry.getRequest();
-        assertEquals("com.example.test.fontprovider.authority",
+        assertEquals("android.support.provider.fonts.font",
                 request.getProviderAuthority());
-        assertEquals("com.example.test.fontprovider.package", request.getProviderPackage());
-        assertEquals("MyRequestedFont", request.getQuery());
+        assertEquals("android.support.compat.test", request.getProviderPackage());
+        assertEquals("singleFontFamily", request.getQuery());
     }
 
     @Test
diff --git a/compat/tests/java/android/support/v4/content/res/ResourcesCompatTest.java b/compat/tests/java/android/support/v4/content/res/ResourcesCompatTest.java
index 56f5ab4..b326dd6 100644
--- a/compat/tests/java/android/support/v4/content/res/ResourcesCompatTest.java
+++ b/compat/tests/java/android/support/v4/content/res/ResourcesCompatTest.java
@@ -20,6 +20,7 @@
 import static org.junit.Assert.assertNotSame;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
 
 import android.content.Context;
 import android.content.res.ColorStateList;
@@ -27,15 +28,21 @@
 import android.graphics.Typeface;
 import android.graphics.drawable.Drawable;
 import android.os.Build;
+import android.support.annotation.NonNull;
 import android.support.compat.test.R;
 import android.support.test.InstrumentationRegistry;
 import android.support.test.filters.SmallTest;
+import android.support.v4.provider.FontsContractCompat;
+import android.support.v4.provider.MockFontProvider;
 import android.support.v4.testutils.TestUtils;
 import android.util.DisplayMetrics;
 
 import org.junit.Before;
 import org.junit.Test;
 
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
 @SmallTest
 public class ResourcesCompatTest {
     private Context mContext;
@@ -45,6 +52,7 @@
     public void setup() {
         mContext = InstrumentationRegistry.getContext();
         mResources = mContext.getResources();
+        MockFontProvider.prepareFontFiles(mContext);
     }
 
     @Test
@@ -293,15 +301,49 @@
     }
 
     @Test
-    public void testGetFont_fontFile() {
+    public void testGetFont_fontFile_sync() {
         Typeface font = ResourcesCompat.getFont(mContext, R.font.samplefont);
 
         assertNotNull(font);
         assertNotSame(Typeface.DEFAULT, font);
     }
 
+    private static final class FontCallback extends ResourcesCompat.FontCallback {
+        private final CountDownLatch mLatch;
+        Typeface mTypeface;
+
+        FontCallback(CountDownLatch latch) {
+            mLatch = latch;
+        }
+
+        @Override
+        public void onFontRetrieved(@NonNull Typeface typeface) {
+            mTypeface = typeface;
+            mLatch.countDown();
+        }
+
+        @Override
+        public void onFontRetrievalFailed(int reason) {
+            mLatch.countDown();
+        }
+    }
+
     @Test
-    public void testGetFont_xmlFile() {
+    public void testGetFont_fontFile_async() throws InterruptedException {
+        final CountDownLatch latch = new CountDownLatch(1);
+        final FontCallback callback = new FontCallback(latch);
+        FontsContractCompat.resetCache();
+
+        ResourcesCompat.getFont(mContext, R.font.samplefont, callback, null);
+
+        assertTrue(latch.await(5L, TimeUnit.SECONDS));
+
+        assertNotNull(callback.mTypeface);
+        assertNotSame(Typeface.DEFAULT, callback.mTypeface);
+    }
+
+    @Test
+    public void testGetFont_xmlFile_sync() {
         Typeface font = ResourcesCompat.getFont(mContext, R.font.samplexmlfont);
 
         assertNotNull(font);
@@ -309,6 +351,47 @@
     }
 
     @Test
+    public void testGetFont_xmlFile_async() throws InterruptedException {
+        final CountDownLatch latch = new CountDownLatch(1);
+        final FontCallback callback = new FontCallback(latch);
+
+        ResourcesCompat.getFont(mContext, R.font.samplexmlfont, callback, null);
+
+        assertTrue(latch.await(5L, TimeUnit.SECONDS));
+
+        assertNotNull(callback.mTypeface);
+        assertNotSame(Typeface.DEFAULT, callback.mTypeface);
+    }
+
+    @Test
+    public void testGetFont_xmlProviderFile_sync() {
+        Typeface font = ResourcesCompat.getFont(mContext, R.font.samplexmldownloadedfont);
+
+        assertNotNull(font);
+        assertNotSame(Typeface.DEFAULT, font);
+    }
+
+    @Test
+    public void testGetFont_xmlProviderFile_async() throws InterruptedException {
+        final CountDownLatch latch = new CountDownLatch(1);
+        final FontCallback callback = new FontCallback(latch);
+
+        // Font provider non-blocking requests post on the calling thread so can't run on
+        // the test thread as it doesn't have a Looper.
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                ResourcesCompat.getFont(mContext, R.font.samplexmldownloadedfont, callback, null);
+            }
+        });
+
+        assertTrue(latch.await(5L, TimeUnit.SECONDS));
+
+        assertNotNull(callback.mTypeface);
+        assertNotSame(Typeface.DEFAULT, callback.mTypeface);
+    }
+
+    @Test
     public void testGetFont_invalidXmlFile() {
         try {
             assertNull(
diff --git a/compat/tests/java/android/support/v4/graphics/TypefaceCompatTest.java b/compat/tests/java/android/support/v4/graphics/TypefaceCompatTest.java
index dab7f0f..dff4c33 100644
--- a/compat/tests/java/android/support/v4/graphics/TypefaceCompatTest.java
+++ b/compat/tests/java/android/support/v4/graphics/TypefaceCompatTest.java
@@ -17,7 +17,10 @@
 package android.support.v4.graphics;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
 
 import android.annotation.SuppressLint;
 import android.app.Instrumentation;
@@ -28,16 +31,17 @@
 import android.content.res.Resources;
 import android.graphics.Paint;
 import android.graphics.Typeface;
+import android.support.annotation.NonNull;
 import android.support.compat.test.R;
 import android.support.test.InstrumentationRegistry;
 import android.support.test.filters.SmallTest;
-import android.support.testutils.PollingCheck;
 import android.support.v4.content.res.FontResourcesParserCompat;
 import android.support.v4.content.res.FontResourcesParserCompat.FamilyResourceEntry;
 import android.support.v4.content.res.FontResourcesParserCompat.ProviderResourceEntry;
+import android.support.v4.content.res.ResourcesCompat;
 import android.support.v4.provider.FontRequest;
+import android.support.v4.provider.FontsContractCompat;
 import android.support.v4.provider.MockFontProvider;
-import android.widget.TextView;
 
 import org.junit.After;
 import org.junit.Before;
@@ -47,6 +51,8 @@
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
 
 @SmallTest
 public class TypefaceCompatTest {
@@ -134,91 +140,169 @@
         return new ProviderResourceEntry(request, entry.getFetchStrategy(), entry.getTimeout());
     }
 
-    @Test
-    public void testCreateFromResourcesFamilyXml_resourceFont_syncloading() throws Exception {
-        Typeface typeface = TypefaceCompat.createFromResourcesFamilyXml(mContext,
-                getProviderResourceEntry(R.font.styletest_sync_providerfont), mResources,
-                R.font.styletest_sync_providerfont, Typeface.NORMAL, null /* TextView */);
-        typeface = Typeface.create(typeface, Typeface.NORMAL);
-        assertEquals(R.font.large_a, getSelectedFontResourceId(typeface));
+    public static class FontCallback extends ResourcesCompat.FontCallback {
+        private final CountDownLatch mLatch;
+        Typeface mTypeface;
 
-        typeface = TypefaceCompat.createFromResourcesFamilyXml(mContext,
-                getProviderResourceEntry(R.font.styletest_sync_providerfont), mResources,
-                R.font.styletest_sync_providerfont, Typeface.ITALIC, null /* TextView */);
-        typeface = Typeface.create(typeface, Typeface.ITALIC);
-        assertEquals(R.font.large_b, getSelectedFontResourceId(typeface));
+        FontCallback(CountDownLatch latch) {
+            mLatch = latch;
+        }
 
-        typeface = TypefaceCompat.createFromResourcesFamilyXml(mContext,
-                getProviderResourceEntry(R.font.styletest_sync_providerfont), mResources,
-                R.font.styletest_sync_providerfont, Typeface.BOLD, null /* TextView */);
-        typeface = Typeface.create(typeface, Typeface.BOLD);
-        assertEquals(R.font.large_c, getSelectedFontResourceId(typeface));
+        @Override
+        public void onFontRetrieved(@NonNull Typeface typeface) {
+            mTypeface = typeface;
+            mLatch.countDown();
+        }
 
-        typeface = TypefaceCompat.createFromResourcesFamilyXml(mContext,
-                getProviderResourceEntry(R.font.styletest_sync_providerfont), mResources,
-                R.font.styletest_sync_providerfont, Typeface.BOLD_ITALIC, null /* TextView */);
-        typeface = Typeface.create(typeface, Typeface.BOLD_ITALIC);
-        assertEquals(R.font.large_d, getSelectedFontResourceId(typeface));
+        @Override
+        public void onFontRetrievalFailed(int reason) {
+            mLatch.countDown();
+        }
     }
 
     @Test
     public void testCreateFromResourcesFamilyXml_resourceFont_asyncloading() throws Exception {
+        final Instrumentation inst = InstrumentationRegistry.getInstrumentation();
+        CountDownLatch latch = new CountDownLatch(1);
+        final FontCallback callback = new FontCallback(latch);
+
+        inst.runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                TypefaceCompat.createFromResourcesFamilyXml(mContext,
+                        getProviderResourceEntry(R.font.styletest_async_providerfont), mResources,
+                        R.font.styletest_async_providerfont, Typeface.NORMAL, callback,
+                        null /* handler */, false /* isXmlRequest */);
+            }
+        });
+        assertTrue(latch.await(5L, TimeUnit.SECONDS));
+
+        assertEquals(R.font.large_a, getSelectedFontResourceId(callback.mTypeface));
+
+        latch = new CountDownLatch(1);
+        final FontCallback callback2 = new FontCallback(latch);
+        inst.runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                TypefaceCompat.createFromResourcesFamilyXml(mContext,
+                        getProviderResourceEntry(R.font.styletest_async_providerfont), mResources,
+                        R.font.styletest_async_providerfont, Typeface.ITALIC, callback2,
+                        null /* handler */, false /* isXmlRequest */);
+            }
+        });
+        assertTrue(latch.await(5L, TimeUnit.SECONDS));
+        assertEquals(R.font.large_b, getSelectedFontResourceId(callback2.mTypeface));
+
+        latch = new CountDownLatch(1);
+        final FontCallback callback3 = new FontCallback(latch);
+        inst.runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                TypefaceCompat.createFromResourcesFamilyXml(mContext,
+                        getProviderResourceEntry(R.font.styletest_async_providerfont), mResources,
+                        R.font.styletest_async_providerfont, Typeface.BOLD, callback3,
+                        null /* handler */, false /* isXmlRequest */);
+            }
+        });
+        assertTrue(latch.await(5L, TimeUnit.SECONDS));
+        assertEquals(R.font.large_c, getSelectedFontResourceId(callback3.mTypeface));
+
+        latch = new CountDownLatch(1);
+        final FontCallback callback4 = new FontCallback(latch);
+        inst.runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                TypefaceCompat.createFromResourcesFamilyXml(mContext,
+                        getProviderResourceEntry(R.font.styletest_async_providerfont), mResources,
+                        R.font.styletest_async_providerfont, Typeface.BOLD_ITALIC, callback4,
+                        null /* handler */, false /* isXmlRequest */);
+            }
+        });
+        assertTrue(latch.await(5L, TimeUnit.SECONDS));
+        assertEquals(R.font.large_d, getSelectedFontResourceId(callback4.mTypeface));
+    }
+
+    @Test
+    public void testProviderFont_xmlRequest() {
+        Typeface typeface = TypefaceCompat.createFromResourcesFamilyXml(mContext,
+                getProviderResourceEntry(R.font.samplexmldownloadedfontblocking), mResources,
+                R.font.samplexmldownloadedfontblocking, Typeface.NORMAL, null,
+                null /* handler */, true /* isXmlRequest */);
+
+        assertNotNull(typeface);
+        assertNotEquals(Typeface.DEFAULT, typeface);
+    }
+
+    @Test
+    public void testProviderFont_nonXmlRequest_noCallback() {
+        // If we don't give a callback, the request should be blocking.
+        Typeface typeface = TypefaceCompat.createFromResourcesFamilyXml(mContext,
+                getProviderResourceEntry(R.font.samplexmldownloadedfontblocking), mResources,
+                R.font.samplexmldownloadedfontblocking, Typeface.NORMAL, null,
+                null /* handler */, false /* isXmlRequest */);
+
+        assertNotNull(typeface);
+        assertNotEquals(Typeface.DEFAULT, typeface);
+    }
+
+    @Test
+    public void testProviderFont_nonXmlRequest_withCallback() throws InterruptedException {
         Instrumentation inst = InstrumentationRegistry.getInstrumentation();
-        final TextView textView = new TextView(mContext);
-        PollingCheck.PollingCheckCondition condition = new PollingCheck.PollingCheckCondition() {
-            @Override
-            public boolean canProceed() {
-                return textView.getTypeface() != null;
-            }
-        };
+        CountDownLatch latch = new CountDownLatch(1);
+        final FontCallback callback = new FontCallback(latch);
+        FontsContractCompat.resetCache();
 
-        textView.setTypeface(null);
+        final Typeface[] result = new Typeface[1];
         inst.runOnMainSync(new Runnable() {
             @Override
             public void run() {
-                TypefaceCompat.createFromResourcesFamilyXml(mContext,
-                        getProviderResourceEntry(R.font.styletest_async_providerfont), mResources,
-                        R.font.styletest_async_providerfont, Typeface.NORMAL, textView);
+                result[0] = TypefaceCompat.createFromResourcesFamilyXml(mContext,
+                        getProviderResourceEntry(R.font.samplexmldownloadedfontblocking),
+                        mResources, R.font.samplexmldownloadedfontblocking, Typeface.NORMAL,
+                        callback, null /* handler */, false /* isXmlRequest */);
             }
         });
-        PollingCheck.waitFor(condition);
-        assertEquals(R.font.large_a, getSelectedFontResourceId(textView.getTypeface()));
+        assertTrue(latch.await(5L, TimeUnit.SECONDS));
+        assertNotNull(callback.mTypeface);
+        assertNull(result[0]);
+    }
 
-        textView.setTypeface(null);
+    @Test
+    public void testProviderFont_nonXmlRequest_withCallback_cached() throws InterruptedException {
+        Instrumentation inst = InstrumentationRegistry.getInstrumentation();
+        CountDownLatch latch = new CountDownLatch(1);
+        final FontCallback callback = new FontCallback(latch);
+        FontsContractCompat.resetCache();
+
+        final Typeface[] result = new Typeface[2];
         inst.runOnMainSync(new Runnable() {
             @Override
             public void run() {
-                TypefaceCompat.createFromResourcesFamilyXml(mContext,
-                        getProviderResourceEntry(R.font.styletest_async_providerfont), mResources,
-                        R.font.styletest_async_providerfont, Typeface.ITALIC, textView);
+                result[0] = TypefaceCompat.createFromResourcesFamilyXml(mContext,
+                        getProviderResourceEntry(R.font.samplexmldownloadedfontblocking),
+                        mResources, R.font.samplexmldownloadedfontblocking, Typeface.NORMAL,
+                        callback, null /* handler */, false /* isXmlRequest */);
             }
         });
-        PollingCheck.waitFor(condition);
-        assertEquals(R.font.large_b, getSelectedFontResourceId(textView.getTypeface()));
+        assertTrue(latch.await(5L, TimeUnit.SECONDS));
+        assertNotNull(callback.mTypeface);
+        assertNull(result[0]);
 
-        textView.setTypeface(null);
+        latch = new CountDownLatch(1);
+        final FontCallback callback2 = new FontCallback(latch);
+
         inst.runOnMainSync(new Runnable() {
             @Override
             public void run() {
-                TypefaceCompat.createFromResourcesFamilyXml(mContext,
-                        getProviderResourceEntry(R.font.styletest_async_providerfont), mResources,
-                        R.font.styletest_async_providerfont, Typeface.BOLD, textView);
+                result[1] = TypefaceCompat.createFromResourcesFamilyXml(mContext,
+                        getProviderResourceEntry(R.font.samplexmldownloadedfontblocking),
+                        mResources, R.font.samplexmldownloadedfontblocking, Typeface.NORMAL,
+                        callback2, null /* handler */, false /* isXmlRequest */);
             }
         });
-        PollingCheck.waitFor(condition);
-        assertEquals(R.font.large_c, getSelectedFontResourceId(textView.getTypeface()));
-
-        textView.setTypeface(null);
-        inst.runOnMainSync(new Runnable() {
-            @Override
-            public void run() {
-                TypefaceCompat.createFromResourcesFamilyXml(mContext,
-                        getProviderResourceEntry(R.font.styletest_async_providerfont), mResources,
-                        R.font.styletest_async_providerfont, Typeface.BOLD_ITALIC, textView);
-            }
-        });
-        PollingCheck.waitFor(condition);
-        assertEquals(R.font.large_d, getSelectedFontResourceId(textView.getTypeface()));
+        assertTrue(latch.await(5L, TimeUnit.SECONDS));
+        assertNotNull(callback2.mTypeface);
+        assertNotNull(result[1]);
     }
 
     @Test
@@ -228,33 +312,45 @@
         final FamilyResourceEntry entry = FontResourcesParserCompat.parse(
                 mResources.getXml(R.font.styletestfont), mResources);
         Typeface typeface = TypefaceCompat.createFromResourcesFamilyXml(mContext, entry, mResources,
-                R.font.styletestfont, Typeface.NORMAL, null /* text view */);
-        assertEquals(typeface, TypefaceCompat.findFromCache(
-                mResources, R.font.styletestfont, Typeface.NORMAL));
+                R.font.styletestfont, Typeface.NORMAL, null /* callback */, null /* handler */,
+                false /* isXmlRequest */);
+        Typeface cachedTypeface = TypefaceCompat.findFromCache(
+                mResources, R.font.styletestfont, Typeface.NORMAL);
+        assertNotNull(cachedTypeface);
+        assertEquals(typeface, cachedTypeface);
         typeface = Typeface.create(typeface, Typeface.NORMAL);
         // styletestfont has a node of fontStyle="normal" fontWeight="400" font="@font/large_a".
         assertEquals(R.font.large_a, getSelectedFontResourceId(typeface));
 
         typeface = TypefaceCompat.createFromResourcesFamilyXml(mContext, entry, mResources,
-                R.font.styletestfont, Typeface.ITALIC, null);
-        assertEquals(typeface, TypefaceCompat.findFromCache(
-                mResources, R.font.styletestfont, Typeface.ITALIC));
+                R.font.styletestfont, Typeface.ITALIC, null /* callback */, null /* handler */,
+                false /* isXmlRequest */);
+        cachedTypeface = TypefaceCompat.findFromCache(
+                mResources, R.font.styletestfont, Typeface.ITALIC);
+        assertNotNull(cachedTypeface);
+        assertEquals(typeface, cachedTypeface);
         typeface = Typeface.create(typeface, Typeface.ITALIC);
         // styletestfont has a node of fontStyle="italic" fontWeight="400" font="@font/large_b".
         assertEquals(R.font.large_b, getSelectedFontResourceId(typeface));
 
         typeface = TypefaceCompat.createFromResourcesFamilyXml(mContext, entry, mResources,
-                R.font.styletestfont, Typeface.BOLD, null);
-        assertEquals(typeface, TypefaceCompat.findFromCache(
-                mResources, R.font.styletestfont, Typeface.BOLD));
+                R.font.styletestfont, Typeface.BOLD, null /* callback */, null /* handler */,
+                false /* isXmlRequest */);
+        cachedTypeface = TypefaceCompat.findFromCache(
+                mResources, R.font.styletestfont, Typeface.BOLD);
+        assertNotNull(cachedTypeface);
+        assertEquals(typeface, cachedTypeface);
         typeface = Typeface.create(typeface, Typeface.BOLD);
         // styletestfont has a node of fontStyle="normal" fontWeight="700" font="@font/large_c".
         assertEquals(R.font.large_c, getSelectedFontResourceId(typeface));
 
         typeface = TypefaceCompat.createFromResourcesFamilyXml(mContext, entry, mResources,
-                R.font.styletestfont, Typeface.BOLD_ITALIC, null);
-        assertEquals(typeface, TypefaceCompat.findFromCache(
-                mResources, R.font.styletestfont, Typeface.BOLD_ITALIC));
+                R.font.styletestfont, Typeface.BOLD_ITALIC, null /* callback */,
+                null /* handler */, false /* isXmlRequest */);
+        cachedTypeface = TypefaceCompat.findFromCache(
+                mResources, R.font.styletestfont, Typeface.BOLD_ITALIC);
+        assertNotNull(cachedTypeface);
+        assertEquals(typeface, cachedTypeface);
         typeface = Typeface.create(typeface, Typeface.BOLD_ITALIC);
         // styletestfont has a node of fontStyle="italic" fontWeight="700" font="@font/large_d".
         assertEquals(R.font.large_d, getSelectedFontResourceId(typeface));
@@ -265,15 +361,19 @@
         Typeface typeface = TypefaceCompat.createFromResourcesFontFile(mContext, mResources,
                 R.font.large_a, "res/font/large_a.ttf", Typeface.NORMAL);
         assertNotNull(typeface);
-        assertEquals(typeface, TypefaceCompat.findFromCache(
-                mResources, R.font.large_a, Typeface.NORMAL));
+        Typeface cachedTypeface = TypefaceCompat.findFromCache(
+                mResources, R.font.large_a, Typeface.NORMAL);
+        assertNotNull(cachedTypeface);
+        assertEquals(typeface, cachedTypeface);
         assertEquals(R.font.large_a, getSelectedFontResourceId(typeface));
 
         typeface = TypefaceCompat.createFromResourcesFontFile(mContext, mResources, R.font.large_b,
                 "res/font/large_b.ttf", Typeface.NORMAL);
         assertNotNull(typeface);
-        assertEquals(typeface, TypefaceCompat.findFromCache(
-                mResources, R.font.large_b, Typeface.NORMAL));
+        cachedTypeface = TypefaceCompat.findFromCache(
+                mResources, R.font.large_b, Typeface.NORMAL);
+        assertNotNull(cachedTypeface);
+        assertEquals(typeface, cachedTypeface);
         assertEquals(R.font.large_b, getSelectedFontResourceId(typeface));
     }
 }
diff --git a/compat/tests/res/font/samplexmldownloadedfont.xml b/compat/tests/res/font/samplexmldownloadedfont.xml
index 659d196..824ad33 100644
--- a/compat/tests/res/font/samplexmldownloadedfont.xml
+++ b/compat/tests/res/font/samplexmldownloadedfont.xml
@@ -1,6 +1,7 @@
 <?xml version="1.0" encoding="utf-8"?>
 <font-family xmlns:app="http://schemas.android.com/apk/res-auto"
-    app:fontProviderAuthority="com.example.test.fontprovider.authority"
-    app:fontProviderPackage="com.example.test.fontprovider.package"
-    app:fontProviderQuery="MyRequestedFont">
+    app:fontProviderAuthority="android.support.provider.fonts.font"
+    app:fontProviderPackage="android.support.compat.test"
+    app:fontProviderQuery="singleFontFamily"
+    app:fontProviderCerts="@array/mock_provider_certs">
 </font-family>
diff --git a/compat/tests/res/font/samplexmldownloadedfontblocking.xml b/compat/tests/res/font/samplexmldownloadedfontblocking.xml
new file mode 100644
index 0000000..3da2382
--- /dev/null
+++ b/compat/tests/res/font/samplexmldownloadedfontblocking.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<font-family xmlns:app="http://schemas.android.com/apk/res-auto"
+    app:fontProviderAuthority="android.support.provider.fonts.font"
+    app:fontProviderPackage="android.support.compat.test"
+    app:fontProviderQuery="singleFontFamily"
+    app:fontProviderFetchStrategy="blocking"
+    app:fontProviderCerts="@array/mock_provider_certs"
+    app:fontProviderFetchTimeout="-1">
+</font-family>
diff --git a/compat/tests/res/values/arrays.xml b/compat/tests/res/values/arrays.xml
index 1aa87fd..5c127ca 100644
--- a/compat/tests/res/values/arrays.xml
+++ b/compat/tests/res/values/arrays.xml
@@ -30,4 +30,9 @@
         <item>@array/certs1</item>
         <item>@array/certs2</item>
     </array>
+
+    <!-- These are the actual certs for the test running app. -->
+    <array name="mock_provider_certs">
+        <item>MIIB3TCCAUYCAQEwDQYJKoZIhvcNAQEFBQAwNzEWMBQGA1UEAwwNQW5kcm9pZCBEZWJ1ZzEQMA4GA1UECgwHQW5kcm9pZDELMAkGA1UEBhMCVVMwHhcNMTcwMzEwMjE0NzIxWhcNNDcwMzAzMjE0NzIxWjA3MRYwFAYDVQQDDA1BbmRyb2lkIERlYnVnMRAwDgYDVQQKDAdBbmRyb2lkMQswCQYDVQQGEwJVUzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAg9zgUpOAhXrfE17OYlLWkTGCvnSXWi94SpnyVBVZqq33OCbNKaIi5s314f4rhTFp4LDLFozIUihTOH1pJGLvRFqFu78vIpWBNOlj5mDJThBme6Z+eElnIttK/ivcfyaFM1dc55apQIlf9aDCLX6lEp7p1/O0rJKuXWalte+nYwcCAwEAATANBgkqhkiG9w0BAQUFAAOBgQBE6FFD5jx725gyV9Nevmlv7ndQ8/CKj1NC4C2g7sh/wLtegEU8k6VCUyLRl8EEEnXQUtRg7KVquDWwMTKtXZP8EghQ1AGIklH2u1z4w9DgdD0CrJZ9TGPN3jpbOj5RujkHoRr+g6mwMluq0vH1GnOUMEtshkybq15SbDOmXjEUJA==</item>
+    </array>
 </resources>
\ No newline at end of file
diff --git a/content/Android.mk b/content/Android.mk
index eff8215..32caf53 100644
--- a/content/Android.mk
+++ b/content/Android.mk
@@ -18,7 +18,7 @@
 LOCAL_USE_AAPT2 := true
 LOCAL_MODULE := android-support-content
 LOCAL_SDK_VERSION := $(SUPPORT_CURRENT_SDK_VERSION)
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
+LOCAL_SRC_FILES := $(call all-java-files-under, src/main/java)
 LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
 LOCAL_SHARED_ANDROID_LIBRARIES := \
     android-support-compat \
diff --git a/content/build.gradle b/content/build.gradle
index 1b2d182..af33423 100644
--- a/content/build.gradle
+++ b/content/build.gradle
@@ -29,11 +29,6 @@
     defaultConfig {
         minSdkVersion 14
     }
-
-    sourceSets {
-        main.java.srcDirs = ['src']
-        main.res.srcDir 'res'
-    }
 }
 
 supportLibrary {
diff --git a/content/src/android/support/content/ContentPager.java b/content/src/main/java/android/support/content/ContentPager.java
similarity index 100%
rename from content/src/android/support/content/ContentPager.java
rename to content/src/main/java/android/support/content/ContentPager.java
diff --git a/content/src/android/support/content/InMemoryCursor.java b/content/src/main/java/android/support/content/InMemoryCursor.java
similarity index 100%
rename from content/src/android/support/content/InMemoryCursor.java
rename to content/src/main/java/android/support/content/InMemoryCursor.java
diff --git a/content/src/android/support/content/LoaderQueryRunner.java b/content/src/main/java/android/support/content/LoaderQueryRunner.java
similarity index 100%
rename from content/src/android/support/content/LoaderQueryRunner.java
rename to content/src/main/java/android/support/content/LoaderQueryRunner.java
diff --git a/content/src/android/support/content/Query.java b/content/src/main/java/android/support/content/Query.java
similarity index 100%
rename from content/src/android/support/content/Query.java
rename to content/src/main/java/android/support/content/Query.java
diff --git a/core-ui/Android.mk b/core-ui/Android.mk
index bb7a4be..184d7be 100644
--- a/core-ui/Android.mk
+++ b/core-ui/Android.mk
@@ -26,7 +26,7 @@
 LOCAL_USE_AAPT2 := true
 LOCAL_MODULE := android-support-core-ui
 LOCAL_SDK_VERSION := $(SUPPORT_CURRENT_SDK_VERSION)
-LOCAL_SRC_FILES := $(call all-java-files-under,java)
+LOCAL_SRC_FILES := $(call all-java-files-under,src/main/java)
 LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
 LOCAL_SHARED_ANDROID_LIBRARIES := \
     android-support-compat \
diff --git a/core-ui/build.gradle b/core-ui/build.gradle
index 46abf57..38a4fe2 100644
--- a/core-ui/build.gradle
+++ b/core-ui/build.gradle
@@ -16,12 +16,6 @@
         minSdkVersion 14
     }
 
-    sourceSets {
-        main.java.srcDirs = [
-                'java'
-        ]
-    }
-
     buildTypes.all {
         consumerProguardFiles 'proguard-rules.pro'
     }
diff --git a/core-ui/java/android/support/v4/app/ActionBarDrawerToggle.java b/core-ui/src/main/java/android/support/v4/app/ActionBarDrawerToggle.java
similarity index 100%
rename from core-ui/java/android/support/v4/app/ActionBarDrawerToggle.java
rename to core-ui/src/main/java/android/support/v4/app/ActionBarDrawerToggle.java
diff --git a/core-ui/java/android/support/v4/app/package.html b/core-ui/src/main/java/android/support/v4/app/package.html
similarity index 100%
rename from core-ui/java/android/support/v4/app/package.html
rename to core-ui/src/main/java/android/support/v4/app/package.html
diff --git a/core-ui/java/android/support/v4/view/AbsSavedState.java b/core-ui/src/main/java/android/support/v4/view/AbsSavedState.java
similarity index 90%
rename from core-ui/java/android/support/v4/view/AbsSavedState.java
rename to core-ui/src/main/java/android/support/v4/view/AbsSavedState.java
index 4cf38ac..86f491f 100644
--- a/core-ui/java/android/support/v4/view/AbsSavedState.java
+++ b/core-ui/src/main/java/android/support/v4/view/AbsSavedState.java
@@ -18,6 +18,8 @@
 
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
 
 /**
  * A {@link Parcelable} implementation that should be used by inheritance
@@ -40,7 +42,7 @@
      *
      * @param superState The state of the superclass of this view
      */
-    protected AbsSavedState(Parcelable superState) {
+    protected AbsSavedState(@NonNull Parcelable superState) {
         if (superState == null) {
             throw new IllegalArgumentException("superState must not be null");
         }
@@ -52,7 +54,7 @@
      *
      * @param source parcel to read from
      */
-    protected AbsSavedState(Parcel source) {
+    protected AbsSavedState(@NonNull Parcel source) {
         this(source, null);
     }
 
@@ -62,11 +64,12 @@
      * @param source parcel to read from
      * @param loader ClassLoader to use for reading
      */
-    protected AbsSavedState(Parcel source, ClassLoader loader) {
+    protected AbsSavedState(@NonNull Parcel source, @Nullable ClassLoader loader) {
         Parcelable superState = source.readParcelable(loader);
         mSuperState = superState != null ? superState : EMPTY_STATE;
     }
 
+    @Nullable
     public final Parcelable getSuperState() {
         return mSuperState;
     }
diff --git a/core-ui/java/android/support/v4/view/AsyncLayoutInflater.java b/core-ui/src/main/java/android/support/v4/view/AsyncLayoutInflater.java
similarity index 98%
rename from core-ui/java/android/support/v4/view/AsyncLayoutInflater.java
rename to core-ui/src/main/java/android/support/v4/view/AsyncLayoutInflater.java
index e194a50..d26e5b8 100644
--- a/core-ui/java/android/support/v4/view/AsyncLayoutInflater.java
+++ b/core-ui/src/main/java/android/support/v4/view/AsyncLayoutInflater.java
@@ -107,7 +107,8 @@
     };
 
     public interface OnInflateFinishedListener {
-        void onInflateFinished(View view, int resid, ViewGroup parent);
+        void onInflateFinished(@NonNull View view, @LayoutRes int resid,
+                @Nullable ViewGroup parent);
     }
 
     private static class InflateRequest {
diff --git a/core-ui/java/android/support/v4/view/NestedScrollingChildHelper.java b/core-ui/src/main/java/android/support/v4/view/NestedScrollingChildHelper.java
similarity index 100%
rename from core-ui/java/android/support/v4/view/NestedScrollingChildHelper.java
rename to core-ui/src/main/java/android/support/v4/view/NestedScrollingChildHelper.java
diff --git a/core-ui/java/android/support/v4/view/NestedScrollingParentHelper.java b/core-ui/src/main/java/android/support/v4/view/NestedScrollingParentHelper.java
similarity index 100%
rename from core-ui/java/android/support/v4/view/NestedScrollingParentHelper.java
rename to core-ui/src/main/java/android/support/v4/view/NestedScrollingParentHelper.java
diff --git a/core-ui/java/android/support/v4/view/PagerAdapter.java b/core-ui/src/main/java/android/support/v4/view/PagerAdapter.java
similarity index 90%
rename from core-ui/java/android/support/v4/view/PagerAdapter.java
rename to core-ui/src/main/java/android/support/v4/view/PagerAdapter.java
index 1b1dc3d..a8fb099 100644
--- a/core-ui/java/android/support/v4/view/PagerAdapter.java
+++ b/core-ui/src/main/java/android/support/v4/view/PagerAdapter.java
@@ -19,6 +19,8 @@
 import android.database.DataSetObservable;
 import android.database.DataSetObserver;
 import android.os.Parcelable;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
 import android.view.View;
 import android.view.ViewGroup;
 
@@ -92,7 +94,7 @@
      * @param container The containing View which is displaying this adapter's
      * page views.
      */
-    public void startUpdate(ViewGroup container) {
+    public void startUpdate(@NonNull ViewGroup container) {
         startUpdate((View) container);
     }
 
@@ -107,7 +109,8 @@
      * @return Returns an Object representing the new page.  This does not
      * need to be a View, but can be some other container of the page.
      */
-    public Object instantiateItem(ViewGroup container, int position) {
+    @NonNull
+    public Object instantiateItem(@NonNull ViewGroup container, int position) {
         return instantiateItem((View) container, position);
     }
 
@@ -121,7 +124,7 @@
      * @param object The same object that was returned by
      * {@link #instantiateItem(View, int)}.
      */
-    public void destroyItem(ViewGroup container, int position, Object object) {
+    public void destroyItem(@NonNull ViewGroup container, int position, @NonNull Object object) {
         destroyItem((View) container, position, object);
     }
 
@@ -134,7 +137,7 @@
      * @param object The same object that was returned by
      * {@link #instantiateItem(View, int)}.
      */
-    public void setPrimaryItem(ViewGroup container, int position, Object object) {
+    public void setPrimaryItem(@NonNull ViewGroup container, int position, @NonNull Object object) {
         setPrimaryItem((View) container, position, object);
     }
 
@@ -145,7 +148,7 @@
      * @param container The containing View which is displaying this adapter's
      * page views.
      */
-    public void finishUpdate(ViewGroup container) {
+    public void finishUpdate(@NonNull ViewGroup container) {
         finishUpdate((View) container);
     }
 
@@ -157,7 +160,7 @@
      * @deprecated Use {@link #startUpdate(ViewGroup)}
      */
     @Deprecated
-    public void startUpdate(View container) {
+    public void startUpdate(@NonNull View container) {
     }
 
     /**
@@ -174,7 +177,8 @@
      * @deprecated Use {@link #instantiateItem(ViewGroup, int)}
      */
     @Deprecated
-    public Object instantiateItem(View container, int position) {
+    @NonNull
+    public Object instantiateItem(@NonNull View container, int position) {
         throw new UnsupportedOperationException(
                 "Required method instantiateItem was not overridden");
     }
@@ -192,7 +196,7 @@
      * @deprecated Use {@link #destroyItem(ViewGroup, int, Object)}
      */
     @Deprecated
-    public void destroyItem(View container, int position, Object object) {
+    public void destroyItem(@NonNull View container, int position, @NonNull Object object) {
         throw new UnsupportedOperationException("Required method destroyItem was not overridden");
     }
 
@@ -208,7 +212,7 @@
      * @deprecated Use {@link #setPrimaryItem(ViewGroup, int, Object)}
      */
     @Deprecated
-    public void setPrimaryItem(View container, int position, Object object) {
+    public void setPrimaryItem(@NonNull View container, int position, @NonNull Object object) {
     }
 
     /**
@@ -221,7 +225,7 @@
      * @deprecated Use {@link #finishUpdate(ViewGroup)}
      */
     @Deprecated
-    public void finishUpdate(View container) {
+    public void finishUpdate(@NonNull View container) {
     }
 
     /**
@@ -233,7 +237,7 @@
      * @param object Object to check for association with <code>view</code>
      * @return true if <code>view</code> is associated with the key object <code>object</code>
      */
-    public abstract boolean isViewFromObject(View view, Object object);
+    public abstract boolean isViewFromObject(@NonNull View view, @NonNull Object object);
 
     /**
      * Save any instance state associated with this adapter and its pages that should be
@@ -241,6 +245,7 @@
      *
      * @return Saved state for this adapter
      */
+    @Nullable
     public Parcelable saveState() {
         return null;
     }
@@ -252,7 +257,7 @@
      * @param state State previously saved by a call to {@link #saveState()}
      * @param loader A ClassLoader that should be used to instantiate any restored objects
      */
-    public void restoreState(Parcelable state, ClassLoader loader) {
+    public void restoreState(@Nullable Parcelable state, @Nullable ClassLoader loader) {
     }
 
     /**
@@ -270,7 +275,7 @@
      *         {@link #POSITION_UNCHANGED} if the object's position has not changed,
      *         or {@link #POSITION_NONE} if the item is no longer present.
      */
-    public int getItemPosition(Object object) {
+    public int getItemPosition(@NonNull Object object) {
         return POSITION_UNCHANGED;
     }
 
@@ -292,7 +297,7 @@
      *
      * @param observer The {@link android.database.DataSetObserver} which will receive callbacks.
      */
-    public void registerDataSetObserver(DataSetObserver observer) {
+    public void registerDataSetObserver(@NonNull DataSetObserver observer) {
         mObservable.registerObserver(observer);
     }
 
@@ -301,7 +306,7 @@
      *
      * @param observer The {@link android.database.DataSetObserver} which will be unregistered.
      */
-    public void unregisterDataSetObserver(DataSetObserver observer) {
+    public void unregisterDataSetObserver(@NonNull DataSetObserver observer) {
         mObservable.unregisterObserver(observer);
     }
 
@@ -320,6 +325,7 @@
      * @param position The position of the title requested
      * @return A title for the requested page
      */
+    @Nullable
     public CharSequence getPageTitle(int position) {
         return null;
     }
diff --git a/core-ui/java/android/support/v4/view/PagerTabStrip.java b/core-ui/src/main/java/android/support/v4/view/PagerTabStrip.java
similarity index 97%
rename from core-ui/java/android/support/v4/view/PagerTabStrip.java
rename to core-ui/src/main/java/android/support/v4/view/PagerTabStrip.java
index f4c0b21..6c88572 100644
--- a/core-ui/java/android/support/v4/view/PagerTabStrip.java
+++ b/core-ui/src/main/java/android/support/v4/view/PagerTabStrip.java
@@ -24,6 +24,8 @@
 import android.support.annotation.ColorInt;
 import android.support.annotation.ColorRes;
 import android.support.annotation.DrawableRes;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
 import android.support.v4.content.ContextCompat;
 import android.util.AttributeSet;
 import android.view.MotionEvent;
@@ -76,11 +78,11 @@
     private float mInitialMotionY;
     private int mTouchSlop;
 
-    public PagerTabStrip(Context context) {
+    public PagerTabStrip(@NonNull Context context) {
         this(context, null);
     }
 
-    public PagerTabStrip(Context context, AttributeSet attrs) {
+    public PagerTabStrip(@NonNull Context context, @Nullable AttributeSet attrs) {
         super(context, attrs);
 
         mIndicatorColor = mTextColor;
diff --git a/core-ui/java/android/support/v4/view/PagerTitleStrip.java b/core-ui/src/main/java/android/support/v4/view/PagerTitleStrip.java
similarity index 98%
rename from core-ui/java/android/support/v4/view/PagerTitleStrip.java
rename to core-ui/src/main/java/android/support/v4/view/PagerTitleStrip.java
index b63e4f4..79a6240 100644
--- a/core-ui/java/android/support/v4/view/PagerTitleStrip.java
+++ b/core-ui/src/main/java/android/support/v4/view/PagerTitleStrip.java
@@ -22,6 +22,8 @@
 import android.graphics.drawable.Drawable;
 import android.support.annotation.ColorInt;
 import android.support.annotation.FloatRange;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
 import android.support.v4.widget.TextViewCompat;
 import android.text.TextUtils.TruncateAt;
 import android.text.method.SingleLineTransformationMethod;
@@ -102,11 +104,11 @@
         text.setTransformationMethod(new SingleLineAllCapsTransform(text.getContext()));
     }
 
-    public PagerTitleStrip(Context context) {
+    public PagerTitleStrip(@NonNull Context context) {
         this(context, null);
     }
 
-    public PagerTitleStrip(Context context, AttributeSet attrs) {
+    public PagerTitleStrip(@NonNull Context context, @Nullable AttributeSet attrs) {
         super(context, attrs);
 
         addView(mPrevText = new TextView(context));
diff --git a/core-ui/java/android/support/v4/view/ViewPager.java b/core-ui/src/main/java/android/support/v4/view/ViewPager.java
similarity index 98%
rename from core-ui/java/android/support/v4/view/ViewPager.java
rename to core-ui/src/main/java/android/support/v4/view/ViewPager.java
index 8cd973c..36d8696 100644
--- a/core-ui/java/android/support/v4/view/ViewPager.java
+++ b/core-ui/src/main/java/android/support/v4/view/ViewPager.java
@@ -347,7 +347,7 @@
          *                 position of the pager. 0 is front and center. 1 is one full
          *                 page position to the right, and -1 is one page position to the left.
          */
-        void transformPage(View page, float position);
+        void transformPage(@NonNull View page, float position);
     }
 
     /**
@@ -381,12 +381,12 @@
     public @interface DecorView {
     }
 
-    public ViewPager(Context context) {
+    public ViewPager(@NonNull Context context) {
         super(context);
         initViewPager();
     }
 
-    public ViewPager(Context context, AttributeSet attrs) {
+    public ViewPager(@NonNull Context context, @Nullable AttributeSet attrs) {
         super(context, attrs);
         initViewPager();
     }
@@ -496,7 +496,7 @@
      *
      * @param adapter Adapter to use
      */
-    public void setAdapter(PagerAdapter adapter) {
+    public void setAdapter(@Nullable PagerAdapter adapter) {
         if (mAdapter != null) {
             mAdapter.setViewPagerObserver(null);
             mAdapter.startUpdate(this);
@@ -561,6 +561,7 @@
      *
      * @return The currently registered PagerAdapter
      */
+    @Nullable
     public PagerAdapter getAdapter() {
         return mAdapter;
     }
@@ -712,7 +713,7 @@
      *
      * @param listener listener to add
      */
-    public void addOnPageChangeListener(OnPageChangeListener listener) {
+    public void addOnPageChangeListener(@NonNull OnPageChangeListener listener) {
         if (mOnPageChangeListeners == null) {
             mOnPageChangeListeners = new ArrayList<>();
         }
@@ -725,7 +726,7 @@
      *
      * @param listener listener to remove
      */
-    public void removeOnPageChangeListener(OnPageChangeListener listener) {
+    public void removeOnPageChangeListener(@NonNull OnPageChangeListener listener) {
         if (mOnPageChangeListeners != null) {
             mOnPageChangeListeners.remove(listener);
         }
@@ -757,7 +758,8 @@
      *                            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) {
+    public void setPageTransformer(boolean reverseDrawingOrder,
+            @Nullable PageTransformer transformer) {
         setPageTransformer(reverseDrawingOrder, transformer, View.LAYER_TYPE_HARDWARE);
     }
 
@@ -774,8 +776,8 @@
      *                      {@link View#LAYER_TYPE_SOFTWARE}, or
      *                      {@link View#LAYER_TYPE_NONE}.
      */
-    public void setPageTransformer(boolean reverseDrawingOrder, PageTransformer transformer,
-            int pageLayerType) {
+    public void setPageTransformer(boolean reverseDrawingOrder,
+            @Nullable PageTransformer transformer, int pageLayerType) {
         final boolean hasTransformer = transformer != null;
         final boolean needsPopulate = hasTransformer != (mPageTransformer != null);
         mPageTransformer = transformer;
@@ -881,7 +883,7 @@
      *
      * @param d Drawable to display between pages
      */
-    public void setPageMarginDrawable(Drawable d) {
+    public void setPageMarginDrawable(@Nullable Drawable d) {
         mMarginDrawable = d;
         if (d != null) refreshDrawableState();
         setWillNotDraw(d == null);
@@ -1383,7 +1385,7 @@
         Parcelable adapterState;
         ClassLoader loader;
 
-        public SavedState(Parcelable superState) {
+        public SavedState(@NonNull Parcelable superState) {
             super(superState);
         }
 
@@ -2744,7 +2746,7 @@
      * @param event The key event to execute.
      * @return Return true if the event was handled, else false.
      */
-    public boolean executeKeyEvent(KeyEvent event) {
+    public boolean executeKeyEvent(@NonNull KeyEvent event) {
         boolean handled = false;
         if (event.getAction() == KeyEvent.ACTION_DOWN) {
             switch (event.getKeyCode()) {
diff --git a/core-ui/java/android/support/v4/view/animation/FastOutLinearInInterpolator.java b/core-ui/src/main/java/android/support/v4/view/animation/FastOutLinearInInterpolator.java
similarity index 100%
rename from core-ui/java/android/support/v4/view/animation/FastOutLinearInInterpolator.java
rename to core-ui/src/main/java/android/support/v4/view/animation/FastOutLinearInInterpolator.java
diff --git a/core-ui/java/android/support/v4/view/animation/FastOutSlowInInterpolator.java b/core-ui/src/main/java/android/support/v4/view/animation/FastOutSlowInInterpolator.java
similarity index 100%
rename from core-ui/java/android/support/v4/view/animation/FastOutSlowInInterpolator.java
rename to core-ui/src/main/java/android/support/v4/view/animation/FastOutSlowInInterpolator.java
diff --git a/core-ui/java/android/support/v4/view/animation/LinearOutSlowInInterpolator.java b/core-ui/src/main/java/android/support/v4/view/animation/LinearOutSlowInInterpolator.java
similarity index 100%
rename from core-ui/java/android/support/v4/view/animation/LinearOutSlowInInterpolator.java
rename to core-ui/src/main/java/android/support/v4/view/animation/LinearOutSlowInInterpolator.java
diff --git a/core-ui/java/android/support/v4/view/animation/LookupTableInterpolator.java b/core-ui/src/main/java/android/support/v4/view/animation/LookupTableInterpolator.java
similarity index 100%
rename from core-ui/java/android/support/v4/view/animation/LookupTableInterpolator.java
rename to core-ui/src/main/java/android/support/v4/view/animation/LookupTableInterpolator.java
diff --git a/core-ui/java/android/support/v4/view/package.html b/core-ui/src/main/java/android/support/v4/view/package.html
similarity index 100%
rename from core-ui/java/android/support/v4/view/package.html
rename to core-ui/src/main/java/android/support/v4/view/package.html
diff --git a/core-ui/java/android/support/v4/widget/AutoScrollHelper.java b/core-ui/src/main/java/android/support/v4/widget/AutoScrollHelper.java
similarity index 99%
rename from core-ui/java/android/support/v4/widget/AutoScrollHelper.java
rename to core-ui/src/main/java/android/support/v4/widget/AutoScrollHelper.java
index d0407be..60d208d 100644
--- a/core-ui/java/android/support/v4/widget/AutoScrollHelper.java
+++ b/core-ui/src/main/java/android/support/v4/widget/AutoScrollHelper.java
@@ -18,6 +18,7 @@
 
 import android.content.res.Resources;
 import android.os.SystemClock;
+import android.support.annotation.NonNull;
 import android.support.v4.view.ViewCompat;
 import android.util.DisplayMetrics;
 import android.view.MotionEvent;
@@ -205,7 +206,7 @@
      *
      * @param target The view to automatically scroll.
      */
-    public AutoScrollHelper(View target) {
+    public AutoScrollHelper(@NonNull View target) {
         mTarget = target;
 
         final DisplayMetrics metrics = Resources.getSystem().getDisplayMetrics();
@@ -289,6 +290,7 @@
      *            {@link #NO_MAX} to leave the relative value unconstrained.
      * @return The scroll helper, which may used to chain setter calls.
      */
+    @NonNull
     public AutoScrollHelper setMaximumVelocity(float horizontalMax, float verticalMax) {
         mMaximumVelocity[HORIZONTAL] = horizontalMax / 1000f;
         mMaximumVelocity[VERTICAL] = verticalMax / 1000f;
@@ -307,6 +309,7 @@
      *            {@link #NO_MIN} to leave the relative value unconstrained.
      * @return The scroll helper, which may used to chain setter calls.
      */
+    @NonNull
     public AutoScrollHelper setMinimumVelocity(float horizontalMin, float verticalMin) {
         mMinimumVelocity[HORIZONTAL] = horizontalMin / 1000f;
         mMinimumVelocity[VERTICAL] = verticalMin / 1000f;
@@ -328,6 +331,7 @@
      *            ignore.
      * @return The scroll helper, which may used to chain setter calls.
      */
+    @NonNull
     public AutoScrollHelper setRelativeVelocity(float horizontal, float vertical) {
         mRelativeVelocity[HORIZONTAL] = horizontal / 1000f;
         mRelativeVelocity[VERTICAL] = vertical / 1000f;
@@ -349,6 +353,7 @@
      * @param type The type of edge to use.
      * @return The scroll helper, which may used to chain setter calls.
      */
+    @NonNull
     public AutoScrollHelper setEdgeType(int type) {
         mEdgeType = type;
         return this;
@@ -368,6 +373,7 @@
      *            maximum value.
      * @return The scroll helper, which may used to chain setter calls.
      */
+    @NonNull
     public AutoScrollHelper setRelativeEdges(float horizontal, float vertical) {
         mRelativeEdges[HORIZONTAL] = horizontal;
         mRelativeEdges[VERTICAL] = vertical;
@@ -390,6 +396,7 @@
      *            value.
      * @return The scroll helper, which may used to chain setter calls.
      */
+    @NonNull
     public AutoScrollHelper setMaximumEdges(float horizontalMax, float verticalMax) {
         mMaximumEdges[HORIZONTAL] = horizontalMax;
         mMaximumEdges[VERTICAL] = verticalMax;
@@ -407,6 +414,7 @@
      * @param delayMillis The activation delay in milliseconds.
      * @return The scroll helper, which may used to chain setter calls.
      */
+    @NonNull
     public AutoScrollHelper setActivationDelay(int delayMillis) {
         mActivationDelay = delayMillis;
         return this;
@@ -422,6 +430,7 @@
      * @param durationMillis The ramp-up duration in milliseconds.
      * @return The scroll helper, which may used to chain setter calls.
      */
+    @NonNull
     public AutoScrollHelper setRampUpDuration(int durationMillis) {
         mScroller.setRampUpDuration(durationMillis);
         return this;
@@ -437,6 +446,7 @@
      * @param durationMillis The ramp-down duration in milliseconds.
      * @return The scroll helper, which may used to chain setter calls.
      */
+    @NonNull
     public AutoScrollHelper setRampDownDuration(int durationMillis) {
         mScroller.setRampDownDuration(durationMillis);
         return this;
diff --git a/core-ui/java/android/support/v4/widget/CircleImageView.java b/core-ui/src/main/java/android/support/v4/widget/CircleImageView.java
similarity index 100%
rename from core-ui/java/android/support/v4/widget/CircleImageView.java
rename to core-ui/src/main/java/android/support/v4/widget/CircleImageView.java
diff --git a/core-ui/java/android/support/v4/widget/CircularProgressDrawable.java b/core-ui/src/main/java/android/support/v4/widget/CircularProgressDrawable.java
similarity index 99%
rename from core-ui/java/android/support/v4/widget/CircularProgressDrawable.java
rename to core-ui/src/main/java/android/support/v4/widget/CircularProgressDrawable.java
index ac29541..2055669 100644
--- a/core-ui/java/android/support/v4/widget/CircularProgressDrawable.java
+++ b/core-ui/src/main/java/android/support/v4/widget/CircularProgressDrawable.java
@@ -132,7 +132,7 @@
     /**
      * @param context application context
      */
-    public CircularProgressDrawable(Context context) {
+    public CircularProgressDrawable(@NonNull Context context) {
         mResources = Preconditions.checkNotNull(context).getResources();
 
         mRing = new Ring();
@@ -215,7 +215,7 @@
      *
      * @param strokeCap stroke cap
      */
-    public void setStrokeCap(Paint.Cap strokeCap) {
+    public void setStrokeCap(@NonNull Paint.Cap strokeCap) {
         mRing.setStrokeCap(strokeCap);
         invalidateSelf();
     }
@@ -225,6 +225,7 @@
      *
      * @return stroke cap
      */
+    @NonNull
     public Paint.Cap getStrokeCap() {
         return mRing.getStrokeCap();
     }
@@ -373,6 +374,7 @@
      *
      * @return list of ARGB colors
      */
+    @NonNull
     public int[] getColorSchemeColors() {
         return mRing.getColors();
     }
@@ -383,7 +385,7 @@
      *
      * @param colors list of ARGB colors to be used in the spinner
      */
-    public void setColorSchemeColors(int... colors) {
+    public void setColorSchemeColors(@NonNull int... colors) {
         mRing.setColors(colors);
         mRing.setColorIndex(0);
         invalidateSelf();
diff --git a/core-ui/java/android/support/v4/widget/ContentLoadingProgressBar.java b/core-ui/src/main/java/android/support/v4/widget/ContentLoadingProgressBar.java
similarity index 93%
rename from core-ui/java/android/support/v4/widget/ContentLoadingProgressBar.java
rename to core-ui/src/main/java/android/support/v4/widget/ContentLoadingProgressBar.java
index 98b63a4..356c7b9 100644
--- a/core-ui/java/android/support/v4/widget/ContentLoadingProgressBar.java
+++ b/core-ui/src/main/java/android/support/v4/widget/ContentLoadingProgressBar.java
@@ -17,6 +17,8 @@
 package android.support.v4.widget;
 
 import android.content.Context;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
 import android.util.AttributeSet;
 import android.view.View;
 import android.widget.ProgressBar;
@@ -61,11 +63,11 @@
         }
     };
 
-    public ContentLoadingProgressBar(Context context) {
+    public ContentLoadingProgressBar(@NonNull Context context) {
         this(context, null);
     }
 
-    public ContentLoadingProgressBar(Context context, AttributeSet attrs) {
+    public ContentLoadingProgressBar(@NonNull Context context, @Nullable AttributeSet attrs) {
         super(context, attrs, 0);
     }
 
diff --git a/core-ui/java/android/support/v4/widget/CursorAdapter.java b/core-ui/src/main/java/android/support/v4/widget/CursorAdapter.java
similarity index 100%
rename from core-ui/java/android/support/v4/widget/CursorAdapter.java
rename to core-ui/src/main/java/android/support/v4/widget/CursorAdapter.java
diff --git a/core-ui/java/android/support/v4/widget/CursorFilter.java b/core-ui/src/main/java/android/support/v4/widget/CursorFilter.java
similarity index 100%
rename from core-ui/java/android/support/v4/widget/CursorFilter.java
rename to core-ui/src/main/java/android/support/v4/widget/CursorFilter.java
diff --git a/core-ui/java/android/support/v4/widget/DrawerLayout.java b/core-ui/src/main/java/android/support/v4/widget/DrawerLayout.java
similarity index 98%
rename from core-ui/java/android/support/v4/widget/DrawerLayout.java
rename to core-ui/src/main/java/android/support/v4/widget/DrawerLayout.java
index c7b40e9..a73e1f1 100644
--- a/core-ui/java/android/support/v4/widget/DrawerLayout.java
+++ b/core-ui/src/main/java/android/support/v4/widget/DrawerLayout.java
@@ -248,7 +248,7 @@
          * @param drawerView The child view that was moved
          * @param slideOffset The new offset of this drawer within its range, from 0-1
          */
-        void onDrawerSlide(View drawerView, float slideOffset);
+        void onDrawerSlide(@NonNull View drawerView, float slideOffset);
 
         /**
          * Called when a drawer has settled in a completely open state.
@@ -256,14 +256,14 @@
          *
          * @param drawerView Drawer view that is now open
          */
-        void onDrawerOpened(View drawerView);
+        void onDrawerOpened(@NonNull View drawerView);
 
         /**
          * Called when a drawer has settled in a completely closed state.
          *
          * @param drawerView Drawer view that is now closed
          */
-        void onDrawerClosed(View drawerView);
+        void onDrawerClosed(@NonNull View drawerView);
 
         /**
          * Called when the drawer motion state changes. The new state will
@@ -296,15 +296,15 @@
         }
     }
 
-    public DrawerLayout(Context context) {
+    public DrawerLayout(@NonNull Context context) {
         this(context, null);
     }
 
-    public DrawerLayout(Context context, AttributeSet attrs) {
+    public DrawerLayout(@NonNull Context context, @Nullable AttributeSet attrs) {
         this(context, attrs, 0);
     }
 
-    public DrawerLayout(Context context, AttributeSet attrs, int defStyle) {
+    public DrawerLayout(@NonNull Context context, @Nullable AttributeSet attrs, int defStyle) {
         super(context, attrs, defStyle);
         setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
         final float density = getResources().getDisplayMetrics().density;
@@ -626,7 +626,7 @@
      * @see #LOCK_MODE_LOCKED_CLOSED
      * @see #LOCK_MODE_LOCKED_OPEN
      */
-    public void setDrawerLockMode(@LockMode int lockMode, View drawerView) {
+    public void setDrawerLockMode(@LockMode int lockMode, @NonNull View drawerView) {
         if (!isDrawerView(drawerView)) {
             throw new IllegalArgumentException("View " + drawerView + " is not a "
                     + "drawer with appropriate layout_gravity");
@@ -700,7 +700,7 @@
      *         {@link #LOCK_MODE_LOCKED_OPEN}.
      */
     @LockMode
-    public int getDrawerLockMode(View drawerView) {
+    public int getDrawerLockMode(@NonNull View drawerView) {
         if (!isDrawerView(drawerView)) {
             throw new IllegalArgumentException("View " + drawerView + " is not a drawer");
         }
@@ -718,7 +718,7 @@
      *            drawer to set the title for.
      * @param title The title for the drawer.
      */
-    public void setDrawerTitle(@EdgeGravity int edgeGravity, CharSequence title) {
+    public void setDrawerTitle(@EdgeGravity int edgeGravity, @Nullable CharSequence title) {
         final int absGravity = GravityCompat.getAbsoluteGravity(
                 edgeGravity, ViewCompat.getLayoutDirection(this));
         if (absGravity == Gravity.LEFT) {
@@ -1276,7 +1276,7 @@
      *
      * @param bg Background drawable to draw behind the status bar
      */
-    public void setStatusBarBackground(Drawable bg) {
+    public void setStatusBarBackground(@Nullable Drawable bg) {
         mStatusBarBackground = bg;
         invalidate();
     }
@@ -1286,6 +1286,7 @@
      *
      * @return The status bar background drawable, or null if none set
      */
+    @Nullable
     public Drawable getStatusBarBackgroundDrawable() {
         return mStatusBarBackground;
     }
@@ -1577,7 +1578,7 @@
      *
      * @param drawerView Drawer view to open
      */
-    public void openDrawer(View drawerView) {
+    public void openDrawer(@NonNull View drawerView) {
         openDrawer(drawerView, true);
     }
 
@@ -1587,7 +1588,7 @@
      * @param drawerView Drawer view to open
      * @param animate Whether opening of the drawer should be animated.
      */
-    public void openDrawer(View drawerView, boolean animate) {
+    public void openDrawer(@NonNull View drawerView, boolean animate) {
         if (!isDrawerView(drawerView)) {
             throw new IllegalArgumentException("View " + drawerView + " is not a sliding drawer");
         }
@@ -1646,7 +1647,7 @@
      *
      * @param drawerView Drawer view to close
      */
-    public void closeDrawer(View drawerView) {
+    public void closeDrawer(@NonNull View drawerView) {
         closeDrawer(drawerView, true);
     }
 
@@ -1656,7 +1657,7 @@
      * @param drawerView Drawer view to close
      * @param animate Whether closing of the drawer should be animated.
      */
-    public void closeDrawer(View drawerView, boolean animate) {
+    public void closeDrawer(@NonNull View drawerView, boolean animate) {
         if (!isDrawerView(drawerView)) {
             throw new IllegalArgumentException("View " + drawerView + " is not a sliding drawer");
         }
@@ -1718,7 +1719,7 @@
      * @return true if the given drawer view is in an open state
      * @see #isDrawerVisible(android.view.View)
      */
-    public boolean isDrawerOpen(View drawer) {
+    public boolean isDrawerOpen(@NonNull View drawer) {
         if (!isDrawerView(drawer)) {
             throw new IllegalArgumentException("View " + drawer + " is not a drawer");
         }
@@ -1751,7 +1752,7 @@
      * @return true if the given drawer is visible on-screen
      * @see #isDrawerOpen(android.view.View)
      */
-    public boolean isDrawerVisible(View drawer) {
+    public boolean isDrawerVisible(@NonNull View drawer) {
         if (!isDrawerView(drawer)) {
             throw new IllegalArgumentException("View " + drawer + " is not a drawer");
         }
@@ -2001,7 +2002,7 @@
         @LockMode int lockModeStart;
         @LockMode int lockModeEnd;
 
-        public SavedState(Parcel in, ClassLoader loader) {
+        public SavedState(@NonNull Parcel in, @Nullable ClassLoader loader) {
             super(in, loader);
             openDrawerGravity = in.readInt();
             lockModeLeft = in.readInt();
@@ -2010,7 +2011,7 @@
             lockModeEnd = in.readInt();
         }
 
-        public SavedState(Parcelable superState) {
+        public SavedState(@NonNull Parcelable superState) {
             super(superState);
         }
 
@@ -2218,7 +2219,7 @@
         boolean isPeeking;
         int openState;
 
-        public LayoutParams(Context c, AttributeSet attrs) {
+        public LayoutParams(@NonNull Context c, @Nullable AttributeSet attrs) {
             super(c, attrs);
 
             final TypedArray a = c.obtainStyledAttributes(attrs, LAYOUT_ATTRS);
@@ -2235,16 +2236,16 @@
             this.gravity = gravity;
         }
 
-        public LayoutParams(LayoutParams source) {
+        public LayoutParams(@NonNull LayoutParams source) {
             super(source);
             this.gravity = source.gravity;
         }
 
-        public LayoutParams(ViewGroup.LayoutParams source) {
+        public LayoutParams(@NonNull ViewGroup.LayoutParams source) {
             super(source);
         }
 
-        public LayoutParams(ViewGroup.MarginLayoutParams source) {
+        public LayoutParams(@NonNull ViewGroup.MarginLayoutParams source) {
             super(source);
         }
     }
diff --git a/core-ui/java/android/support/v4/widget/ExploreByTouchHelper.java b/core-ui/src/main/java/android/support/v4/widget/ExploreByTouchHelper.java
similarity index 98%
rename from core-ui/java/android/support/v4/widget/ExploreByTouchHelper.java
rename to core-ui/src/main/java/android/support/v4/widget/ExploreByTouchHelper.java
index 8a29eff..2b5ed0a 100644
--- a/core-ui/java/android/support/v4/widget/ExploreByTouchHelper.java
+++ b/core-ui/src/main/java/android/support/v4/widget/ExploreByTouchHelper.java
@@ -129,7 +129,7 @@
      *
      * @param host view whose virtual view hierarchy is exposed by this helper
      */
-    public ExploreByTouchHelper(View host) {
+    public ExploreByTouchHelper(@NonNull View host) {
         if (host == null) {
             throw new IllegalArgumentException("View may not be null");
         }
@@ -1107,7 +1107,8 @@
      *            populate the event
      * @param event The event to populate
      */
-    protected void onPopulateEventForVirtualView(int virtualViewId, AccessibilityEvent event) {
+    protected void onPopulateEventForVirtualView(int virtualViewId,
+            @NonNull AccessibilityEvent event) {
         // Default implementation is no-op.
     }
 
@@ -1119,7 +1120,7 @@
      *
      * @param event the event to populate with information about the host view
      */
-    protected void onPopulateEventForHost(AccessibilityEvent event) {
+    protected void onPopulateEventForHost(@NonNull AccessibilityEvent event) {
         // Default implementation is no-op.
     }
 
@@ -1187,7 +1188,7 @@
      * @param node The node to populate
      */
     protected abstract void onPopulateNodeForVirtualView(
-            int virtualViewId, AccessibilityNodeInfoCompat node);
+            int virtualViewId, @NonNull AccessibilityNodeInfoCompat node);
 
     /**
      * Populates an {@link AccessibilityNodeInfoCompat} with information
@@ -1197,7 +1198,7 @@
      *
      * @param node the node to populate with information about the host view
      */
-    protected void onPopulateNodeForHost(AccessibilityNodeInfoCompat node) {
+    protected void onPopulateNodeForHost(@NonNull AccessibilityNodeInfoCompat node) {
         // Default implementation is no-op.
     }
 
@@ -1225,7 +1226,7 @@
      * @return true if the action was performed
      */
     protected abstract boolean onPerformActionForVirtualView(
-            int virtualViewId, int action, Bundle arguments);
+            int virtualViewId, int action, @Nullable Bundle arguments);
 
     /**
      * Exposes a virtual view hierarchy to the accessibility framework.
diff --git a/core-ui/java/android/support/v4/widget/FocusStrategy.java b/core-ui/src/main/java/android/support/v4/widget/FocusStrategy.java
similarity index 100%
rename from core-ui/java/android/support/v4/widget/FocusStrategy.java
rename to core-ui/src/main/java/android/support/v4/widget/FocusStrategy.java
diff --git a/core-ui/java/android/support/v4/widget/ListViewAutoScrollHelper.java b/core-ui/src/main/java/android/support/v4/widget/ListViewAutoScrollHelper.java
similarity index 95%
rename from core-ui/java/android/support/v4/widget/ListViewAutoScrollHelper.java
rename to core-ui/src/main/java/android/support/v4/widget/ListViewAutoScrollHelper.java
index 73d18ce..c373f27 100644
--- a/core-ui/java/android/support/v4/widget/ListViewAutoScrollHelper.java
+++ b/core-ui/src/main/java/android/support/v4/widget/ListViewAutoScrollHelper.java
@@ -16,6 +16,7 @@
 
 package android.support.v4.widget;
 
+import android.support.annotation.NonNull;
 import android.view.View;
 import android.widget.ListView;
 
@@ -26,7 +27,7 @@
 public class ListViewAutoScrollHelper extends AutoScrollHelper {
     private final ListView mTarget;
 
-    public ListViewAutoScrollHelper(ListView target) {
+    public ListViewAutoScrollHelper(@NonNull ListView target) {
         super(target);
 
         mTarget = target;
diff --git a/core-ui/java/android/support/v4/widget/NestedScrollView.java b/core-ui/src/main/java/android/support/v4/widget/NestedScrollView.java
similarity index 99%
rename from core-ui/java/android/support/v4/widget/NestedScrollView.java
rename to core-ui/src/main/java/android/support/v4/widget/NestedScrollView.java
index 517686f..73ff084 100644
--- a/core-ui/java/android/support/v4/widget/NestedScrollView.java
+++ b/core-ui/src/main/java/android/support/v4/widget/NestedScrollView.java
@@ -26,6 +26,8 @@
 import android.os.Bundle;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
 import android.support.annotation.RestrictTo;
 import android.support.v4.view.AccessibilityDelegateCompat;
 import android.support.v4.view.InputDeviceCompat;
@@ -181,15 +183,16 @@
 
     private OnScrollChangeListener mOnScrollChangeListener;
 
-    public NestedScrollView(Context context) {
+    public NestedScrollView(@NonNull Context context) {
         this(context, null);
     }
 
-    public NestedScrollView(Context context, AttributeSet attrs) {
+    public NestedScrollView(@NonNull Context context, @Nullable AttributeSet attrs) {
         this(context, attrs, 0);
     }
 
-    public NestedScrollView(Context context, AttributeSet attrs, int defStyleAttr) {
+    public NestedScrollView(@NonNull Context context, @Nullable AttributeSet attrs,
+            int defStyleAttr) {
         super(context, attrs, defStyleAttr);
         initScrollView();
 
@@ -441,7 +444,7 @@
      * @see android.view.View#getScrollX()
      * @see android.view.View#getScrollY()
      */
-    public void setOnScrollChangeListener(OnScrollChangeListener l) {
+    public void setOnScrollChangeListener(@Nullable OnScrollChangeListener l) {
         mOnScrollChangeListener = l;
     }
 
@@ -552,7 +555,7 @@
      * @param event The key event to execute.
      * @return Return true if the event was handled, else false.
      */
-    public boolean executeKeyEvent(KeyEvent event) {
+    public boolean executeKeyEvent(@NonNull KeyEvent event) {
         mTempRect.setEmpty();
 
         if (!canScroll()) {
diff --git a/core-ui/java/android/support/v4/widget/ResourceCursorAdapter.java b/core-ui/src/main/java/android/support/v4/widget/ResourceCursorAdapter.java
similarity index 100%
rename from core-ui/java/android/support/v4/widget/ResourceCursorAdapter.java
rename to core-ui/src/main/java/android/support/v4/widget/ResourceCursorAdapter.java
diff --git a/core-ui/java/android/support/v4/widget/SimpleCursorAdapter.java b/core-ui/src/main/java/android/support/v4/widget/SimpleCursorAdapter.java
similarity index 100%
rename from core-ui/java/android/support/v4/widget/SimpleCursorAdapter.java
rename to core-ui/src/main/java/android/support/v4/widget/SimpleCursorAdapter.java
diff --git a/core-ui/java/android/support/v4/widget/SlidingPaneLayout.java b/core-ui/src/main/java/android/support/v4/widget/SlidingPaneLayout.java
similarity index 98%
rename from core-ui/java/android/support/v4/widget/SlidingPaneLayout.java
rename to core-ui/src/main/java/android/support/v4/widget/SlidingPaneLayout.java
index 602df70..5676ccf 100644
--- a/core-ui/java/android/support/v4/widget/SlidingPaneLayout.java
+++ b/core-ui/src/main/java/android/support/v4/widget/SlidingPaneLayout.java
@@ -30,6 +30,8 @@
 import android.os.Parcelable;
 import android.support.annotation.ColorInt;
 import android.support.annotation.DrawableRes;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
 import android.support.annotation.RequiresApi;
 import android.support.v4.content.ContextCompat;
 import android.support.v4.view.AbsSavedState;
@@ -213,20 +215,20 @@
          * @param panel The child view that was moved
          * @param slideOffset The new offset of this sliding pane within its range, from 0-1
          */
-        void onPanelSlide(View panel, float slideOffset);
+        void onPanelSlide(@NonNull View panel, float slideOffset);
         /**
          * Called when a sliding pane becomes slid completely open. The pane may or may not
          * be interactive at this point depending on how much of the pane is visible.
          * @param panel The child view that was slid to an open position, revealing other panes
          */
-        void onPanelOpened(View panel);
+        void onPanelOpened(@NonNull View panel);
 
         /**
          * Called when a sliding pane becomes slid completely closed. The pane is now guaranteed
          * to be interactive. It may now obscure other views in the layout.
          * @param panel The child view that was slid to a closed position
          */
-        void onPanelClosed(View panel);
+        void onPanelClosed(@NonNull View panel);
     }
 
     /**
@@ -245,15 +247,15 @@
         }
     }
 
-    public SlidingPaneLayout(Context context) {
+    public SlidingPaneLayout(@NonNull Context context) {
         this(context, null);
     }
 
-    public SlidingPaneLayout(Context context, AttributeSet attrs) {
+    public SlidingPaneLayout(@NonNull Context context, @Nullable AttributeSet attrs) {
         this(context, attrs, 0);
     }
 
-    public SlidingPaneLayout(Context context, AttributeSet attrs, int defStyle) {
+    public SlidingPaneLayout(@NonNull Context context, @Nullable AttributeSet attrs, int defStyle) {
         super(context, attrs, defStyle);
 
         final float density = context.getResources().getDisplayMetrics().density;
@@ -324,7 +326,7 @@
         return mCoveredFadeColor;
     }
 
-    public void setPanelSlideListener(PanelSlideListener listener) {
+    public void setPanelSlideListener(@Nullable PanelSlideListener listener) {
         mPanelSlideListener = listener;
     }
 
@@ -1081,7 +1083,7 @@
      *
      * @param d drawable to use as a shadow
      */
-    public void setShadowDrawableLeft(Drawable d) {
+    public void setShadowDrawableLeft(@Nullable Drawable d) {
         mShadowDrawableLeft = d;
     }
 
@@ -1091,7 +1093,7 @@
      *
      * @param d drawable to use as a shadow
      */
-    public void setShadowDrawableRight(Drawable d) {
+    public void setShadowDrawableRight(@Nullable Drawable d) {
         mShadowDrawableRight = d;
     }
 
@@ -1410,20 +1412,20 @@
             super(width, height);
         }
 
-        public LayoutParams(android.view.ViewGroup.LayoutParams source) {
+        public LayoutParams(@NonNull android.view.ViewGroup.LayoutParams source) {
             super(source);
         }
 
-        public LayoutParams(MarginLayoutParams source) {
+        public LayoutParams(@NonNull MarginLayoutParams source) {
             super(source);
         }
 
-        public LayoutParams(LayoutParams source) {
+        public LayoutParams(@NonNull LayoutParams source) {
             super(source);
             this.weight = source.weight;
         }
 
-        public LayoutParams(Context c, AttributeSet attrs) {
+        public LayoutParams(@NonNull Context c, @Nullable AttributeSet attrs) {
             super(c, attrs);
 
             final TypedArray a = c.obtainStyledAttributes(attrs, ATTRS);
diff --git a/core-ui/java/android/support/v4/widget/Space.java b/core-ui/src/main/java/android/support/v4/widget/Space.java
similarity index 88%
rename from core-ui/java/android/support/v4/widget/Space.java
rename to core-ui/src/main/java/android/support/v4/widget/Space.java
index 77a2d2e..7d37a72 100644
--- a/core-ui/java/android/support/v4/widget/Space.java
+++ b/core-ui/src/main/java/android/support/v4/widget/Space.java
@@ -19,6 +19,8 @@
 import android.annotation.SuppressLint;
 import android.content.Context;
 import android.graphics.Canvas;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
 import android.util.AttributeSet;
 import android.view.View;
 
@@ -28,18 +30,18 @@
  */
 public class Space extends View {
 
-    public Space(Context context, AttributeSet attrs, int defStyle) {
+    public Space(@NonNull Context context, @Nullable AttributeSet attrs, int defStyle) {
         super(context, attrs, defStyle);
         if (getVisibility() == VISIBLE) {
             setVisibility(INVISIBLE);
         }
     }
 
-    public Space(Context context, AttributeSet attrs) {
+    public Space(@NonNull Context context, @Nullable AttributeSet attrs) {
         this(context, attrs, 0);
     }
 
-    public Space(Context context) {
+    public Space(@NonNull Context context) {
         this(context, null);
     }
 
diff --git a/core-ui/java/android/support/v4/widget/SwipeProgressBar.java b/core-ui/src/main/java/android/support/v4/widget/SwipeProgressBar.java
similarity index 100%
rename from core-ui/java/android/support/v4/widget/SwipeProgressBar.java
rename to core-ui/src/main/java/android/support/v4/widget/SwipeProgressBar.java
diff --git a/core-ui/java/android/support/v4/widget/SwipeRefreshLayout.java b/core-ui/src/main/java/android/support/v4/widget/SwipeRefreshLayout.java
similarity index 98%
rename from core-ui/java/android/support/v4/widget/SwipeRefreshLayout.java
rename to core-ui/src/main/java/android/support/v4/widget/SwipeRefreshLayout.java
index 2181bab..ca04e46 100644
--- a/core-ui/java/android/support/v4/widget/SwipeRefreshLayout.java
+++ b/core-ui/src/main/java/android/support/v4/widget/SwipeRefreshLayout.java
@@ -20,6 +20,7 @@
 import android.content.res.TypedArray;
 import android.support.annotation.ColorInt;
 import android.support.annotation.ColorRes;
+import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
 import android.support.annotation.VisibleForTesting;
 import android.support.v4.content.ContextCompat;
@@ -316,7 +317,7 @@
      *
      * @param context
      */
-    public SwipeRefreshLayout(Context context) {
+    public SwipeRefreshLayout(@NonNull Context context) {
         this(context, null);
     }
 
@@ -326,7 +327,7 @@
      * @param context
      * @param attrs
      */
-    public SwipeRefreshLayout(Context context, AttributeSet attrs) {
+    public SwipeRefreshLayout(@NonNull Context context, @Nullable AttributeSet attrs) {
         super(context, attrs);
 
         mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
@@ -387,7 +388,7 @@
      * Set the listener to be notified when a refresh is triggered via the swipe
      * gesture.
      */
-    public void setOnRefreshListener(OnRefreshListener listener) {
+    public void setOnRefreshListener(@Nullable OnRefreshListener listener) {
         mListener = listener;
     }
 
@@ -1189,6 +1190,6 @@
          *
          * @return Whether it is possible for the child view of parent layout to scroll up.
          */
-        boolean canChildScrollUp(SwipeRefreshLayout parent, @Nullable View child);
+        boolean canChildScrollUp(@NonNull SwipeRefreshLayout parent, @Nullable View child);
     }
 }
diff --git a/core-ui/java/android/support/v4/widget/ViewDragHelper.java b/core-ui/src/main/java/android/support/v4/widget/ViewDragHelper.java
similarity index 97%
rename from core-ui/java/android/support/v4/widget/ViewDragHelper.java
rename to core-ui/src/main/java/android/support/v4/widget/ViewDragHelper.java
index c222c17..09c6f66 100644
--- a/core-ui/java/android/support/v4/widget/ViewDragHelper.java
+++ b/core-ui/src/main/java/android/support/v4/widget/ViewDragHelper.java
@@ -18,6 +18,8 @@
 package android.support.v4.widget;
 
 import android.content.Context;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
 import android.support.v4.view.ViewCompat;
 import android.util.Log;
 import android.view.MotionEvent;
@@ -167,7 +169,9 @@
          * @param dx Change in X position from the last call
          * @param dy Change in Y position from the last call
          */
-        public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {}
+        public void onViewPositionChanged(@NonNull View changedView, int left, int top, int dx,
+                int dy) {
+        }
 
         /**
          * Called when a child view is captured for dragging or settling. The ID of the pointer
@@ -178,7 +182,7 @@
          * @param capturedChild Child view that was captured
          * @param activePointerId Pointer id tracking the child capture
          */
-        public void onViewCaptured(View capturedChild, int activePointerId) {}
+        public void onViewCaptured(@NonNull View capturedChild, int activePointerId) {}
 
         /**
          * Called when the child view is no longer being actively dragged.
@@ -198,7 +202,7 @@
          * @param xvel X velocity of the pointer as it left the screen in pixels per second.
          * @param yvel Y velocity of the pointer as it left the screen in pixels per second.
          */
-        public void onViewReleased(View releasedChild, float xvel, float yvel) {}
+        public void onViewReleased(@NonNull View releasedChild, float xvel, float yvel) {}
 
         /**
          * Called when one of the subscribed edges in the parent view has been touched
@@ -256,7 +260,7 @@
          * @param child Child view to check
          * @return range of horizontal motion in pixels
          */
-        public int getViewHorizontalDragRange(View child) {
+        public int getViewHorizontalDragRange(@NonNull View child) {
             return 0;
         }
 
@@ -267,7 +271,7 @@
          * @param child Child view to check
          * @return range of vertical motion in pixels
          */
-        public int getViewVerticalDragRange(View child) {
+        public int getViewVerticalDragRange(@NonNull View child) {
             return 0;
         }
 
@@ -287,7 +291,7 @@
          * @param pointerId ID of the pointer attempting the capture
          * @return true if capture should be allowed, false otherwise
          */
-        public abstract boolean tryCaptureView(View child, int pointerId);
+        public abstract boolean tryCaptureView(@NonNull View child, int pointerId);
 
         /**
          * Restrict the motion of the dragged child view along the horizontal axis.
@@ -300,7 +304,7 @@
          * @param dx Proposed change in position for left
          * @return The new clamped position for left
          */
-        public int clampViewPositionHorizontal(View child, int left, int dx) {
+        public int clampViewPositionHorizontal(@NonNull View child, int left, int dx) {
             return 0;
         }
 
@@ -315,7 +319,7 @@
          * @param dy Proposed change in position for top
          * @return The new clamped position for top
          */
-        public int clampViewPositionVertical(View child, int top, int dy) {
+        public int clampViewPositionVertical(@NonNull View child, int top, int dy) {
             return 0;
         }
     }
@@ -345,7 +349,7 @@
      * @param cb Callback to provide information and receive events
      * @return a new ViewDragHelper instance
      */
-    public static ViewDragHelper create(ViewGroup forParent, Callback cb) {
+    public static ViewDragHelper create(@NonNull ViewGroup forParent, @NonNull Callback cb) {
         return new ViewDragHelper(forParent.getContext(), forParent, cb);
     }
 
@@ -358,7 +362,8 @@
      * @param cb Callback to provide information and receive events
      * @return a new ViewDragHelper instance
      */
-    public static ViewDragHelper create(ViewGroup forParent, float sensitivity, Callback cb) {
+    public static ViewDragHelper create(@NonNull ViewGroup forParent, float sensitivity,
+            @NonNull Callback cb) {
         final ViewDragHelper helper = create(forParent, cb);
         helper.mTouchSlop = (int) (helper.mTouchSlop * (1 / sensitivity));
         return helper;
@@ -372,7 +377,8 @@
      * @param context Context to initialize config-dependent params from
      * @param forParent Parent view to monitor
      */
-    private ViewDragHelper(Context context, ViewGroup forParent, Callback cb) {
+    private ViewDragHelper(@NonNull Context context, @NonNull ViewGroup forParent,
+            @NonNull Callback cb) {
         if (forParent == null) {
             throw new IllegalArgumentException("Parent view may not be null");
         }
@@ -458,7 +464,7 @@
      * @param childView Child view to capture
      * @param activePointerId ID of the pointer that is dragging the captured child view
      */
-    public void captureChildView(View childView, int activePointerId) {
+    public void captureChildView(@NonNull View childView, int activePointerId) {
         if (childView.getParent() != mParentView) {
             throw new IllegalArgumentException("captureChildView: parameter must be a descendant "
                     + "of the ViewDragHelper's tracked parent view (" + mParentView + ")");
@@ -473,6 +479,7 @@
     /**
      * @return The currently captured view, or null if no view has been captured.
      */
+    @Nullable
     public View getCapturedView() {
         return mCapturedView;
     }
@@ -537,7 +544,7 @@
      * @param finalTop Final top position of child
      * @return true if animation should continue through {@link #continueSettling(boolean)} calls
      */
-    public boolean smoothSlideViewTo(View child, int finalLeft, int finalTop) {
+    public boolean smoothSlideViewTo(@NonNull View child, int finalLeft, int finalTop) {
         mCapturedView = child;
         mActivePointerId = INVALID_POINTER;
 
@@ -918,7 +925,7 @@
      * @param y Y coordinate of the active touch point
      * @return true if child views of v can be scrolled by delta of dx.
      */
-    protected boolean canScroll(View v, boolean checkV, int dx, int dy, int x, int y) {
+    protected boolean canScroll(@NonNull View v, boolean checkV, int dx, int dy, int x, int y) {
         if (v instanceof ViewGroup) {
             final ViewGroup group = (ViewGroup) v;
             final int scrollX = v.getScrollX();
@@ -948,7 +955,7 @@
      * @param ev MotionEvent provided to onInterceptTouchEvent
      * @return true if the parent view should return true from onInterceptTouchEvent
      */
-    public boolean shouldInterceptTouchEvent(MotionEvent ev) {
+    public boolean shouldInterceptTouchEvent(@NonNull MotionEvent ev) {
         final int action = ev.getActionMasked();
         final int actionIndex = ev.getActionIndex();
 
@@ -1082,7 +1089,7 @@
      *
      * @param ev The touch event received by the parent view
      */
-    public void processTouchEvent(MotionEvent ev) {
+    public void processTouchEvent(@NonNull MotionEvent ev) {
         final int action = ev.getActionMasked();
         final int actionIndex = ev.getActionIndex();
 
@@ -1453,7 +1460,7 @@
      * @param y Y position to test in the parent's coordinate system
      * @return true if the supplied view is under the given point, false otherwise
      */
-    public boolean isViewUnder(View view, int x, int y) {
+    public boolean isViewUnder(@Nullable View view, int x, int y) {
         if (view == null) {
             return false;
         }
@@ -1471,6 +1478,7 @@
      * @param y Y position to test in the parent's coordinate system
      * @return The topmost child view under (x, y) or null if none found.
      */
+    @Nullable
     public View findTopChildUnder(int x, int y) {
         final int childCount = mParentView.getChildCount();
         for (int i = childCount - 1; i >= 0; i--) {
diff --git a/core-ui/java/android/support/v4/widget/package.html b/core-ui/src/main/java/android/support/v4/widget/package.html
similarity index 100%
rename from core-ui/java/android/support/v4/widget/package.html
rename to core-ui/src/main/java/android/support/v4/widget/package.html
diff --git a/customtabs/Android.mk b/customtabs/Android.mk
index cfd9971..f9195e8 100644
--- a/customtabs/Android.mk
+++ b/customtabs/Android.mk
@@ -26,10 +26,10 @@
 LOCAL_USE_AAPT2 := true
 LOCAL_MODULE := android-support-customtabs
 LOCAL_SDK_VERSION := $(SUPPORT_CURRENT_SDK_VERSION)
-LOCAL_AIDL_INCLUDES := $LOCAL_PATH/src
+LOCAL_AIDL_INCLUDES := $(LOCAL_PATH)/src/main/java
 LOCAL_SRC_FILES := \
-    $(call all-java-files-under,src) \
-    $(call all-Iaidl-files-under,src)
+    $(call all-java-files-under,src/main/java) \
+    $(call all-Iaidl-files-under,src/main/java)
 LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
 LOCAL_SHARED_ANDROID_LIBRARIES := \
     android-support-annotations \
diff --git a/customtabs/api/current.txt b/customtabs/api/current.txt
index 05c16c1..8494391 100644
--- a/customtabs/api/current.txt
+++ b/customtabs/api/current.txt
@@ -114,6 +114,7 @@
   }
 
   public final class CustomTabsSession {
+    method public static android.support.customtabs.CustomTabsSession createMockSessionForTesting(android.content.ComponentName);
     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);
@@ -124,6 +125,7 @@
   }
 
   public class CustomTabsSessionToken {
+    method public static android.support.customtabs.CustomTabsSessionToken createMockSessionTokenForTesting();
     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);
@@ -146,5 +148,10 @@
     method public void unbindFromContext(android.content.Context);
   }
 
+  public class TrustedWebUtils {
+    method public static void launchAsTrustedWebActivity(android.content.Context, android.support.customtabs.CustomTabsIntent, android.net.Uri);
+    field public static final java.lang.String EXTRA_LAUNCH_AS_TRUSTED_WEB_ACTIVITY = "android.support.customtabs.extra.LAUNCH_AS_TRUSTED_WEB_ACTIVITY";
+  }
+
 }
 
diff --git a/customtabs/build.gradle b/customtabs/build.gradle
index 6cf8b77..fc90301 100644
--- a/customtabs/build.gradle
+++ b/customtabs/build.gradle
@@ -15,11 +15,7 @@
     }
 
     sourceSets {
-        main.java.srcDirs = ['src']
-        main.aidl.srcDirs = ['src']
-        main.res.srcDir 'res'
-        main.assets.srcDir 'assets'
-        main.resources.srcDir 'java'
+        main.aidl.srcDirs = ['src/main/java']
     }
 }
 
diff --git a/customtabs/src/android/support/customtabs/CustomTabsCallback.java b/customtabs/src/main/java/android/support/customtabs/CustomTabsCallback.java
similarity index 100%
rename from customtabs/src/android/support/customtabs/CustomTabsCallback.java
rename to customtabs/src/main/java/android/support/customtabs/CustomTabsCallback.java
diff --git a/customtabs/src/android/support/customtabs/CustomTabsClient.java b/customtabs/src/main/java/android/support/customtabs/CustomTabsClient.java
similarity index 100%
rename from customtabs/src/android/support/customtabs/CustomTabsClient.java
rename to customtabs/src/main/java/android/support/customtabs/CustomTabsClient.java
diff --git a/customtabs/src/android/support/customtabs/CustomTabsIntent.java b/customtabs/src/main/java/android/support/customtabs/CustomTabsIntent.java
similarity index 100%
rename from customtabs/src/android/support/customtabs/CustomTabsIntent.java
rename to customtabs/src/main/java/android/support/customtabs/CustomTabsIntent.java
diff --git a/customtabs/src/android/support/customtabs/CustomTabsService.java b/customtabs/src/main/java/android/support/customtabs/CustomTabsService.java
similarity index 100%
rename from customtabs/src/android/support/customtabs/CustomTabsService.java
rename to customtabs/src/main/java/android/support/customtabs/CustomTabsService.java
diff --git a/customtabs/src/android/support/customtabs/CustomTabsServiceConnection.java b/customtabs/src/main/java/android/support/customtabs/CustomTabsServiceConnection.java
similarity index 100%
rename from customtabs/src/android/support/customtabs/CustomTabsServiceConnection.java
rename to customtabs/src/main/java/android/support/customtabs/CustomTabsServiceConnection.java
diff --git a/customtabs/src/android/support/customtabs/CustomTabsSession.java b/customtabs/src/main/java/android/support/customtabs/CustomTabsSession.java
similarity index 94%
rename from customtabs/src/android/support/customtabs/CustomTabsSession.java
rename to customtabs/src/main/java/android/support/customtabs/CustomTabsSession.java
index d4930ae..a84d63c 100644
--- a/customtabs/src/android/support/customtabs/CustomTabsSession.java
+++ b/customtabs/src/main/java/android/support/customtabs/CustomTabsSession.java
@@ -25,6 +25,7 @@
 import android.os.RemoteException;
 import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
+import android.support.annotation.VisibleForTesting;
 import android.support.customtabs.CustomTabsService.Relation;
 import android.support.customtabs.CustomTabsService.Result;
 import android.view.View;
@@ -43,6 +44,21 @@
     private final ICustomTabsCallback mCallback;
     private final ComponentName mComponentName;
 
+    /**
+     * Provides browsers a way to generate a mock {@link CustomTabsSession} for testing
+     * purposes.
+     *
+     * @param componentName The component the session should be created for.
+     * @return A mock session with no functionality.
+     */
+    @VisibleForTesting
+    @NonNull
+    public static CustomTabsSession createMockSessionForTesting(
+            @NonNull ComponentName componentName) {
+        return new CustomTabsSession(
+                null, new CustomTabsSessionToken.MockCallback(), componentName);
+    }
+
     /* package */ CustomTabsSession(
             ICustomTabsService service, ICustomTabsCallback callback, ComponentName componentName) {
         mService = service;
diff --git a/customtabs/src/android/support/customtabs/CustomTabsSessionToken.java b/customtabs/src/main/java/android/support/customtabs/CustomTabsSessionToken.java
similarity index 82%
rename from customtabs/src/android/support/customtabs/CustomTabsSessionToken.java
rename to customtabs/src/main/java/android/support/customtabs/CustomTabsSessionToken.java
index ee47278..5a9e1b6 100644
--- a/customtabs/src/android/support/customtabs/CustomTabsSessionToken.java
+++ b/customtabs/src/main/java/android/support/customtabs/CustomTabsSessionToken.java
@@ -21,6 +21,7 @@
 import android.os.Bundle;
 import android.os.IBinder;
 import android.os.RemoteException;
+import android.support.annotation.NonNull;
 import android.support.customtabs.CustomTabsService.Relation;
 import android.support.v4.app.BundleCompat;
 import android.util.Log;
@@ -34,6 +35,29 @@
     private final ICustomTabsCallback mCallbackBinder;
     private final CustomTabsCallback mCallback;
 
+    /* package */ static class MockCallback extends ICustomTabsCallback.Stub {
+        @Override
+        public void onNavigationEvent(int navigationEvent, Bundle extras) {}
+
+        @Override
+        public void extraCallback(String callbackName, Bundle args) {}
+
+        @Override
+        public void onMessageChannelReady(Bundle extras) {}
+
+        @Override
+        public void onPostMessage(String message, Bundle extras) {}
+
+        @Override
+        public void onRelationshipValidationResult(@Relation int relation, Uri requestedOrigin,
+                boolean result, Bundle extras) {}
+
+        @Override
+        public IBinder asBinder() {
+            return this;
+        }
+    }
+
     /**
      * Obtain a {@link CustomTabsSessionToken} from an intent. See {@link CustomTabsIntent.Builder}
      * for ways to generate an intent for custom tabs.
@@ -48,6 +72,17 @@
         return new CustomTabsSessionToken(ICustomTabsCallback.Stub.asInterface(binder));
     }
 
+    /**
+     * Provides browsers a way to generate a mock {@link CustomTabsSessionToken} for testing
+     * purposes.
+     *
+     * @return A mock token with no functionality.
+     */
+    @NonNull
+    public static CustomTabsSessionToken createMockSessionTokenForTesting() {
+        return new CustomTabsSessionToken(new MockCallback());
+    }
+
     CustomTabsSessionToken(ICustomTabsCallback callbackBinder) {
         mCallbackBinder = callbackBinder;
         mCallback = new CustomTabsCallback() {
diff --git a/customtabs/src/android/support/customtabs/ICustomTabsCallback.aidl b/customtabs/src/main/java/android/support/customtabs/ICustomTabsCallback.aidl
similarity index 100%
rename from customtabs/src/android/support/customtabs/ICustomTabsCallback.aidl
rename to customtabs/src/main/java/android/support/customtabs/ICustomTabsCallback.aidl
diff --git a/customtabs/src/android/support/customtabs/ICustomTabsService.aidl b/customtabs/src/main/java/android/support/customtabs/ICustomTabsService.aidl
similarity index 100%
rename from customtabs/src/android/support/customtabs/ICustomTabsService.aidl
rename to customtabs/src/main/java/android/support/customtabs/ICustomTabsService.aidl
diff --git a/customtabs/src/android/support/customtabs/IPostMessageService.aidl b/customtabs/src/main/java/android/support/customtabs/IPostMessageService.aidl
similarity index 100%
rename from customtabs/src/android/support/customtabs/IPostMessageService.aidl
rename to customtabs/src/main/java/android/support/customtabs/IPostMessageService.aidl
diff --git a/customtabs/src/android/support/customtabs/PostMessageService.java b/customtabs/src/main/java/android/support/customtabs/PostMessageService.java
similarity index 100%
rename from customtabs/src/android/support/customtabs/PostMessageService.java
rename to customtabs/src/main/java/android/support/customtabs/PostMessageService.java
diff --git a/customtabs/src/android/support/customtabs/PostMessageServiceConnection.java b/customtabs/src/main/java/android/support/customtabs/PostMessageServiceConnection.java
similarity index 100%
rename from customtabs/src/android/support/customtabs/PostMessageServiceConnection.java
rename to customtabs/src/main/java/android/support/customtabs/PostMessageServiceConnection.java
diff --git a/customtabs/src/main/java/android/support/customtabs/TrustedWebUtils.java b/customtabs/src/main/java/android/support/customtabs/TrustedWebUtils.java
new file mode 100644
index 0000000..e9a2233
--- /dev/null
+++ b/customtabs/src/main/java/android/support/customtabs/TrustedWebUtils.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.customtabs;
+
+import android.content.Context;
+import android.net.Uri;
+import android.os.Bundle;
+import android.support.annotation.NonNull;
+import android.support.v4.app.BundleCompat;
+
+/**
+ * Class for utilities and convenience calls for opening a qualifying web page as a
+ * Trusted Web Activity.
+ *
+ * Trusted Web Activity is a fullscreen UI with no visible browser controls that hosts web pages
+ * meeting certain criteria. The full list of qualifications is at the implementing browser's
+ * discretion, but minimum recommended set is for the web page :
+ *  <ul>
+ *      <li>To have declared delegate_permission/common.handle_all_urls relationship with the
+ *      launching client application ensuring 1:1 trust between the Android native and web
+ *      components. See https://developers.google.com/digital-asset-links/ for details.</li>
+ *      <li>To work as a reliable, fast and engaging standalone component within the launching app's
+ *      flow.</li>
+ *      <li>To be accessible and operable even when offline.</li>
+ *  </ul>
+ *
+ *  Fallback behaviors may also differ with implementation. Possibilities are launching the page in
+ *  a custom tab, or showing it in browser UI. Browsers are encouraged to use
+ *  {@link CustomTabsCallback#onRelationshipValidationResult(int, Uri, boolean, Bundle)}
+ *  for sending details of the verification results.
+ */
+public class TrustedWebUtils {
+
+    /**
+     * Boolean extra that triggers a {@link CustomTabsIntent} launch to be in a fullscreen UI with
+     * no browser controls.
+     *
+     * @see TrustedWebUtils#launchAsTrustedWebActivity(Context, CustomTabsIntent, Uri).
+     */
+    public static final String EXTRA_LAUNCH_AS_TRUSTED_WEB_ACTIVITY =
+            "android.support.customtabs.extra.LAUNCH_AS_TRUSTED_WEB_ACTIVITY";
+
+    private TrustedWebUtils() {}
+
+    /**
+     * Launch the given {@link CustomTabsIntent} as a Trusted Web Activity. The given
+     * {@link CustomTabsIntent} should have a valid {@link CustomTabsSession} associated with it
+     * during construction. Once the Trusted Web Activity is launched, browser side implementations
+     * may have their own fallback behavior (e.g. Showing the page in a custom tab UI with toolbar)
+     * based on qualifications listed above or more.
+     *
+     * @param context {@link Context} to use while launching the {@link CustomTabsIntent}.
+     * @param customTabsIntent The {@link CustomTabsIntent} to use for launching the
+     *                         Trusted Web Activity. Note that all customizations in the given
+     *                         associated with browser toolbar controls will be ignored.
+     * @param uri The web page to launch as Trusted Web Activity.
+     */
+    public static void launchAsTrustedWebActivity(@NonNull Context context,
+            @NonNull CustomTabsIntent customTabsIntent, @NonNull Uri uri) {
+        if (BundleCompat.getBinder(
+                customTabsIntent.intent.getExtras(), CustomTabsIntent.EXTRA_SESSION) == null) {
+            throw new IllegalArgumentException(
+                    "Given CustomTabsIntent should be associated with a valid CustomTabsSession");
+        }
+        customTabsIntent.intent.putExtra(EXTRA_LAUNCH_AS_TRUSTED_WEB_ACTIVITY, true);
+        customTabsIntent.launchUrl(context, uri);
+    }
+}
diff --git a/customtabs/tests/src/android/support/customtabs/TrustedWebUtilsTest.java b/customtabs/tests/src/android/support/customtabs/TrustedWebUtilsTest.java
new file mode 100644
index 0000000..a9a5abc
--- /dev/null
+++ b/customtabs/tests/src/android/support/customtabs/TrustedWebUtilsTest.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.customtabs;
+
+import static junit.framework.Assert.assertEquals;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import android.content.ActivityNotFoundException;
+import android.content.Intent;
+import android.net.Uri;
+import android.support.test.filters.SmallTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.v4.app.BundleCompat;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Tests for TrustedWebUtils.
+ */
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class TrustedWebUtilsTest {
+    @Rule
+    public final ActivityTestRule<TestActivity> mActivityTestRule;
+
+    public TrustedWebUtilsTest() {
+        mActivityTestRule = new ActivityTestRule<TestActivity>(TestActivity.class);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testTrustedWebIntentRequiresValidSession() {
+        CustomTabsIntent customTabsIntent = new CustomTabsIntent.Builder().build();
+        TrustedWebUtils.launchAsTrustedWebActivity(
+                mActivityTestRule.getActivity(), customTabsIntent, Uri.EMPTY);
+    }
+
+    @Test(expected = ActivityNotFoundException.class)
+    public void testTrustedWebIntentContainsRequiredExtra() {
+        CustomTabsSession mockSession = CustomTabsSession.createMockSessionForTesting(
+                mActivityTestRule.getActivity().getComponentName());
+        CustomTabsIntent customTabsIntent = new CustomTabsIntent.Builder(mockSession).build();
+        TrustedWebUtils.launchAsTrustedWebActivity(
+                mActivityTestRule.getActivity(), customTabsIntent, Uri.EMPTY);
+        assertNotNull(BundleCompat.getBinder(
+                customTabsIntent.intent.getExtras(), CustomTabsIntent.EXTRA_SESSION));
+        assertEquals(customTabsIntent.intent.getAction(), Intent.ACTION_VIEW);
+        assertTrue(customTabsIntent.intent.hasExtra(
+                TrustedWebUtils.EXTRA_LAUNCH_AS_TRUSTED_WEB_ACTIVITY));
+    }
+}
diff --git a/dynamic-animation/Android.mk b/dynamic-animation/Android.mk
index 1b33094..11aa484 100644
--- a/dynamic-animation/Android.mk
+++ b/dynamic-animation/Android.mk
@@ -18,7 +18,7 @@
 LOCAL_USE_AAPT2 := true
 LOCAL_MODULE := android-support-dynamic-animation
 LOCAL_SDK_VERSION := $(SUPPORT_CURRENT_SDK_VERSION)
-LOCAL_SRC_FILES := $(call all-java-files-under,src)
+LOCAL_SRC_FILES := $(call all-java-files-under,src/main/java)
 LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
 LOCAL_SHARED_ANDROID_LIBRARIES := \
     android-support-compat \
diff --git a/dynamic-animation/build.gradle b/dynamic-animation/build.gradle
index b1557e8..220758d 100644
--- a/dynamic-animation/build.gradle
+++ b/dynamic-animation/build.gradle
@@ -13,11 +13,6 @@
     defaultConfig {
         minSdkVersion 14
     }
-
-    sourceSets {
-        main.java.srcDir 'src'
-        main.res.srcDirs 'res', 'res-public'
-    }
 }
 
 supportLibrary {
diff --git a/dynamic-animation/src/android/support/animation/AnimationHandler.java b/dynamic-animation/src/main/java/android/support/animation/AnimationHandler.java
similarity index 100%
rename from dynamic-animation/src/android/support/animation/AnimationHandler.java
rename to dynamic-animation/src/main/java/android/support/animation/AnimationHandler.java
diff --git a/dynamic-animation/src/android/support/animation/DynamicAnimation.java b/dynamic-animation/src/main/java/android/support/animation/DynamicAnimation.java
similarity index 100%
rename from dynamic-animation/src/android/support/animation/DynamicAnimation.java
rename to dynamic-animation/src/main/java/android/support/animation/DynamicAnimation.java
diff --git a/dynamic-animation/src/android/support/animation/FlingAnimation.java b/dynamic-animation/src/main/java/android/support/animation/FlingAnimation.java
similarity index 100%
rename from dynamic-animation/src/android/support/animation/FlingAnimation.java
rename to dynamic-animation/src/main/java/android/support/animation/FlingAnimation.java
diff --git a/dynamic-animation/src/android/support/animation/FloatPropertyCompat.java b/dynamic-animation/src/main/java/android/support/animation/FloatPropertyCompat.java
similarity index 100%
rename from dynamic-animation/src/android/support/animation/FloatPropertyCompat.java
rename to dynamic-animation/src/main/java/android/support/animation/FloatPropertyCompat.java
diff --git a/dynamic-animation/src/android/support/animation/FloatValueHolder.java b/dynamic-animation/src/main/java/android/support/animation/FloatValueHolder.java
similarity index 100%
rename from dynamic-animation/src/android/support/animation/FloatValueHolder.java
rename to dynamic-animation/src/main/java/android/support/animation/FloatValueHolder.java
diff --git a/dynamic-animation/src/android/support/animation/Force.java b/dynamic-animation/src/main/java/android/support/animation/Force.java
similarity index 100%
rename from dynamic-animation/src/android/support/animation/Force.java
rename to dynamic-animation/src/main/java/android/support/animation/Force.java
diff --git a/dynamic-animation/src/android/support/animation/SpringAnimation.java b/dynamic-animation/src/main/java/android/support/animation/SpringAnimation.java
similarity index 100%
rename from dynamic-animation/src/android/support/animation/SpringAnimation.java
rename to dynamic-animation/src/main/java/android/support/animation/SpringAnimation.java
diff --git a/dynamic-animation/src/android/support/animation/SpringForce.java b/dynamic-animation/src/main/java/android/support/animation/SpringForce.java
similarity index 100%
rename from dynamic-animation/src/android/support/animation/SpringForce.java
rename to dynamic-animation/src/main/java/android/support/animation/SpringForce.java
diff --git a/exifinterface/src/android/support/media/ExifInterface.java b/exifinterface/src/android/support/media/ExifInterface.java
index b790cd2..72b61cb 100644
--- a/exifinterface/src/android/support/media/ExifInterface.java
+++ b/exifinterface/src/android/support/media/ExifInterface.java
@@ -22,6 +22,7 @@
 import android.location.Location;
 import android.support.annotation.IntDef;
 import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
 import android.util.Log;
 import android.util.Pair;
 
@@ -3699,7 +3700,7 @@
     /**
      * Reads Exif tags from the specified image file.
      */
-    public ExifInterface(String filename) throws IOException {
+    public ExifInterface(@NonNull String filename) throws IOException {
         if (filename == null) {
             throw new IllegalArgumentException("filename cannot be null");
         }
@@ -3720,7 +3721,7 @@
      * should close the input stream after use. This constructor is not intended to be used with
      * an input stream that performs any networking operations.
      */
-    public ExifInterface(InputStream inputStream) throws IOException {
+    public ExifInterface(@NonNull InputStream inputStream) throws IOException {
         if (inputStream == null) {
             throw new IllegalArgumentException("inputStream cannot be null");
         }
@@ -3739,7 +3740,8 @@
      *
      * @param tag the name of the tag.
      */
-    private ExifAttribute getExifAttribute(String tag) {
+    @Nullable
+    private ExifAttribute getExifAttribute(@NonNull String tag) {
         if (TAG_ISO_SPEED_RATINGS.equals(tag)) {
             if (DEBUG) {
                 Log.d(TAG, "getExifAttribute: Replacing TAG_ISO_SPEED_RATINGS with "
@@ -3764,7 +3766,8 @@
      *
      * @param tag the name of the tag.
      */
-    public String getAttribute(String tag) {
+    @Nullable
+    public String getAttribute(@NonNull String tag) {
         ExifAttribute attribute = getExifAttribute(tag);
         if (attribute != null) {
             if (!sTagSetForCompatibility.contains(tag)) {
@@ -3804,7 +3807,7 @@
      * @param tag the name of the tag.
      * @param defaultValue the value to return if the tag is not available.
      */
-    public int getAttributeInt(String tag, int defaultValue) {
+    public int getAttributeInt(@NonNull String tag, int defaultValue) {
         ExifAttribute exifAttribute = getExifAttribute(tag);
         if (exifAttribute == null) {
             return defaultValue;
@@ -3825,7 +3828,7 @@
      * @param tag the name of the tag.
      * @param defaultValue the value to return if the tag is not available.
      */
-    public double getAttributeDouble(String tag, double defaultValue) {
+    public double getAttributeDouble(@NonNull String tag, double defaultValue) {
         ExifAttribute exifAttribute = getExifAttribute(tag);
         if (exifAttribute == null) {
             return defaultValue;
@@ -3844,7 +3847,7 @@
      * @param tag the name of the tag.
      * @param value the value of the tag.
      */
-    public void setAttribute(String tag, String value) {
+    public void setAttribute(@NonNull String tag, @Nullable String value) {
         if (TAG_ISO_SPEED_RATINGS.equals(tag)) {
             if (DEBUG) {
                 Log.d(TAG, "setAttribute: Replacing TAG_ISO_SPEED_RATINGS with "
@@ -4320,6 +4323,7 @@
      * The returned data can be decoded using
      * {@link android.graphics.BitmapFactory#decodeByteArray(byte[],int,int)}
      */
+    @Nullable
     public byte[] getThumbnail() {
         if (mThumbnailCompression == DATA_JPEG || mThumbnailCompression == DATA_JPEG_COMPRESSED) {
             return getThumbnailBytes();
@@ -4331,6 +4335,7 @@
      * Returns the thumbnail bytes inside the image file, regardless of the compression type of the
      * thumbnail image.
      */
+    @Nullable
     public byte[] getThumbnailBytes() {
         if (!mHasThumbnail) {
             return null;
@@ -4379,6 +4384,7 @@
      * Creates and returns a Bitmap object of the thumbnail image based on the byte array and the
      * thumbnail compression value, or {@code null} if the compression type is unsupported.
      */
+    @Nullable
     public Bitmap getThumbnailBitmap() {
         if (!mHasThumbnail) {
             return null;
@@ -4425,6 +4431,7 @@
      * @return two-element array, the offset in the first value, and length in
      *         the second, or {@code null} if no thumbnail was found.
      */
+    @Nullable
     public long[] getThumbnailRange() {
         if (!mHasThumbnail) {
             return null;
@@ -4462,6 +4469,7 @@
      * array where the first element is the latitude and the second element is the longitude.
      * Otherwise, it returns null.
      */
+    @Nullable
     public double[] getLatLong() {
         String latValue = getAttribute(TAG_GPS_LATITUDE);
         String latRef = getAttribute(TAG_GPS_LATITUDE_REF);
diff --git a/fragment/Android.mk b/fragment/Android.mk
index cc1b5f8..efac954 100644
--- a/fragment/Android.mk
+++ b/fragment/Android.mk
@@ -30,7 +30,7 @@
 LOCAL_MODULE := android-support-fragment
 LOCAL_SDK_VERSION := $(SUPPORT_CURRENT_SDK_VERSION)
 LOCAL_SRC_FILES := \
-    $(call all-java-files-under, java)
+    $(call all-java-files-under, src/main/java)
 LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
 LOCAL_SHARED_ANDROID_LIBRARIES := \
     android-support-compat \
diff --git a/fragment/build.gradle b/fragment/build.gradle
index 954cdd8..3a86f38 100644
--- a/fragment/build.gradle
+++ b/fragment/build.gradle
@@ -16,10 +16,6 @@
     defaultConfig {
         minSdkVersion 14
     }
-
-    sourceSets {
-        main.java.srcDirs = ['java']
-    }
 }
 
 supportLibrary {
diff --git a/fragment/java/android/support/v4/app/BackStackRecord.java b/fragment/src/main/java/android/support/v4/app/BackStackRecord.java
similarity index 100%
rename from fragment/java/android/support/v4/app/BackStackRecord.java
rename to fragment/src/main/java/android/support/v4/app/BackStackRecord.java
diff --git a/fragment/java/android/support/v4/app/BaseFragmentActivityApi14.java b/fragment/src/main/java/android/support/v4/app/BaseFragmentActivityApi14.java
similarity index 100%
rename from fragment/java/android/support/v4/app/BaseFragmentActivityApi14.java
rename to fragment/src/main/java/android/support/v4/app/BaseFragmentActivityApi14.java
diff --git a/fragment/java/android/support/v4/app/BaseFragmentActivityApi16.java b/fragment/src/main/java/android/support/v4/app/BaseFragmentActivityApi16.java
similarity index 100%
rename from fragment/java/android/support/v4/app/BaseFragmentActivityApi16.java
rename to fragment/src/main/java/android/support/v4/app/BaseFragmentActivityApi16.java
diff --git a/fragment/java/android/support/v4/app/DialogFragment.java b/fragment/src/main/java/android/support/v4/app/DialogFragment.java
similarity index 100%
rename from fragment/java/android/support/v4/app/DialogFragment.java
rename to fragment/src/main/java/android/support/v4/app/DialogFragment.java
diff --git a/fragment/java/android/support/v4/app/Fragment.java b/fragment/src/main/java/android/support/v4/app/Fragment.java
similarity index 98%
rename from fragment/java/android/support/v4/app/Fragment.java
rename to fragment/src/main/java/android/support/v4/app/Fragment.java
index 0eb7083..2415e79 100644
--- a/fragment/java/android/support/v4/app/Fragment.java
+++ b/fragment/src/main/java/android/support/v4/app/Fragment.java
@@ -463,6 +463,7 @@
     /**
      * Get the tag name of the fragment, if specified.
      */
+    @Nullable
     final public String getTag() {
         return mTag;
     }
@@ -474,7 +475,7 @@
      * <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) {
+    public void setArguments(@Nullable Bundle args) {
         if (mIndex >= 0 && isStateSaved()) {
             throw new IllegalStateException("Fragment already active and state has been saved");
         }
@@ -485,6 +486,7 @@
      * Return the arguments supplied when the fragment was instantiated,
      * if any.
      */
+    @Nullable
     final public Bundle getArguments() {
         return mArguments;
     }
@@ -512,7 +514,7 @@
      *
      * @param state The state the fragment should be restored from.
      */
-    public void setInitialSavedState(SavedState state) {
+    public void setInitialSavedState(@Nullable SavedState state) {
         if (mIndex >= 0) {
             throw new IllegalStateException("Fragment already active");
         }
@@ -532,7 +534,7 @@
      * are going to call back with {@link #onActivityResult(int, int, Intent)}.
      */
     @SuppressWarnings("ReferenceEquality")
-    public void setTargetFragment(Fragment fragment, int requestCode) {
+    public void setTargetFragment(@Nullable 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
@@ -558,6 +560,7 @@
     /**
      * Return the target fragment set by {@link #setTargetFragment}.
      */
+    @Nullable
     final public Fragment getTargetFragment() {
         return mTarget;
     }
@@ -572,6 +575,7 @@
     /**
      * Return the {@link Context} this fragment is currently associated with.
      */
+    @Nullable
     public Context getContext() {
         return mHost == null ? null : mHost.getContext();
     }
@@ -581,6 +585,7 @@
      * May return {@code null} if the fragment is associated with a {@link Context}
      * instead.
      */
+    @Nullable
     final public FragmentActivity getActivity() {
         return mHost == null ? null : (FragmentActivity) mHost.getActivity();
     }
@@ -589,6 +594,7 @@
      * Return the host object of this fragment. May return {@code null} if the fragment
      * isn't currently being hosted.
      */
+    @Nullable
     final public Object getHost() {
         return mHost == null ? null : mHost.onGetHost();
     }
@@ -596,6 +602,7 @@
     /**
      * Return <code>getActivity().getResources()</code>.
      */
+    @NonNull
     final public Resources getResources() {
         if (mHost == null) {
             throw new IllegalStateException("Fragment " + this + " not attached to Activity");
@@ -609,6 +616,7 @@
      *
      * @param resId Resource id for the CharSequence text
      */
+    @NonNull
     public final CharSequence getText(@StringRes int resId) {
         return getResources().getText(resId);
     }
@@ -619,6 +627,7 @@
      *
      * @param resId Resource id for the string
      */
+    @NonNull
     public final String getString(@StringRes int resId) {
         return getResources().getString(resId);
     }
@@ -631,7 +640,7 @@
      * @param resId Resource id for the format string
      * @param formatArgs The format arguments that will be used for substitution.
      */
-
+    @NonNull
     public final String getString(@StringRes int resId, Object... formatArgs) {
         return getResources().getString(resId, formatArgs);
     }
@@ -646,6 +655,7 @@
      * <p>If this Fragment is a child of another Fragment, the FragmentManager
      * returned here will be the parent's {@link #getChildFragmentManager()}.
      */
+    @Nullable
     final public FragmentManager getFragmentManager() {
         return mFragmentManager;
     }
@@ -654,6 +664,7 @@
      * Return a private FragmentManager for placing and managing Fragments
      * inside of this Fragment.
      */
+    @NonNull
     final public FragmentManager getChildFragmentManager() {
         if (mChildFragmentManager == null) {
             instantiateChildFragmentManager();
@@ -674,6 +685,7 @@
      * Return this fragment's child FragmentManager one has been previously created,
      * otherwise null.
      */
+    @Nullable
     FragmentManager peekChildFragmentManager() {
         return mChildFragmentManager;
     }
@@ -682,6 +694,7 @@
      * Returns the parent Fragment containing this Fragment.  If this Fragment
      * is attached directly to an Activity, returns null.
      */
+    @Nullable
     final public Fragment getParentFragment() {
         return mParentFragment;
     }
@@ -1082,7 +1095,8 @@
      * a previous saved state, this is the state.
      * @return The LayoutInflater used to inflate Views of this Fragment.
      */
-    public LayoutInflater onGetLayoutInflater(Bundle savedInstanceState) {
+    @NonNull
+    public LayoutInflater onGetLayoutInflater(@Nullable Bundle savedInstanceState) {
         // TODO: move the implementation in getLayoutInflater to here
         return getLayoutInflater(savedInstanceState);
     }
@@ -1113,7 +1127,8 @@
      * a previous saved state, this is the state.
      * @return The LayoutInflater used to inflate Views of this Fragment.
      */
-    LayoutInflater performGetLayoutInflater(Bundle savedInstanceState) {
+    @NonNull
+    LayoutInflater performGetLayoutInflater(@Nullable Bundle savedInstanceState) {
         LayoutInflater layoutInflater = onGetLayoutInflater(savedInstanceState);
         mLayoutInflater = layoutInflater;
         return mLayoutInflater;
@@ -1129,8 +1144,9 @@
      * {@link #getLayoutInflater()} instead of this method.
      */
     @Deprecated
+    @NonNull
     @RestrictTo(LIBRARY_GROUP)
-    public LayoutInflater getLayoutInflater(Bundle savedFragmentState) {
+    public LayoutInflater getLayoutInflater(@Nullable Bundle savedFragmentState) {
         if (mHost == null) {
             throw new IllegalStateException("onGetLayoutInflater() cannot be executed until the "
                     + "Fragment is attached to the FragmentManager.");
@@ -1356,7 +1372,7 @@
      * @return Return the View for the fragment's UI, or null.
      */
     @Nullable
-    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
+    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
             @Nullable Bundle savedInstanceState) {
         return null;
     }
@@ -1768,7 +1784,7 @@
      *
      * @param transition The Transition to use to move Views into the initial Scene.
      */
-    public void setEnterTransition(Object transition) {
+    public void setEnterTransition(@Nullable Object transition) {
         ensureAnimationInfo().mEnterTransition = transition;
     }
 
@@ -1781,6 +1797,7 @@
      *
      * @return the Transition to use to move Views into the initial Scene.
      */
+    @Nullable
     public Object getEnterTransition() {
         if (mAnimationInfo == null) {
             return null;
@@ -1802,7 +1819,7 @@
      *                   is preparing to close. <code>transition</code> must be an
      *                   android.transition.Transition.
      */
-    public void setReturnTransition(Object transition) {
+    public void setReturnTransition(@Nullable Object transition) {
         ensureAnimationInfo().mReturnTransition = transition;
     }
 
@@ -1818,6 +1835,7 @@
      * @return the Transition to use to move Views out of the Scene when the Fragment
      *         is preparing to close.
      */
+    @Nullable
     public Object getReturnTransition() {
         if (mAnimationInfo == null) {
             return null;
@@ -1839,7 +1857,7 @@
      *                   is being closed not due to popping the back stack. <code>transition</code>
      *                   must be an android.transition.Transition.
      */
-    public void setExitTransition(Object transition) {
+    public void setExitTransition(@Nullable Object transition) {
         ensureAnimationInfo().mExitTransition = transition;
     }
 
@@ -1855,6 +1873,7 @@
      * @return the Transition to use to move Views out of the Scene when the Fragment
      *         is being closed not due to popping the back stack.
      */
+    @Nullable
     public Object getExitTransition() {
         if (mAnimationInfo == null) {
             return null;
@@ -1875,7 +1894,7 @@
      *                   previously-started Activity. <code>transition</code>
      *                   must be an android.transition.Transition.
      */
-    public void setReenterTransition(Object transition) {
+    public void setReenterTransition(@Nullable Object transition) {
         ensureAnimationInfo().mReenterTransition = transition;
     }
 
@@ -1908,7 +1927,7 @@
      * @param transition The Transition to use for shared elements transferred into the content
      *                   Scene.  <code>transition</code> must be an android.transition.Transition.
      */
-    public void setSharedElementEnterTransition(Object transition) {
+    public void setSharedElementEnterTransition(@Nullable Object transition) {
         ensureAnimationInfo().mSharedElementEnterTransition = transition;
     }
 
@@ -1921,6 +1940,7 @@
      * @return The Transition to use for shared elements transferred into the content
      *                   Scene.
      */
+    @Nullable
     public Object getSharedElementEnterTransition() {
         if (mAnimationInfo == null) {
             return null;
@@ -1940,7 +1960,7 @@
      * @param transition The Transition to use for shared elements transferred out of the content
      *                   Scene. <code>transition</code> must be an android.transition.Transition.
      */
-    public void setSharedElementReturnTransition(Object transition) {
+    public void setSharedElementReturnTransition(@Nullable Object transition) {
         ensureAnimationInfo().mSharedElementReturnTransition = transition;
     }
 
@@ -1956,6 +1976,7 @@
      * @return The Transition to use for shared elements transferred out of the content
      *                   Scene.
      */
+    @Nullable
     public Object getSharedElementReturnTransition() {
         if (mAnimationInfo == null) {
             return null;
@@ -2231,8 +2252,8 @@
         mLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_CREATE);
     }
 
-    View performCreateView(LayoutInflater inflater, ViewGroup container,
-            Bundle savedInstanceState) {
+    View performCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
+            @Nullable Bundle savedInstanceState) {
         if (mChildFragmentManager != null) {
             mChildFragmentManager.noteStateNotSaved();
         }
diff --git a/fragment/java/android/support/v4/app/FragmentActivity.java b/fragment/src/main/java/android/support/v4/app/FragmentActivity.java
similarity index 100%
rename from fragment/java/android/support/v4/app/FragmentActivity.java
rename to fragment/src/main/java/android/support/v4/app/FragmentActivity.java
diff --git a/fragment/java/android/support/v4/app/FragmentContainer.java b/fragment/src/main/java/android/support/v4/app/FragmentContainer.java
similarity index 100%
rename from fragment/java/android/support/v4/app/FragmentContainer.java
rename to fragment/src/main/java/android/support/v4/app/FragmentContainer.java
diff --git a/fragment/java/android/support/v4/app/FragmentController.java b/fragment/src/main/java/android/support/v4/app/FragmentController.java
similarity index 100%
rename from fragment/java/android/support/v4/app/FragmentController.java
rename to fragment/src/main/java/android/support/v4/app/FragmentController.java
diff --git a/fragment/java/android/support/v4/app/FragmentHostCallback.java b/fragment/src/main/java/android/support/v4/app/FragmentHostCallback.java
similarity index 98%
rename from fragment/java/android/support/v4/app/FragmentHostCallback.java
rename to fragment/src/main/java/android/support/v4/app/FragmentHostCallback.java
index 7dc9f59..eeae62a 100644
--- a/fragment/java/android/support/v4/app/FragmentHostCallback.java
+++ b/fragment/src/main/java/android/support/v4/app/FragmentHostCallback.java
@@ -94,8 +94,9 @@
      * Return a {@link LayoutInflater}.
      * See {@link Activity#getLayoutInflater()}.
      */
+    @NonNull
     public LayoutInflater onGetLayoutInflater() {
-        return (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+        return LayoutInflater.from(mContext);
     }
 
     /**
diff --git a/fragment/java/android/support/v4/app/FragmentManager.java b/fragment/src/main/java/android/support/v4/app/FragmentManager.java
similarity index 100%
rename from fragment/java/android/support/v4/app/FragmentManager.java
rename to fragment/src/main/java/android/support/v4/app/FragmentManager.java
diff --git a/fragment/java/android/support/v4/app/FragmentManagerNonConfig.java b/fragment/src/main/java/android/support/v4/app/FragmentManagerNonConfig.java
similarity index 100%
rename from fragment/java/android/support/v4/app/FragmentManagerNonConfig.java
rename to fragment/src/main/java/android/support/v4/app/FragmentManagerNonConfig.java
diff --git a/fragment/java/android/support/v4/app/FragmentPagerAdapter.java b/fragment/src/main/java/android/support/v4/app/FragmentPagerAdapter.java
similarity index 100%
rename from fragment/java/android/support/v4/app/FragmentPagerAdapter.java
rename to fragment/src/main/java/android/support/v4/app/FragmentPagerAdapter.java
diff --git a/fragment/java/android/support/v4/app/FragmentState.java b/fragment/src/main/java/android/support/v4/app/FragmentState.java
similarity index 100%
rename from fragment/java/android/support/v4/app/FragmentState.java
rename to fragment/src/main/java/android/support/v4/app/FragmentState.java
diff --git a/fragment/java/android/support/v4/app/FragmentStatePagerAdapter.java b/fragment/src/main/java/android/support/v4/app/FragmentStatePagerAdapter.java
similarity index 100%
rename from fragment/java/android/support/v4/app/FragmentStatePagerAdapter.java
rename to fragment/src/main/java/android/support/v4/app/FragmentStatePagerAdapter.java
diff --git a/fragment/java/android/support/v4/app/FragmentTabHost.java b/fragment/src/main/java/android/support/v4/app/FragmentTabHost.java
similarity index 100%
rename from fragment/java/android/support/v4/app/FragmentTabHost.java
rename to fragment/src/main/java/android/support/v4/app/FragmentTabHost.java
diff --git a/fragment/java/android/support/v4/app/FragmentTransaction.java b/fragment/src/main/java/android/support/v4/app/FragmentTransaction.java
similarity index 100%
rename from fragment/java/android/support/v4/app/FragmentTransaction.java
rename to fragment/src/main/java/android/support/v4/app/FragmentTransaction.java
diff --git a/fragment/java/android/support/v4/app/FragmentTransition.java b/fragment/src/main/java/android/support/v4/app/FragmentTransition.java
similarity index 100%
rename from fragment/java/android/support/v4/app/FragmentTransition.java
rename to fragment/src/main/java/android/support/v4/app/FragmentTransition.java
diff --git a/fragment/java/android/support/v4/app/FragmentTransitionCompat21.java b/fragment/src/main/java/android/support/v4/app/FragmentTransitionCompat21.java
similarity index 100%
rename from fragment/java/android/support/v4/app/FragmentTransitionCompat21.java
rename to fragment/src/main/java/android/support/v4/app/FragmentTransitionCompat21.java
diff --git a/fragment/java/android/support/v4/app/FragmentTransitionImpl.java b/fragment/src/main/java/android/support/v4/app/FragmentTransitionImpl.java
similarity index 100%
rename from fragment/java/android/support/v4/app/FragmentTransitionImpl.java
rename to fragment/src/main/java/android/support/v4/app/FragmentTransitionImpl.java
diff --git a/fragment/java/android/support/v4/app/ListFragment.java b/fragment/src/main/java/android/support/v4/app/ListFragment.java
similarity index 100%
rename from fragment/java/android/support/v4/app/ListFragment.java
rename to fragment/src/main/java/android/support/v4/app/ListFragment.java
diff --git a/fragment/java/android/support/v4/app/LoaderManager.java b/fragment/src/main/java/android/support/v4/app/LoaderManager.java
similarity index 100%
rename from fragment/java/android/support/v4/app/LoaderManager.java
rename to fragment/src/main/java/android/support/v4/app/LoaderManager.java
diff --git a/fragment/java/android/support/v4/app/OneShotPreDrawListener.java b/fragment/src/main/java/android/support/v4/app/OneShotPreDrawListener.java
similarity index 100%
rename from fragment/java/android/support/v4/app/OneShotPreDrawListener.java
rename to fragment/src/main/java/android/support/v4/app/OneShotPreDrawListener.java
diff --git a/fragment/java/android/support/v4/app/SuperNotCalledException.java b/fragment/src/main/java/android/support/v4/app/SuperNotCalledException.java
similarity index 100%
rename from fragment/java/android/support/v4/app/SuperNotCalledException.java
rename to fragment/src/main/java/android/support/v4/app/SuperNotCalledException.java
diff --git a/fragment/java/android/support/v4/app/package.html b/fragment/src/main/java/android/support/v4/app/package.html
similarity index 100%
rename from fragment/java/android/support/v4/app/package.html
rename to fragment/src/main/java/android/support/v4/app/package.html
diff --git a/graphics/drawable/Android.mk b/graphics/drawable/Android.mk
index b06fd76..b1f0b38 100644
--- a/graphics/drawable/Android.mk
+++ b/graphics/drawable/Android.mk
@@ -23,7 +23,7 @@
 LOCAL_USE_AAPT2 := true
 LOCAL_MODULE := android-support-vectordrawable
 LOCAL_SDK_VERSION := $(SUPPORT_CURRENT_SDK_VERSION)
-LOCAL_SRC_FILES := $(call all-java-files-under, static/src)
+LOCAL_SRC_FILES := $(call all-java-files-under, static/src/main/java)
 LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/static/res
 LOCAL_MANIFEST_FILE := static/AndroidManifest.xml
 LOCAL_SHARED_ANDROID_LIBRARIES := \
@@ -42,7 +42,7 @@
 LOCAL_USE_AAPT2 := true
 LOCAL_MODULE := android-support-animatedvectordrawable
 LOCAL_SDK_VERSION := $(SUPPORT_CURRENT_SDK_VERSION)
-LOCAL_SRC_FILES := $(call all-java-files-under, animated/src)
+LOCAL_SRC_FILES := $(call all-java-files-under, animated/src/main/java)
 LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/animated/res
 LOCAL_MANIFEST_FILE := animated/AndroidManifest.xml
 LOCAL_SHARED_ANDROID_LIBRARIES := \
diff --git a/graphics/drawable/AndroidManifest.xml b/graphics/drawable/AndroidManifest.xml
deleted file mode 100644
index 83124c7..0000000
--- a/graphics/drawable/AndroidManifest.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="android.support.graphics.drawable">
-    <application />
-</manifest>
diff --git a/graphics/drawable/animated/build.gradle b/graphics/drawable/animated/build.gradle
index 29aeb3b..6036284 100644
--- a/graphics/drawable/animated/build.gradle
+++ b/graphics/drawable/animated/build.gradle
@@ -15,10 +15,6 @@
         generatedDensities = []
     }
 
-    sourceSets {
-        main.java.srcDir 'src'
-    }
-
     aaptOptions {
         additionalParameters "--no-version-vectors"
     }
diff --git a/graphics/drawable/animated/lint-baseline.xml b/graphics/drawable/animated/lint-baseline.xml
index eab8464..9fbd83c 100644
--- a/graphics/drawable/animated/lint-baseline.xml
+++ b/graphics/drawable/animated/lint-baseline.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<issues format="4" by="lint 3.0.0-alpha9">
+<issues format="4" by="lint 3.0.0-beta6">
 
     <issue
         id="ResourceType"
@@ -7,7 +7,7 @@
         errorLine1="            parser = resources.getAnimation(id);"
         errorLine2="                                            ~~">
         <location
-            file="src/android/support/graphics/drawable/AnimatorInflaterCompat.java"
+            file="src/main/java/android/support/graphics/drawable/AnimatorInflaterCompat.java"
             line="130"
             column="45"/>
     </issue>
diff --git a/graphics/drawable/animated/src/android/support/graphics/drawable/Animatable2Compat.java b/graphics/drawable/animated/src/main/java/android/support/graphics/drawable/Animatable2Compat.java
similarity index 100%
rename from graphics/drawable/animated/src/android/support/graphics/drawable/Animatable2Compat.java
rename to graphics/drawable/animated/src/main/java/android/support/graphics/drawable/Animatable2Compat.java
diff --git a/graphics/drawable/animated/src/android/support/graphics/drawable/AnimatedVectorDrawableCompat.java b/graphics/drawable/animated/src/main/java/android/support/graphics/drawable/AnimatedVectorDrawableCompat.java
similarity index 100%
rename from graphics/drawable/animated/src/android/support/graphics/drawable/AnimatedVectorDrawableCompat.java
rename to graphics/drawable/animated/src/main/java/android/support/graphics/drawable/AnimatedVectorDrawableCompat.java
diff --git a/graphics/drawable/animated/src/android/support/graphics/drawable/AnimationUtilsCompat.java b/graphics/drawable/animated/src/main/java/android/support/graphics/drawable/AnimationUtilsCompat.java
similarity index 100%
rename from graphics/drawable/animated/src/android/support/graphics/drawable/AnimationUtilsCompat.java
rename to graphics/drawable/animated/src/main/java/android/support/graphics/drawable/AnimationUtilsCompat.java
diff --git a/graphics/drawable/animated/src/android/support/graphics/drawable/AnimatorInflaterCompat.java b/graphics/drawable/animated/src/main/java/android/support/graphics/drawable/AnimatorInflaterCompat.java
similarity index 100%
rename from graphics/drawable/animated/src/android/support/graphics/drawable/AnimatorInflaterCompat.java
rename to graphics/drawable/animated/src/main/java/android/support/graphics/drawable/AnimatorInflaterCompat.java
diff --git a/graphics/drawable/animated/src/android/support/graphics/drawable/ArgbEvaluator.java b/graphics/drawable/animated/src/main/java/android/support/graphics/drawable/ArgbEvaluator.java
similarity index 100%
rename from graphics/drawable/animated/src/android/support/graphics/drawable/ArgbEvaluator.java
rename to graphics/drawable/animated/src/main/java/android/support/graphics/drawable/ArgbEvaluator.java
diff --git a/graphics/drawable/animated/src/android/support/graphics/drawable/PathInterpolatorCompat.java b/graphics/drawable/animated/src/main/java/android/support/graphics/drawable/PathInterpolatorCompat.java
similarity index 100%
rename from graphics/drawable/animated/src/android/support/graphics/drawable/PathInterpolatorCompat.java
rename to graphics/drawable/animated/src/main/java/android/support/graphics/drawable/PathInterpolatorCompat.java
diff --git a/graphics/drawable/static/build.gradle b/graphics/drawable/static/build.gradle
index ee24ad5..949ba89 100644
--- a/graphics/drawable/static/build.gradle
+++ b/graphics/drawable/static/build.gradle
@@ -14,10 +14,6 @@
         generatedDensities = []
     }
 
-    sourceSets {
-        main.java.srcDir 'src'
-    }
-
     aaptOptions {
         additionalParameters "--no-version-vectors"
     }
diff --git a/graphics/drawable/static/src/android/support/graphics/drawable/AndroidResources.java b/graphics/drawable/static/src/main/java/android/support/graphics/drawable/AndroidResources.java
similarity index 100%
rename from graphics/drawable/static/src/android/support/graphics/drawable/AndroidResources.java
rename to graphics/drawable/static/src/main/java/android/support/graphics/drawable/AndroidResources.java
diff --git a/graphics/drawable/static/src/android/support/graphics/drawable/VectorDrawableCommon.java b/graphics/drawable/static/src/main/java/android/support/graphics/drawable/VectorDrawableCommon.java
similarity index 100%
rename from graphics/drawable/static/src/android/support/graphics/drawable/VectorDrawableCommon.java
rename to graphics/drawable/static/src/main/java/android/support/graphics/drawable/VectorDrawableCommon.java
diff --git a/graphics/drawable/static/src/android/support/graphics/drawable/VectorDrawableCompat.java b/graphics/drawable/static/src/main/java/android/support/graphics/drawable/VectorDrawableCompat.java
similarity index 100%
rename from graphics/drawable/static/src/android/support/graphics/drawable/VectorDrawableCompat.java
rename to graphics/drawable/static/src/main/java/android/support/graphics/drawable/VectorDrawableCompat.java
diff --git a/lifecycle/common/src/main/java/android/arch/lifecycle/Lifecycling.java b/lifecycle/common/src/main/java/android/arch/lifecycle/Lifecycling.java
index ed9aa3f..63d8a0e 100644
--- a/lifecycle/common/src/main/java/android/arch/lifecycle/Lifecycling.java
+++ b/lifecycle/common/src/main/java/android/arch/lifecycle/Lifecycling.java
@@ -30,7 +30,7 @@
  * @hide
  */
 @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
-class Lifecycling {
+public class Lifecycling {
     private static Constructor<? extends GenericLifecycleObserver> sREFLECTIVE;
 
     static {
@@ -152,7 +152,10 @@
         return klass != null && LifecycleObserver.class.isAssignableFrom(klass);
     }
 
-    static String getAdapterName(String className) {
+    /**
+     * Create a name for an adapter class.
+     */
+    public static String getAdapterName(String className) {
         return className.replace(".", "_") + "_LifecycleAdapter";
     }
 }
diff --git a/lifecycle/compiler/build.gradle b/lifecycle/compiler/build.gradle
index 44bf15d..e784f80 100644
--- a/lifecycle/compiler/build.gradle
+++ b/lifecycle/compiler/build.gradle
@@ -26,6 +26,19 @@
 version = LibraryVersions.LIFECYCLES_EXT.toString()
 createKotlinCheckstyle(project)
 
+// we actually need to compile :lifecycle:common, but compileJava is easier
+task compileTestLibrarySource(type: JavaCompile, dependsOn: compileJava) {
+    source "src/tests/test-data/lib/src"
+    classpath = project.compileJava.classpath
+    destinationDir = new File(project.buildDir, 'test-data/lib/classes')
+}
+
+task jarTestLibrarySource(type: Jar, dependsOn: compileTestLibrarySource) {
+    from compileTestLibrarySource.destinationDir
+    archiveName = "test-library.jar"
+    destinationDir = file("src/tests/test-data/lib/")
+}
+
 supportLibrary {
     name 'Android Lifecycles Compiler'
     publish true
diff --git a/lifecycle/compiler/src/main/kotlin/android/arch/lifecycle/ErrorMessages.kt b/lifecycle/compiler/src/main/kotlin/android/arch/lifecycle/ErrorMessages.kt
index 8dac863..10180a6 100644
--- a/lifecycle/compiler/src/main/kotlin/android/arch/lifecycle/ErrorMessages.kt
+++ b/lifecycle/compiler/src/main/kotlin/android/arch/lifecycle/ErrorMessages.kt
@@ -33,5 +33,4 @@
     const val INVALID_ENCLOSING_ELEMENT =
             "Parent of OnLifecycleEvent should be a class or interface"
     const val INVALID_ANNOTATED_ELEMENT = "OnLifecycleEvent can only be added to methods"
-
 }
diff --git a/lifecycle/compiler/src/main/kotlin/android/arch/lifecycle/input_collector.kt b/lifecycle/compiler/src/main/kotlin/android/arch/lifecycle/input_collector.kt
index 5183df5..43368936 100644
--- a/lifecycle/compiler/src/main/kotlin/android/arch/lifecycle/input_collector.kt
+++ b/lifecycle/compiler/src/main/kotlin/android/arch/lifecycle/input_collector.kt
@@ -18,6 +18,7 @@
 
 import android.arch.lifecycle.model.EventMethod
 import android.arch.lifecycle.model.LifecycleObserverInfo
+import android.arch.lifecycle.model.getAdapterName
 import com.google.auto.common.MoreElements
 import com.google.auto.common.MoreTypes
 import javax.annotation.processing.ProcessingEnvironment
@@ -28,32 +29,75 @@
 import javax.lang.model.element.Modifier
 import javax.lang.model.element.TypeElement
 import javax.lang.model.element.VariableElement
+import javax.lang.model.type.TypeMirror
+import javax.lang.model.util.ElementFilter
+import javax.lang.model.util.Elements
+import javax.lang.model.util.Types
 import javax.tools.Diagnostic
 
 fun collectAndVerifyInput(processingEnv: ProcessingEnvironment,
                           roundEnv: RoundEnvironment): Map<TypeElement, LifecycleObserverInfo> {
     val validator = Validator(processingEnv)
-
-    return roundEnv.getElementsAnnotatedWith(OnLifecycleEvent::class.java).map { elem ->
+    val worldCollector = ObserversCollector(processingEnv)
+    roundEnv.getElementsAnnotatedWith(OnLifecycleEvent::class.java).forEach { elem ->
         if (elem.kind != ElementKind.METHOD) {
             validator.printErrorMessage(ErrorMessages.INVALID_ANNOTATED_ELEMENT, elem)
-            null
         } else {
             val enclosingElement = elem.enclosingElement
-            val onState = elem.getAnnotation(OnLifecycleEvent::class.java)
-            val method = MoreElements.asExecutable(elem)
-            if (validator.validateClass(enclosingElement)
-                    && validator.validateMethod(method, onState.value)) {
-                EventMethod(method, onState, MoreElements.asType(enclosingElement))
-            } else {
-                null
+            if (validator.validateClass(enclosingElement)) {
+                worldCollector.collect(MoreElements.asType(enclosingElement))
             }
         }
     }
-            .filterNotNull()
-            .groupBy { MoreElements.asType(it.method.enclosingElement) }
-            .mapValues { entry -> LifecycleObserverInfo(entry.key, entry.value) }
+    return worldCollector.observers
+}
 
+class ObserversCollector(processingEnv: ProcessingEnvironment) {
+    val typeUtils: Types = processingEnv.typeUtils
+    val elementUtils: Elements = processingEnv.elementUtils
+    val lifecycleObserverTypeMirror: TypeMirror =
+            elementUtils.getTypeElement(LifecycleObserver::class.java.canonicalName).asType()
+    val validator = Validator(processingEnv)
+    val observers: MutableMap<TypeElement, LifecycleObserverInfo> = mutableMapOf()
+
+    fun collect(type: TypeElement): LifecycleObserverInfo? {
+        if (type in observers) {
+            return observers[type]
+        }
+        val parents = (listOf(type.superclass) + type.interfaces)
+                .filter { typeUtils.isAssignable(it, lifecycleObserverTypeMirror) }
+                .filterNot { typeUtils.isSameType(it, lifecycleObserverTypeMirror) }
+                .map { collect(MoreTypes.asTypeElement(it)) }
+                .filterNotNull()
+        val info = createObserverInfo(type, parents)
+        if (info != null) {
+            observers[type] = info
+        }
+        return info
+    }
+
+    private fun hasAdapter(type: TypeElement): Boolean {
+        val packageName = if (type.getPackageQName().isEmpty()) "" else "${type.getPackageQName()}."
+        return elementUtils.getTypeElement(packageName + getAdapterName(type)) != null
+    }
+
+    private fun createObserverInfo(typeElement: TypeElement,
+                                   parents: List<LifecycleObserverInfo>): LifecycleObserverInfo? {
+        if (!validator.validateClass(typeElement)) {
+            return null
+        }
+        val methods = ElementFilter.methodsIn(typeElement.enclosedElements).filter { executable ->
+            MoreElements.isAnnotationPresent(executable, OnLifecycleEvent::class.java)
+        }.map { executable ->
+            val onState = executable.getAnnotation(OnLifecycleEvent::class.java)
+            if (validator.validateMethod(executable, onState.value)) {
+                EventMethod(executable, onState, typeElement)
+            } else {
+                null
+            }
+        }.filterNotNull()
+        return LifecycleObserverInfo(typeElement, methods, hasAdapter(typeElement), parents)
+    }
 }
 
 class Validator(val processingEnv: ProcessingEnvironment) {
@@ -100,7 +144,7 @@
     }
 
     fun validateClass(classElement: Element): Boolean {
-        if (classElement.kind != ElementKind.CLASS && classElement.kind != ElementKind.INTERFACE) {
+        if (!MoreElements.isType(classElement)) {
             printErrorMessage(ErrorMessages.INVALID_ENCLOSING_ELEMENT, classElement)
             return false
         }
diff --git a/lifecycle/compiler/src/main/kotlin/android/arch/lifecycle/model/AdapterClass.kt b/lifecycle/compiler/src/main/kotlin/android/arch/lifecycle/model/AdapterClass.kt
index 1e76fa8..bd7759a 100644
--- a/lifecycle/compiler/src/main/kotlin/android/arch/lifecycle/model/AdapterClass.kt
+++ b/lifecycle/compiler/src/main/kotlin/android/arch/lifecycle/model/AdapterClass.kt
@@ -16,9 +16,19 @@
 
 package android.arch.lifecycle.model
 
+import android.arch.lifecycle.Lifecycling
+import android.arch.lifecycle.getPackage
 import javax.lang.model.element.ExecutableElement
 import javax.lang.model.element.TypeElement
 
 data class AdapterClass(val type: TypeElement,
                         val calls: List<EventMethodCall>,
-                        val syntheticMethods: Set<ExecutableElement>)
\ No newline at end of file
+                        val syntheticMethods: Set<ExecutableElement>)
+
+fun getAdapterName(type: TypeElement): String {
+    val packageElement = type.getPackage()
+    val qName = type.qualifiedName.toString()
+    val partialName = if (packageElement.isUnnamed) qName else qName.substring(
+            packageElement.qualifiedName.toString().length + 1)
+    return Lifecycling.getAdapterName(partialName)
+}
diff --git a/lifecycle/compiler/src/main/kotlin/android/arch/lifecycle/model/LifecycleObserverInfo.kt b/lifecycle/compiler/src/main/kotlin/android/arch/lifecycle/model/LifecycleObserverInfo.kt
index d8bc364..0693478 100644
--- a/lifecycle/compiler/src/main/kotlin/android/arch/lifecycle/model/LifecycleObserverInfo.kt
+++ b/lifecycle/compiler/src/main/kotlin/android/arch/lifecycle/model/LifecycleObserverInfo.kt
@@ -20,4 +20,6 @@
 
 data class LifecycleObserverInfo(
         val type: TypeElement,
-        val methods: List<EventMethod>)
\ No newline at end of file
+        val methods: List<EventMethod>,
+        val hasAdapter: Boolean,
+        val parents: List<LifecycleObserverInfo> = listOf())
\ No newline at end of file
diff --git a/lifecycle/compiler/src/main/kotlin/android/arch/lifecycle/transformation.kt b/lifecycle/compiler/src/main/kotlin/android/arch/lifecycle/transformation.kt
index 66fabf7..16c3d81 100644
--- a/lifecycle/compiler/src/main/kotlin/android/arch/lifecycle/transformation.kt
+++ b/lifecycle/compiler/src/main/kotlin/android/arch/lifecycle/transformation.kt
@@ -20,39 +20,11 @@
 import android.arch.lifecycle.model.EventMethod
 import android.arch.lifecycle.model.EventMethodCall
 import android.arch.lifecycle.model.LifecycleObserverInfo
-import com.google.auto.common.MoreTypes
 import com.google.common.collect.HashMultimap
-import java.util.LinkedList
 import javax.annotation.processing.ProcessingEnvironment
 import javax.lang.model.element.TypeElement
-import javax.lang.model.type.NoType
-import javax.lang.model.type.TypeMirror
 import javax.tools.Diagnostic
 
-
-private fun superObservers(world: Map<TypeElement, LifecycleObserverInfo>,
-                           observer: LifecycleObserverInfo): List<LifecycleObserverInfo> {
-    val stack = LinkedList<TypeMirror>()
-    stack += observer.type.interfaces.reversed()
-    stack += observer.type.superclass
-    val result = mutableListOf<LifecycleObserverInfo>()
-    while (stack.isNotEmpty()) {
-        val typeMirror = stack.removeLast()
-        if (typeMirror is NoType) {
-            continue
-        }
-        val type = MoreTypes.asTypeElement(typeMirror)
-        val currentObserver = world[type]
-        if (currentObserver != null) {
-            result.add(currentObserver)
-        } else {
-            stack += type.interfaces.reversed()
-            stack += type.superclass
-        }
-    }
-    return result
-}
-
 private fun mergeAndVerifyMethods(processingEnv: ProcessingEnvironment,
                                   type: TypeElement,
                                   classMethods: List<EventMethod>,
@@ -80,26 +52,26 @@
 fun flattenObservers(processingEnv: ProcessingEnvironment,
                      world: Map<TypeElement, LifecycleObserverInfo>): List<LifecycleObserverInfo> {
     val flattened: MutableMap<LifecycleObserverInfo, LifecycleObserverInfo> = mutableMapOf()
-    val superObservers = world.mapValues { superObservers(world, it.value) }
 
     fun traverse(observer: LifecycleObserverInfo) {
         if (observer in flattened) {
             return
         }
-        val observers = superObservers[observer.type]!!
-        if (observers.isEmpty()) {
+        if (observer.parents.isEmpty()) {
             flattened[observer] = observer
             return
         }
-        observers.filter { it !in flattened }.forEach(::traverse)
-        val methods = observers
+        observer.parents.forEach(::traverse)
+        val methods = observer.parents
                 .map(flattened::get)
                 .fold(emptyList<EventMethod>()) { list, parentObserver ->
-                    mergeAndVerifyMethods(processingEnv, observer.type, parentObserver!!.methods, list)
+                    mergeAndVerifyMethods(processingEnv, observer.type,
+                            parentObserver!!.methods, list)
                 }
 
         flattened[observer] = LifecycleObserverInfo(observer.type,
-                mergeAndVerifyMethods(processingEnv, observer.type, observer.methods, methods))
+                mergeAndVerifyMethods(processingEnv, observer.type, observer.methods, methods),
+                observer.hasAdapter)
     }
 
     world.values.forEach(::traverse)
@@ -110,21 +82,24 @@
                       world: Map<TypeElement, LifecycleObserverInfo>): List<AdapterClass> {
     val flatObservers = flattenObservers(processingEnv, world)
     val syntheticMethods = HashMultimap.create<TypeElement, EventMethodCall>()
-    val adapterCalls = flatObservers.map { (type, methods) ->
-        val calls = methods.map { eventMethod ->
-            val executable = eventMethod.method
-            if (type.getPackageQName() != eventMethod.packageName()
-                    && (executable.isPackagePrivate() || executable.isProtected())) {
-                EventMethodCall(eventMethod, eventMethod.type)
-            } else {
-                EventMethodCall(eventMethod)
-            }
-        }
-        calls.filter { it.syntheticAccess != null }.forEach { eventMethod ->
-            syntheticMethods.put(eventMethod.method.type, eventMethod)
-        }
-        type to calls
-    }.toMap()
+    flatObservers.filterNot(LifecycleObserverInfo::hasAdapter)
+    val adapterCalls = flatObservers
+            .filterNot(LifecycleObserverInfo::hasAdapter)
+            .map { (type, methods) ->
+                val calls = methods.map { eventMethod ->
+                    val executable = eventMethod.method
+                    if (type.getPackageQName() != eventMethod.packageName()
+                            && (executable.isPackagePrivate() || executable.isProtected())) {
+                        EventMethodCall(eventMethod, eventMethod.type)
+                    } else {
+                        EventMethodCall(eventMethod)
+                    }
+                }
+                calls.filter { it.syntheticAccess != null }.forEach { eventMethod ->
+                    syntheticMethods.put(eventMethod.method.type, eventMethod)
+                }
+                type to calls
+            }.toMap()
 
     return adapterCalls.map { (type, calls) ->
         val methods = syntheticMethods.get(type) ?: setOf()
diff --git a/lifecycle/compiler/src/main/kotlin/android/arch/lifecycle/writer.kt b/lifecycle/compiler/src/main/kotlin/android/arch/lifecycle/writer.kt
index 4f12ff4..6b9b7a6 100644
--- a/lifecycle/compiler/src/main/kotlin/android/arch/lifecycle/writer.kt
+++ b/lifecycle/compiler/src/main/kotlin/android/arch/lifecycle/writer.kt
@@ -18,6 +18,7 @@
 
 import android.arch.lifecycle.model.AdapterClass
 import android.arch.lifecycle.model.EventMethodCall
+import android.arch.lifecycle.model.getAdapterName
 import com.squareup.javapoet.AnnotationSpec
 import com.squareup.javapoet.ClassName
 import com.squareup.javapoet.FieldSpec
@@ -36,7 +37,6 @@
     infos.forEach({ writeAdapter(it, processingEnv) })
 }
 
-
 private val GENERATED_PACKAGE = "javax.annotation"
 private val GENERATED_NAME = "Generated"
 private val LIFECYCLE_OWNER = ClassName.get(LifecycleOwner::class.java)
@@ -63,9 +63,7 @@
     val dispatchMethod = dispatchMethodBuilder.apply {
         adapter.calls
                 .groupBy { (eventMethod) -> eventMethod.onLifecycleEvent.value }
-                .forEach { entry ->
-                    val event = entry.key
-                    val calls = entry.value
+                .forEach { (event, calls) ->
                     if (event == Lifecycle.Event.ON_ANY) {
                         writeMethodCalls(eventParam, calls, ownerParam, receiverField)
                     } else {
@@ -184,12 +182,4 @@
 
 private fun takeParams(count: Int, vararg params: Any) = params.take(count).toTypedArray()
 
-private fun generateParamString(count: Int) = (0..(count - 1)).joinToString(",") { N }
-
-private fun getAdapterName(type: TypeElement): String {
-    val packageElement = type.getPackage()
-    val qName = type.qualifiedName.toString()
-    val partialName = if (packageElement.isUnnamed) qName else qName.substring(
-            packageElement.qualifiedName.toString().length + 1)
-    return Lifecycling.getAdapterName(partialName)
-}
+private fun generateParamString(count: Int) = (0 until count).joinToString(",") { N }
\ No newline at end of file
diff --git a/lifecycle/compiler/src/tests/kotlin/android/arch/lifecycle/ValidCasesTest.kt b/lifecycle/compiler/src/tests/kotlin/android/arch/lifecycle/ValidCasesTest.kt
index 247d416..a4fda54 100644
--- a/lifecycle/compiler/src/tests/kotlin/android/arch/lifecycle/ValidCasesTest.kt
+++ b/lifecycle/compiler/src/tests/kotlin/android/arch/lifecycle/ValidCasesTest.kt
@@ -19,10 +19,13 @@
 import android.arch.lifecycle.utils.load
 import android.arch.lifecycle.utils.processClass
 import com.google.testing.compile.CompileTester
+import com.google.testing.compile.JavaSourcesSubject
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.junit.runners.JUnit4
 import javax.tools.StandardLocation
+import java.io.File
+import java.net.URLClassLoader
 
 @RunWith(JUnit4::class)
 class ValidCasesTest {
@@ -112,4 +115,16 @@
             CompileTester.SuccessfulFileClause<T> {
         return generatesFileNamed(StandardLocation.CLASS_OUTPUT, "", "META-INF/proguard/$name")
     }
+
+    @Test
+    fun testJar() {
+        val jarUrl = File("src/tests/test-data/lib/test-library.jar").toURI().toURL()
+        val classLoader = URLClassLoader(arrayOf(jarUrl), this.javaClass.classLoader)
+        JavaSourcesSubject.assertThat(load("foo.DerivedFromJar", ""))
+                .withClasspathFrom(classLoader)
+                .processedWith(LifecycleProcessor())
+                .compilesWithoutError().and()
+                .generatesSources(load("foo.DerivedFromJar_LifecycleAdapter", "expected")
+        )
+    }
 }
diff --git a/lifecycle/compiler/src/tests/test-data/Bar.java b/lifecycle/compiler/src/tests/test-data/Bar.java
index 773948e..cfc41ca 100644
--- a/lifecycle/compiler/src/tests/test-data/Bar.java
+++ b/lifecycle/compiler/src/tests/test-data/Bar.java
@@ -4,10 +4,11 @@
 import static android.arch.lifecycle.Lifecycle.Event.ON_STOP;
 
 import android.arch.lifecycle.Lifecycle.Event;
+import android.arch.lifecycle.LifecycleObserver;
 import android.arch.lifecycle.LifecycleOwner;
 import android.arch.lifecycle.OnLifecycleEvent;
 
-public class Bar {
+public class Bar implements LifecycleObserver {
     @OnLifecycleEvent(ON_START)
     public void doOnStart() {
     }
@@ -20,17 +21,17 @@
     public void doOnStop2Args(LifecycleOwner provider) {
     }
 
-    public static class Inner1 {
+    public static class Inner1 implements LifecycleObserver {
         @OnLifecycleEvent(ON_START)
         public void doOnStart() {
         }
 
-        public static class Inner2 {
+        public static class Inner2 implements LifecycleObserver {
             @OnLifecycleEvent(ON_START)
             public void doOnStart() {
             }
 
-            public static class Inner3 {
+            public static class Inner3 implements LifecycleObserver {
                 @OnLifecycleEvent(ON_START)
                 public void doOnStart() {
                 }
diff --git a/lifecycle/compiler/src/tests/test-data/DerivedFromJar.java b/lifecycle/compiler/src/tests/test-data/DerivedFromJar.java
new file mode 100644
index 0000000..d503903
--- /dev/null
+++ b/lifecycle/compiler/src/tests/test-data/DerivedFromJar.java
@@ -0,0 +1,12 @@
+package foo;
+
+import static android.arch.lifecycle.Lifecycle.Event.ON_START;
+
+import android.arch.lifecycle.Lifecycle.Event;
+import android.arch.lifecycle.OnLifecycleEvent;
+
+public class DerivedFromJar extends test.library.LibraryBaseObserver {
+    @OnLifecycleEvent(ON_START)
+    public void doAnother() {
+    }
+}
diff --git a/lifecycle/compiler/src/tests/test-data/DifferentPackagesBase1.java b/lifecycle/compiler/src/tests/test-data/DifferentPackagesBase1.java
index cc9d5d5..fb0966d 100644
--- a/lifecycle/compiler/src/tests/test-data/DifferentPackagesBase1.java
+++ b/lifecycle/compiler/src/tests/test-data/DifferentPackagesBase1.java
@@ -19,10 +19,11 @@
 import static android.arch.lifecycle.Lifecycle.Event.ON_STOP;
 
 import android.arch.lifecycle.Lifecycle.Event;
+import android.arch.lifecycle.LifecycleObserver;
 import android.arch.lifecycle.LifecycleOwner;
 import android.arch.lifecycle.OnLifecycleEvent;
 
-public class DifferentPackagesBase1 {
+public class DifferentPackagesBase1 implements LifecycleObserver {
     @OnLifecycleEvent(ON_STOP)
     void onStop(LifecycleOwner provider){}
 }
diff --git a/lifecycle/compiler/src/tests/test-data/DifferentPackagesBase2.java b/lifecycle/compiler/src/tests/test-data/DifferentPackagesBase2.java
index e31921a..1c3ea72 100644
--- a/lifecycle/compiler/src/tests/test-data/DifferentPackagesBase2.java
+++ b/lifecycle/compiler/src/tests/test-data/DifferentPackagesBase2.java
@@ -19,10 +19,11 @@
 import static android.arch.lifecycle.Lifecycle.Event.ON_STOP;
 
 import android.arch.lifecycle.Lifecycle.Event;
+import android.arch.lifecycle.LifecycleObserver;
 import android.arch.lifecycle.LifecycleOwner;
 import android.arch.lifecycle.OnLifecycleEvent;
 
-class DifferentPackagesPreBase2 {
+class DifferentPackagesPreBase2 implements LifecycleObserver {
     @OnLifecycleEvent(ON_STOP)
     void onStop(LifecycleOwner provider){}
 }
diff --git a/lifecycle/compiler/src/tests/test-data/InheritanceOk1.java b/lifecycle/compiler/src/tests/test-data/InheritanceOk1.java
index 79c2151..889c463 100644
--- a/lifecycle/compiler/src/tests/test-data/InheritanceOk1.java
+++ b/lifecycle/compiler/src/tests/test-data/InheritanceOk1.java
@@ -19,10 +19,11 @@
 import static android.arch.lifecycle.Lifecycle.Event.ON_STOP;
 
 import android.arch.lifecycle.Lifecycle.Event;
+import android.arch.lifecycle.LifecycleObserver;
 import android.arch.lifecycle.LifecycleOwner;
 import android.arch.lifecycle.OnLifecycleEvent;
 
-class Base1 {
+class Base1 implements LifecycleObserver {
     @OnLifecycleEvent(ON_STOP)
     public void onStop(LifecycleOwner provider) {
     }
@@ -43,7 +44,7 @@
     }
 }
 
-class Base2 {
+class Base2 implements LifecycleObserver {
     @OnLifecycleEvent(ON_STOP)
     public void onStop(LifecycleOwner provider) {
     }
diff --git a/lifecycle/compiler/src/tests/test-data/InheritanceOk2.java b/lifecycle/compiler/src/tests/test-data/InheritanceOk2.java
index 31f0a41..bb00cca 100644
--- a/lifecycle/compiler/src/tests/test-data/InheritanceOk2.java
+++ b/lifecycle/compiler/src/tests/test-data/InheritanceOk2.java
@@ -3,10 +3,11 @@
 import static android.arch.lifecycle.Lifecycle.Event.ON_STOP;
 
 import android.arch.lifecycle.Lifecycle.Event;
+import android.arch.lifecycle.LifecycleObserver;
 import android.arch.lifecycle.LifecycleOwner;
 import android.arch.lifecycle.OnLifecycleEvent;
 
-class InheritanceOk2Base {
+class InheritanceOk2Base implements LifecycleObserver {
     @OnLifecycleEvent(ON_STOP)
     public void onStop(LifecycleOwner provider) {
     }
diff --git a/lifecycle/compiler/src/tests/test-data/InheritanceOk3.java b/lifecycle/compiler/src/tests/test-data/InheritanceOk3.java
index 50c4623..5a3c91d 100644
--- a/lifecycle/compiler/src/tests/test-data/InheritanceOk3.java
+++ b/lifecycle/compiler/src/tests/test-data/InheritanceOk3.java
@@ -19,10 +19,11 @@
 import static android.arch.lifecycle.Lifecycle.Event.ON_STOP;
 
 import android.arch.lifecycle.Lifecycle.Event;
+import android.arch.lifecycle.LifecycleObserver;
 import android.arch.lifecycle.LifecycleOwner;
 import android.arch.lifecycle.OnLifecycleEvent;
 
-class InheritanceOk3Base {
+class InheritanceOk3Base implements LifecycleObserver {
     @OnLifecycleEvent(ON_STOP)
     public void onStop(LifecycleOwner provider) {
     }
diff --git a/lifecycle/compiler/src/tests/test-data/InterfaceOk1.java b/lifecycle/compiler/src/tests/test-data/InterfaceOk1.java
index 3584f6d..8450302 100644
--- a/lifecycle/compiler/src/tests/test-data/InterfaceOk1.java
+++ b/lifecycle/compiler/src/tests/test-data/InterfaceOk1.java
@@ -17,10 +17,11 @@
 import static android.arch.lifecycle.Lifecycle.Event.ON_STOP;
 
 import android.arch.lifecycle.Lifecycle.Event;
+import android.arch.lifecycle.LifecycleObserver;
 import android.arch.lifecycle.LifecycleOwner;
 import android.arch.lifecycle.OnLifecycleEvent;
 
-interface InterfaceOk1 {
+interface InterfaceOk1 extends LifecycleObserver {
     @OnLifecycleEvent(ON_STOP)
     void onStop(LifecycleOwner provider);
 }
diff --git a/lifecycle/compiler/src/tests/test-data/InterfaceOk2.java b/lifecycle/compiler/src/tests/test-data/InterfaceOk2.java
index 58688d3..fee5b10 100644
--- a/lifecycle/compiler/src/tests/test-data/InterfaceOk2.java
+++ b/lifecycle/compiler/src/tests/test-data/InterfaceOk2.java
@@ -19,16 +19,17 @@
 import static android.arch.lifecycle.Lifecycle.Event.ON_STOP;
 
 import android.arch.lifecycle.Lifecycle.Event;
+import android.arch.lifecycle.LifecycleObserver;
 import android.arch.lifecycle.LifecycleOwner;
 import android.arch.lifecycle.OnLifecycleEvent;
 
-class InterfaceOk2Base {
+class InterfaceOk2Base implements LifecycleObserver {
     @OnLifecycleEvent(ON_STOP)
     public void onStop1(LifecycleOwner provider) {
     }
 }
 
-interface InterfaceOk2Interface {
+interface InterfaceOk2Interface extends LifecycleObserver {
     @OnLifecycleEvent(ON_STOP)
     void onStop2(LifecycleOwner provider);
 }
diff --git a/lifecycle/compiler/src/tests/test-data/InvalidClassModifier.java b/lifecycle/compiler/src/tests/test-data/InvalidClassModifier.java
index 4c30bb6..919bb8c 100644
--- a/lifecycle/compiler/src/tests/test-data/InvalidClassModifier.java
+++ b/lifecycle/compiler/src/tests/test-data/InvalidClassModifier.java
@@ -19,10 +19,11 @@
 import static android.arch.lifecycle.Lifecycle.Event.ON_STOP;
 
 import android.arch.lifecycle.Lifecycle.Event;
+import android.arch.lifecycle.LifecycleObserver;
 import android.arch.lifecycle.OnLifecycleEvent;
 
 public class InvalidClassModifier {
-    private static class Inner {
+    private static class Inner implements LifecycleObserver {
         @OnLifecycleEvent(ON_STOP)
         private void onStop() {
         }
diff --git a/lifecycle/compiler/src/tests/test-data/InvalidFirstArg1.java b/lifecycle/compiler/src/tests/test-data/InvalidFirstArg1.java
index 26bfc23..b028443 100644
--- a/lifecycle/compiler/src/tests/test-data/InvalidFirstArg1.java
+++ b/lifecycle/compiler/src/tests/test-data/InvalidFirstArg1.java
@@ -3,9 +3,10 @@
 import static android.arch.lifecycle.Lifecycle.Event.ON_STOP;
 
 import android.arch.lifecycle.Lifecycle.Event;
+import android.arch.lifecycle.LifecycleObserver;
 import android.arch.lifecycle.OnLifecycleEvent;
 
-public class InvalidFirstArg1 {
+public class InvalidFirstArg1 implements LifecycleObserver {
     @OnLifecycleEvent(ON_STOP)
     public void onStop(Event event) {
     }
diff --git a/lifecycle/compiler/src/tests/test-data/InvalidFirstArg2.java b/lifecycle/compiler/src/tests/test-data/InvalidFirstArg2.java
index 459c316..d9937ac 100644
--- a/lifecycle/compiler/src/tests/test-data/InvalidFirstArg2.java
+++ b/lifecycle/compiler/src/tests/test-data/InvalidFirstArg2.java
@@ -3,9 +3,10 @@
 import static android.arch.lifecycle.Lifecycle.Event.ON_ANY;
 
 import android.arch.lifecycle.Lifecycle.Event;
+import android.arch.lifecycle.LifecycleObserver;
 import android.arch.lifecycle.OnLifecycleEvent;
 
-public class InvalidFirstArg2 {
+public class InvalidFirstArg2 implements LifecycleObserver {
     @OnLifecycleEvent(ON_ANY)
     public void onStop(Event e2, Event event) {
     }
diff --git a/lifecycle/compiler/src/tests/test-data/InvalidInheritance1.java b/lifecycle/compiler/src/tests/test-data/InvalidInheritance1.java
index 69f6bb2..d8f0f62 100644
--- a/lifecycle/compiler/src/tests/test-data/InvalidInheritance1.java
+++ b/lifecycle/compiler/src/tests/test-data/InvalidInheritance1.java
@@ -19,9 +19,10 @@
 import static android.arch.lifecycle.Lifecycle.Event.ON_START;
 import static android.arch.lifecycle.Lifecycle.Event.ON_STOP;
 
+import android.arch.lifecycle.LifecycleObserver;
 import android.arch.lifecycle.OnLifecycleEvent;
 
-class Base {
+class Base implements LifecycleObserver {
     @OnLifecycleEvent(ON_STOP)
     void foo() {
     }
diff --git a/lifecycle/compiler/src/tests/test-data/InvalidInheritance2.java b/lifecycle/compiler/src/tests/test-data/InvalidInheritance2.java
index b714e47..b63ad44 100644
--- a/lifecycle/compiler/src/tests/test-data/InvalidInheritance2.java
+++ b/lifecycle/compiler/src/tests/test-data/InvalidInheritance2.java
@@ -19,10 +19,10 @@
 import static android.arch.lifecycle.Lifecycle.Event.ON_START;
 import static android.arch.lifecycle.Lifecycle.Event.ON_STOP;
 
-import android.arch.lifecycle.LifecycleOwner;
+import android.arch.lifecycle.LifecycleObserver;
 import android.arch.lifecycle.OnLifecycleEvent;
 
-interface Base {
+interface Base extends LifecycleObserver {
     @OnLifecycleEvent(ON_STOP)
     void foo();
 }
diff --git a/lifecycle/compiler/src/tests/test-data/InvalidMethodModifier.java b/lifecycle/compiler/src/tests/test-data/InvalidMethodModifier.java
index 6540333..5eed7b8 100644
--- a/lifecycle/compiler/src/tests/test-data/InvalidMethodModifier.java
+++ b/lifecycle/compiler/src/tests/test-data/InvalidMethodModifier.java
@@ -19,9 +19,10 @@
 import static android.arch.lifecycle.Lifecycle.Event.ON_STOP;
 
 import android.arch.lifecycle.Lifecycle.Event;
+import android.arch.lifecycle.LifecycleObserver;
 import android.arch.lifecycle.OnLifecycleEvent;
 
-public class InvalidMethodModifier {
+public class InvalidMethodModifier implements LifecycleObserver {
     @OnLifecycleEvent(ON_STOP)
     private void onStop() {
     }
diff --git a/lifecycle/compiler/src/tests/test-data/InvalidSecondArg.java b/lifecycle/compiler/src/tests/test-data/InvalidSecondArg.java
index e98d915..60ad464 100644
--- a/lifecycle/compiler/src/tests/test-data/InvalidSecondArg.java
+++ b/lifecycle/compiler/src/tests/test-data/InvalidSecondArg.java
@@ -2,10 +2,11 @@
 
 import static android.arch.lifecycle.Lifecycle.Event.ON_ANY;
 
+import android.arch.lifecycle.LifecycleObserver;
 import android.arch.lifecycle.LifecycleOwner;
 import android.arch.lifecycle.OnLifecycleEvent;
 
-public class InvalidSecondArg {
+public class InvalidSecondArg implements LifecycleObserver {
     @OnLifecycleEvent(ON_ANY)
     public void onStop(LifecycleOwner provider, Object lastEvent) {
     }
diff --git a/lifecycle/compiler/src/tests/test-data/NoPackageOk.java b/lifecycle/compiler/src/tests/test-data/NoPackageOk.java
index a00283d..e7a84ef 100644
--- a/lifecycle/compiler/src/tests/test-data/NoPackageOk.java
+++ b/lifecycle/compiler/src/tests/test-data/NoPackageOk.java
@@ -17,10 +17,11 @@
 import static android.arch.lifecycle.Lifecycle.Event.ON_STOP;
 
 import android.arch.lifecycle.Lifecycle.Event;
+import android.arch.lifecycle.LifecycleObserver;
 import android.arch.lifecycle.LifecycleOwner;
 import android.arch.lifecycle.OnLifecycleEvent;
 
-class NoPackageOk {
+class NoPackageOk implements LifecycleObserver {
     @OnLifecycleEvent(ON_STOP)
     void onStop(LifecycleOwner provider){}
 }
diff --git a/lifecycle/compiler/src/tests/test-data/OnAnyMethod.java b/lifecycle/compiler/src/tests/test-data/OnAnyMethod.java
index f03f1cd..8761774 100644
--- a/lifecycle/compiler/src/tests/test-data/OnAnyMethod.java
+++ b/lifecycle/compiler/src/tests/test-data/OnAnyMethod.java
@@ -20,10 +20,11 @@
 import static android.arch.lifecycle.Lifecycle.Event.ON_STOP;
 
 import android.arch.lifecycle.Lifecycle.Event;
+import android.arch.lifecycle.LifecycleObserver;
 import android.arch.lifecycle.LifecycleOwner;
 import android.arch.lifecycle.OnLifecycleEvent;
 
-public class OnAnyMethod {
+public class OnAnyMethod implements LifecycleObserver {
 
     @OnLifecycleEvent(ON_STOP)
     void onStop(LifecycleOwner provider){}
@@ -31,7 +32,6 @@
     @OnLifecycleEvent(ON_ANY)
     void any(LifecycleOwner provider){}
 
-
     @OnLifecycleEvent(ON_ANY)
     void any(LifecycleOwner provider, Event event){}
 }
diff --git a/lifecycle/compiler/src/tests/test-data/TooManyArgs1.java b/lifecycle/compiler/src/tests/test-data/TooManyArgs1.java
index 0d65098..cdcff60 100644
--- a/lifecycle/compiler/src/tests/test-data/TooManyArgs1.java
+++ b/lifecycle/compiler/src/tests/test-data/TooManyArgs1.java
@@ -3,10 +3,11 @@
 import static android.arch.lifecycle.Lifecycle.Event.ON_ANY;
 
 import android.arch.lifecycle.Lifecycle.Event;
+import android.arch.lifecycle.LifecycleObserver;
 import android.arch.lifecycle.LifecycleOwner;
 import android.arch.lifecycle.OnLifecycleEvent;
 
-public class TooManyArgs1 {
+public class TooManyArgs1 implements LifecycleObserver {
     @OnLifecycleEvent(ON_ANY)
     public void onAny(LifecycleOwner provider, Event event, int x) {
     }
diff --git a/lifecycle/compiler/src/tests/test-data/TooManyArgs2.java b/lifecycle/compiler/src/tests/test-data/TooManyArgs2.java
index f332d0b..b38d906 100644
--- a/lifecycle/compiler/src/tests/test-data/TooManyArgs2.java
+++ b/lifecycle/compiler/src/tests/test-data/TooManyArgs2.java
@@ -3,10 +3,11 @@
 import static android.arch.lifecycle.Lifecycle.Event.ON_STOP;
 
 import android.arch.lifecycle.Lifecycle.Event;
+import android.arch.lifecycle.LifecycleObserver;
 import android.arch.lifecycle.LifecycleOwner;
 import android.arch.lifecycle.OnLifecycleEvent;
 
-public class TooManyArgs2 {
+public class TooManyArgs2 implements LifecycleObserver {
     @OnLifecycleEvent(ON_STOP)
     public void onStop(LifecycleOwner provider, Event event) {
     }
diff --git a/lifecycle/compiler/src/tests/test-data/expected/DerivedFromJar_LifecycleAdapter.java b/lifecycle/compiler/src/tests/test-data/expected/DerivedFromJar_LifecycleAdapter.java
new file mode 100644
index 0000000..f3889a1
--- /dev/null
+++ b/lifecycle/compiler/src/tests/test-data/expected/DerivedFromJar_LifecycleAdapter.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 foo;
+
+import android.arch.lifecycle.GenericLifecycleObserver;
+import android.arch.lifecycle.Lifecycle;
+import android.arch.lifecycle.LifecycleOwner;
+import java.lang.Override;
+import javax.annotation.Generated;
+
+@Generated("android.arch.lifecycle.LifecycleProcessor")
+public class DerivedFromJar_LifecycleAdapter implements GenericLifecycleObserver {
+  final DerivedFromJar mReceiver;
+
+  DerivedFromJar_LifecycleAdapter(DerivedFromJar receiver) {
+    this.mReceiver = receiver;
+  }
+
+  @Override
+  public void onStateChanged(LifecycleOwner owner, Lifecycle.Event event) {
+    if (event == Lifecycle.Event.ON_START) {
+      mReceiver.doOnStart();
+      mReceiver.doAnother();
+    }
+  }
+}
diff --git a/lifecycle/compiler/src/tests/test-data/lib/src/test/library/LibraryBaseObserver.java b/lifecycle/compiler/src/tests/test-data/lib/src/test/library/LibraryBaseObserver.java
new file mode 100644
index 0000000..d43347f
--- /dev/null
+++ b/lifecycle/compiler/src/tests/test-data/lib/src/test/library/LibraryBaseObserver.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package test.library;
+
+import static android.arch.lifecycle.Lifecycle.Event.ON_START;
+import static android.arch.lifecycle.Lifecycle.Event.ON_STOP;
+
+import android.arch.lifecycle.Lifecycle.Event;
+import android.arch.lifecycle.LifecycleObserver;
+import android.arch.lifecycle.LifecycleOwner;
+import android.arch.lifecycle.OnLifecycleEvent;
+
+public class LibraryBaseObserver implements LifecycleObserver {
+    @OnLifecycleEvent(ON_START)
+    public void doOnStart() {
+    }
+}
diff --git a/lifecycle/compiler/src/tests/test-data/lib/src/test/library/LibraryBaseObserver_LifecycleAdapter.java b/lifecycle/compiler/src/tests/test-data/lib/src/test/library/LibraryBaseObserver_LifecycleAdapter.java
new file mode 100644
index 0000000..da44f92
--- /dev/null
+++ b/lifecycle/compiler/src/tests/test-data/lib/src/test/library/LibraryBaseObserver_LifecycleAdapter.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package test.library;
+
+import android.arch.lifecycle.GenericLifecycleObserver;
+import android.arch.lifecycle.Lifecycle;
+import android.arch.lifecycle.LifecycleOwner;
+import java.lang.Override;
+import javax.annotation.Generated;
+
+@Generated("android.arch.lifecycle.LifecycleProcessor")
+public class LibraryBaseObserver_LifecycleAdapter implements GenericLifecycleObserver {
+    final LibraryBaseObserver mReceiver;
+
+    LibraryBaseObserver_LifecycleAdapter(LibraryBaseObserver receiver) {
+        this.mReceiver = receiver;
+    }
+
+    @Override
+    public void onStateChanged(LifecycleOwner owner, Lifecycle.Event event) {
+        if (event == Lifecycle.Event.ON_START) {
+            mReceiver.doOnStart();
+        }
+    }
+}
diff --git a/lifecycle/compiler/src/tests/test-data/lib/test-library.jar b/lifecycle/compiler/src/tests/test-data/lib/test-library.jar
new file mode 100644
index 0000000..f1156ad
--- /dev/null
+++ b/lifecycle/compiler/src/tests/test-data/lib/test-library.jar
Binary files differ
diff --git a/lifecycle/extensions/build.gradle b/lifecycle/extensions/build.gradle
index 9d33e55..79be36c 100644
--- a/lifecycle/extensions/build.gradle
+++ b/lifecycle/extensions/build.gradle
@@ -45,8 +45,6 @@
     compile libs.support.fragments, libs.support_exclude_config
     compile project(":lifecycle:common")
 
-    annotationProcessor project(":lifecycle:compiler")
-
     testCompile project(":arch:core-testing")
     testCompile libs.junit
     testCompile libs.mockito_core
diff --git a/lifecycle/extensions/src/main/java/android/arch/lifecycle/LiveData.java b/lifecycle/extensions/src/main/java/android/arch/lifecycle/LiveData.java
index da5600c..4c0b7a4 100644
--- a/lifecycle/extensions/src/main/java/android/arch/lifecycle/LiveData.java
+++ b/lifecycle/extensions/src/main/java/android/arch/lifecycle/LiveData.java
@@ -354,7 +354,7 @@
         return mActiveCount > 0;
     }
 
-    class LifecycleBoundObserver implements LifecycleObserver {
+    class LifecycleBoundObserver implements GenericLifecycleObserver {
         public final LifecycleOwner owner;
         public final Observer<T> observer;
         public boolean active;
@@ -365,9 +365,8 @@
             this.observer = observer;
         }
 
-        @SuppressWarnings("unused")
-        @OnLifecycleEvent(Lifecycle.Event.ON_ANY)
-        void onStateChange() {
+        @Override
+        public void onStateChanged(LifecycleOwner source, Lifecycle.Event event) {
             if (owner.getLifecycle().getCurrentState() == DESTROYED) {
                 removeObserver(observer);
                 return;
diff --git a/lifecycle/reactivestreams/src/main/java/android/arch/lifecycle/LiveDataReactiveStreams.java b/lifecycle/reactivestreams/src/main/java/android/arch/lifecycle/LiveDataReactiveStreams.java
index ec9b7f1..2b25bc9 100644
--- a/lifecycle/reactivestreams/src/main/java/android/arch/lifecycle/LiveDataReactiveStreams.java
+++ b/lifecycle/reactivestreams/src/main/java/android/arch/lifecycle/LiveDataReactiveStreams.java
@@ -17,6 +17,7 @@
 package android.arch.lifecycle;
 
 import android.arch.core.executor.ArchTaskExecutor;
+import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
 
 import org.reactivestreams.Publisher;
@@ -133,40 +134,101 @@
 
     /**
      * Creates an Observable {@link LiveData} stream from a ReactiveStreams publisher.
+     *
+     * <p>
+     * When the LiveData becomes active, it subscribes to the emissions from the Publisher.
+     *
+     * <p>
+     * When the LiveData becomes inactive, the subscription is cleared.
+     * LiveData holds the last value emitted by the Publisher when the LiveData was active.
+     * <p>
+     * Therefore, in the case of a hot RxJava Observable, when a new LiveData {@link Observer} is
+     * added, it will automatically notify with the last value held in LiveData,
+     * which might not be the last value emitted by the Publisher.
+     *
+     * @param <T> The type of data hold by this instance.
      */
     public static <T> LiveData<T> fromPublisher(final Publisher<T> publisher) {
-        MutableLiveData<T> liveData = new MutableLiveData<>();
-        // Since we don't have a way to directly observe cancels, weakly hold the live data.
-        final WeakReference<MutableLiveData<T>> liveDataRef = new WeakReference<>(liveData);
-
-        publisher.subscribe(new Subscriber<T>() {
-            @Override
-            public void onSubscribe(Subscription s) {
-                // Don't worry about backpressure. If the stream is too noisy then backpressure can
-                // be handled upstream.
-                s.request(Long.MAX_VALUE);
-            }
-
-            @Override
-            public void onNext(final T t) {
-                final LiveData<T> liveData = liveDataRef.get();
-                if (liveData != null) {
-                    liveData.postValue(t);
-                }
-            }
-
-            @Override
-            public void onError(Throwable t) {
-                // Errors should be handled upstream, so propagate as a crash.
-                throw new RuntimeException(t);
-            }
-
-            @Override
-            public void onComplete() {
-            }
-        });
-
-        return liveData;
+        return new PublisherLiveData<>(publisher);
     }
 
+    /**
+     * Defines a {@link LiveData} object that wraps a {@link Publisher}.
+     *
+     * <p>
+     * When the LiveData becomes active, it subscribes to the emissions from the Publisher.
+     *
+     * <p>
+     * When the LiveData becomes inactive, the subscription is cleared.
+     * LiveData holds the last value emitted by the Publisher when the LiveData was active.
+     * <p>
+     * Therefore, in the case of a hot RxJava Observable, when a new LiveData {@link Observer} is
+     * added, it will automatically notify with the last value held in LiveData,
+     * which might not be the last value emitted by the Publisher.
+     *
+     * @param <T> The type of data hold by this instance.
+     */
+    private static class PublisherLiveData<T> extends LiveData<T> {
+        private WeakReference<Subscription> mSubscriptionRef;
+        private final Publisher mPublisher;
+        private final Object mLock = new Object();
+
+        PublisherLiveData(@NonNull final Publisher publisher) {
+            mPublisher = publisher;
+        }
+
+        @Override
+        protected void onActive() {
+            super.onActive();
+
+            mPublisher.subscribe(new Subscriber<T>() {
+                @Override
+                public void onSubscribe(Subscription s) {
+                    // Don't worry about backpressure. If the stream is too noisy then
+                    // backpressure can be handled upstream.
+                    synchronized (mLock) {
+                        s.request(Long.MAX_VALUE);
+                        mSubscriptionRef = new WeakReference<>(s);
+                    }
+                }
+
+                @Override
+                public void onNext(final T t) {
+                    postValue(t);
+                }
+
+                @Override
+                public void onError(Throwable t) {
+                    synchronized (mLock) {
+                        mSubscriptionRef = null;
+                    }
+                    // Errors should be handled upstream, so propagate as a crash.
+                    throw new RuntimeException(t);
+                }
+
+                @Override
+                public void onComplete() {
+                    synchronized (mLock) {
+                        mSubscriptionRef = null;
+                    }
+                }
+            });
+
+        }
+
+        @Override
+        protected void onInactive() {
+            super.onInactive();
+            synchronized (mLock) {
+                WeakReference<Subscription> subscriptionRef = mSubscriptionRef;
+                if (subscriptionRef != null) {
+                    Subscription subscription = subscriptionRef.get();
+                    if (subscription != null) {
+                        subscription.cancel();
+                    }
+                    mSubscriptionRef = null;
+                }
+            }
+        }
+    }
 }
diff --git a/lifecycle/reactivestreams/src/test/java/android/arch/lifecycle/LiveDataReactiveStreamsTest.java b/lifecycle/reactivestreams/src/test/java/android/arch/lifecycle/LiveDataReactiveStreamsTest.java
index ca52ee5..7278847 100644
--- a/lifecycle/reactivestreams/src/test/java/android/arch/lifecycle/LiveDataReactiveStreamsTest.java
+++ b/lifecycle/reactivestreams/src/test/java/android/arch/lifecycle/LiveDataReactiveStreamsTest.java
@@ -140,6 +140,38 @@
     }
 
     @Test
+    public void convertsFromPublisherAfterInactive() {
+        PublishProcessor<String> processor = PublishProcessor.create();
+        LiveData<String> liveData = LiveDataReactiveStreams.fromPublisher(processor);
+
+        liveData.observe(mLifecycleOwner, mObserver);
+        processor.onNext("foo");
+        liveData.removeObserver(mObserver);
+        processor.onNext("bar");
+
+        liveData.observe(mLifecycleOwner, mObserver);
+        processor.onNext("baz");
+
+        assertThat(mLiveDataOutput, is(Arrays.asList("foo", "foo", "baz")));
+    }
+
+    @Test
+    public void convertsFromPublisherManagesSubcriptions() {
+        PublishProcessor<String> processor = PublishProcessor.create();
+        LiveData<String> liveData = LiveDataReactiveStreams.fromPublisher(processor);
+
+        assertThat(processor.hasSubscribers(), is(false));
+        liveData.observe(mLifecycleOwner, mObserver);
+
+        // once the live data is active, there's a subscriber
+        assertThat(processor.hasSubscribers(), is(true));
+
+        liveData.removeObserver(mObserver);
+        // once the live data is inactive, the subscriber is removed
+        assertThat(processor.hasSubscribers(), is(false));
+    }
+
+    @Test
     public void convertsFromAsyncPublisher() {
         Flowable<String> input = Flowable.just("foo")
                 .concatWith(Flowable.just("bar", "baz").observeOn(sBackgroundScheduler));
diff --git a/paging/common/src/main/java/android/arch/paging/ContiguousDataSource.java b/paging/common/src/main/java/android/arch/paging/ContiguousDataSource.java
index 9ff1117..afcc208 100644
--- a/paging/common/src/main/java/android/arch/paging/ContiguousDataSource.java
+++ b/paging/common/src/main/java/android/arch/paging/ContiguousDataSource.java
@@ -41,6 +41,8 @@
         return true;
     }
 
+    /** @hide */
+    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
     @WorkerThread
     @Nullable
     public abstract NullPaddedList<Value> loadInitial(
@@ -58,7 +60,10 @@
      * @param pageSize        Suggested number of items to load.
      * @return List of items, starting at position currentEndIndex + 1. Null if the data source is
      * no longer valid, and should not be queried again.
+     *
+     * @hide
      */
+    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
     @WorkerThread
     @Nullable
     public final List<Value> loadAfter(int currentEndIndex,
@@ -88,7 +93,10 @@
      *                          on item contents.
      * @param pageSize          Suggested number of items to load.
      * @return List of items, in descending order, starting at position currentBeginIndex - 1.
+     *
+     * @hide
      */
+    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
     @WorkerThread
     @Nullable
     public final List<Value> loadBefore(int currentBeginIndex,
diff --git a/percent/src/android/support/percent/PercentFrameLayout.java b/percent/src/android/support/percent/PercentFrameLayout.java
index b9abd39..4190858 100644
--- a/percent/src/android/support/percent/PercentFrameLayout.java
+++ b/percent/src/android/support/percent/PercentFrameLayout.java
@@ -126,6 +126,7 @@
  *         app:layout_constraintBottom_toBottomOf="@+id/bottom_guideline" /&gt
  *
  * &lt;/android.support.constraint.ConstraintLayout&gt
+ * </pre>
  */
 @Deprecated
 public class PercentFrameLayout extends FrameLayout {
diff --git a/recommendation/Android.mk b/recommendation/Android.mk
index 99ba65f..ea819e9 100644
--- a/recommendation/Android.mk
+++ b/recommendation/Android.mk
@@ -25,7 +25,7 @@
 LOCAL_USE_AAPT2 := true
 LOCAL_MODULE := android-support-recommendation
 LOCAL_SDK_VERSION := current
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
+LOCAL_SRC_FILES := $(call all-java-files-under, src/main/java)
 LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
 LOCAL_SHARED_ANDROID_LIBRARIES := \
     android-support-v4 \
diff --git a/recommendation/build.gradle b/recommendation/build.gradle
index 61b2fb2..0c38487 100644
--- a/recommendation/build.gradle
+++ b/recommendation/build.gradle
@@ -8,12 +8,6 @@
     defaultConfig {
         minSdkVersion 21
     }
-
-    sourceSets {
-        main.java.srcDirs = ['src']
-        main.res.srcDir 'res'
-    }
-
 }
 
 supportLibrary {
diff --git a/recommendation/src/android/support/app/recommendation/ContentRecommendation.java b/recommendation/src/main/java/android/support/app/recommendation/ContentRecommendation.java
similarity index 100%
rename from recommendation/src/android/support/app/recommendation/ContentRecommendation.java
rename to recommendation/src/main/java/android/support/app/recommendation/ContentRecommendation.java
diff --git a/recommendation/src/android/support/app/recommendation/RecommendationExtender.java b/recommendation/src/main/java/android/support/app/recommendation/RecommendationExtender.java
similarity index 100%
rename from recommendation/src/android/support/app/recommendation/RecommendationExtender.java
rename to recommendation/src/main/java/android/support/app/recommendation/RecommendationExtender.java
diff --git a/room/common/src/main/java/android/arch/persistence/room/RoomWarnings.java b/room/common/src/main/java/android/arch/persistence/room/RoomWarnings.java
index 91f32e4..c64be96 100644
--- a/room/common/src/main/java/android/arch/persistence/room/RoomWarnings.java
+++ b/room/common/src/main/java/android/arch/persistence/room/RoomWarnings.java
@@ -117,4 +117,12 @@
      */
     public static final String MISSING_INDEX_ON_FOREIGN_KEY_CHILD =
             "ROOM_MISSING_FOREIGN_KEY_CHILD_INDEX";
+
+    /**
+     * Reported when a Pojo has multiple constructors, one of which is a no-arg constructor. Room
+     * will pick that one by default but will print this warning in case the constructor choice is
+     * important. You can always guide Room to use the right constructor using the @Ignore
+     * annotation.
+     */
+    public static final String DEFAULT_CONSTRUCTOR = "ROOM_DEFAULT_CONSTRUCTOR";
 }
diff --git a/room/compiler/src/main/kotlin/android/arch/persistence/room/ext/javapoet_ext.kt b/room/compiler/src/main/kotlin/android/arch/persistence/room/ext/javapoet_ext.kt
index daaa8e3..066bd1f 100644
--- a/room/compiler/src/main/kotlin/android/arch/persistence/room/ext/javapoet_ext.kt
+++ b/room/compiler/src/main/kotlin/android/arch/persistence/room/ext/javapoet_ext.kt
@@ -78,6 +78,8 @@
             ClassName.get("android.arch.persistence.room.util", "TableInfo.Column")
     val TABLE_INFO_FOREIGN_KEY : ClassName =
             ClassName.get("android.arch.persistence.room.util", "TableInfo.ForeignKey")
+    val TABLE_INFO_INDEX : ClassName =
+            ClassName.get("android.arch.persistence.room.util", "TableInfo.Index")
     val LIMIT_OFFSET_DATA_SOURCE : ClassName =
             ClassName.get("android.arch.persistence.room.paging", "LimitOffsetDataSource")
 }
diff --git a/room/compiler/src/main/kotlin/android/arch/persistence/room/processor/EntityProcessor.kt b/room/compiler/src/main/kotlin/android/arch/persistence/room/processor/EntityProcessor.kt
index 540c95a..405c6b1 100644
--- a/room/compiler/src/main/kotlin/android/arch/persistence/room/processor/EntityProcessor.kt
+++ b/room/compiler/src/main/kotlin/android/arch/persistence/room/processor/EntityProcessor.kt
@@ -247,21 +247,27 @@
         context.checker.check(candidates.isNotEmpty(), element, ProcessorErrors.MISSING_PRIMARY_KEY)
 
         // 1. If a key is not autogenerated, but is Primary key or is part of Primary key we
-        // force the @NonNull annotation
+        // force the @NonNull annotation. If the key is a single Primary Key, Integer or Long, we
+        // don't force the @NonNull annotation since SQLite will automatically generate IDs.
         // 2. If a key is autogenerate, we generate NOT NULL in table spec, but we don't require
         // @NonNull annotation on the field itself.
         candidates.filter { candidate -> !candidate.autoGenerateId }
                 .map { candidate ->
                     candidate.fields.map { field ->
-                        context.checker.check(field.nonNull, field.element,
-                                ProcessorErrors.primaryKeyNull(field.getPath()))
-                        // Validate parents for nullability
-                        var parent = field.parent
-                        while(parent != null) {
-                            val parentField = parent.field
-                            context.checker.check(parentField.nonNull, parentField.element,
-                                    ProcessorErrors.primaryKeyNull(parentField.getPath()))
-                            parent = parentField.parent
+                        if (candidate.fields.size > 1 ||
+                                (candidate.fields.size == 1
+                                        && field.affinity != SQLTypeAffinity.INTEGER)) {
+                            context.checker.check(field.nonNull, field.element,
+                                    ProcessorErrors.primaryKeyNull(field.getPath()))
+                            // Validate parents for nullability
+                            var parent = field.parent
+                            while (parent != null) {
+                                val parentField = parent.field
+                                context.checker.check(parentField.nonNull,
+                                        parentField.element,
+                                        ProcessorErrors.primaryKeyNull(parentField.getPath()))
+                                parent = parentField.parent
+                            }
                         }
                     }
                 }
@@ -518,7 +524,7 @@
         }
 
         private fun createIndexName(columnNames: List<String>, tableName: String): String {
-            return "index_" + tableName + "_" + columnNames.joinToString("_")
+            return Index.DEFAULT_PREFIX + tableName + "_" + columnNames.joinToString("_")
         }
 
         private fun extractForeignKeys(annotation: AnnotationMirror): List<ForeignKeyInput> {
diff --git a/room/compiler/src/main/kotlin/android/arch/persistence/room/processor/PojoProcessor.kt b/room/compiler/src/main/kotlin/android/arch/persistence/room/processor/PojoProcessor.kt
index 21c7fcc..535e116 100644
--- a/room/compiler/src/main/kotlin/android/arch/persistence/room/processor/PojoProcessor.kt
+++ b/room/compiler/src/main/kotlin/android/arch/persistence/room/processor/PojoProcessor.kt
@@ -16,10 +16,10 @@
 
 package android.arch.persistence.room.processor
 
-import android.arch.persistence.room.Relation
 import android.arch.persistence.room.ColumnInfo
 import android.arch.persistence.room.Embedded
 import android.arch.persistence.room.Ignore
+import android.arch.persistence.room.Relation
 import android.arch.persistence.room.ext.getAllFieldsIncludingPrivateSupers
 import android.arch.persistence.room.ext.getAnnotationValue
 import android.arch.persistence.room.ext.getAsString
@@ -35,17 +35,17 @@
 import android.arch.persistence.room.processor.cache.Cache
 import android.arch.persistence.room.vo.CallType
 import android.arch.persistence.room.vo.Constructor
-import android.arch.persistence.room.vo.Field
-import android.arch.persistence.room.vo.FieldGetter
 import android.arch.persistence.room.vo.EmbeddedField
 import android.arch.persistence.room.vo.Entity
+import android.arch.persistence.room.vo.Field
+import android.arch.persistence.room.vo.FieldGetter
 import android.arch.persistence.room.vo.FieldSetter
 import android.arch.persistence.room.vo.Pojo
+import android.arch.persistence.room.vo.Warning
 import com.google.auto.common.AnnotationMirrors
 import com.google.auto.common.MoreElements
 import com.google.auto.common.MoreTypes
 import javax.lang.model.element.ExecutableElement
-import javax.lang.model.element.Modifier
 import javax.lang.model.element.Modifier.ABSTRACT
 import javax.lang.model.element.Modifier.PRIVATE
 import javax.lang.model.element.Modifier.PROTECTED
@@ -276,14 +276,22 @@
             }
             context.logger.e(element, ProcessorErrors.MISSING_POJO_CONSTRUCTOR)
             return null
-        }
-        if (goodConstructors.size > 1) {
+        } else if (goodConstructors.size > 1) {
+            // if there is a no-arg constructor, pick it. Even though it is weird, easily happens
+            // with kotlin data classes.
+            val noArg = goodConstructors.firstOrNull { it.params.isEmpty() }
+            if (noArg != null) {
+                context.logger.w(Warning.DEFAULT_CONSTRUCTOR, element,
+                        ProcessorErrors.TOO_MANY_POJO_CONSTRUCTORS_CHOOSING_NO_ARG)
+                return noArg
+            }
             goodConstructors.forEach {
                 context.logger.e(it.element, ProcessorErrors.TOO_MANY_POJO_CONSTRUCTORS)
             }
             return null
+        } else {
+            return goodConstructors.first()
         }
-        return goodConstructors.first()
     }
 
     private fun processEmbeddedField(declaredType: DeclaredType?, variableElement: VariableElement)
diff --git a/room/compiler/src/main/kotlin/android/arch/persistence/room/processor/ProcessorErrors.kt b/room/compiler/src/main/kotlin/android/arch/persistence/room/processor/ProcessorErrors.kt
index 8058ff9..be26297 100644
--- a/room/compiler/src/main/kotlin/android/arch/persistence/room/processor/ProcessorErrors.kt
+++ b/room/compiler/src/main/kotlin/android/arch/persistence/room/processor/ProcessorErrors.kt
@@ -460,6 +460,11 @@
             unwanted constructors with @Ignore.
             """.trim()
 
+    val TOO_MANY_POJO_CONSTRUCTORS_CHOOSING_NO_ARG = """
+            There are multiple good constructors and Room will pick the no-arg constructor.
+            You can use the @Ignore annotation to eliminate unwanted constructors.
+            """.trim()
+
     val PAGING_SPECIFY_DATA_SOURCE_TYPE = "For now, Room only supports TiledDataSource class."
 
     fun primaryKeyNull(field: String): String{
diff --git a/room/compiler/src/main/kotlin/android/arch/persistence/room/vo/Index.kt b/room/compiler/src/main/kotlin/android/arch/persistence/room/vo/Index.kt
index 69f16f3..0bee2e0 100644
--- a/room/compiler/src/main/kotlin/android/arch/persistence/room/vo/Index.kt
+++ b/room/compiler/src/main/kotlin/android/arch/persistence/room/vo/Index.kt
@@ -23,7 +23,10 @@
  * Represents a processed index.
  */
 data class Index(val name : String, val unique : Boolean, val fields : List<Field>) {
-
+    companion object {
+        // should match the value in TableInfo.Index.DEFAULT_PREFIX
+        const val DEFAULT_PREFIX = "index_"
+    }
     fun createQuery(tableName : String) : String {
         val uniqueSQL = if (unique) {
             "UNIQUE"
diff --git a/room/compiler/src/main/kotlin/android/arch/persistence/room/vo/Warning.kt b/room/compiler/src/main/kotlin/android/arch/persistence/room/vo/Warning.kt
index 9cf137d..91bcb33 100644
--- a/room/compiler/src/main/kotlin/android/arch/persistence/room/vo/Warning.kt
+++ b/room/compiler/src/main/kotlin/android/arch/persistence/room/vo/Warning.kt
@@ -31,7 +31,8 @@
     INDEX_FROM_PARENT_FIELD_IS_DROPPED("ROOM_PARENT_FIELD_INDEX_IS_DROPPED"),
     RELATION_TYPE_MISMATCH("ROOM_RELATION_TYPE_MISMATCH"),
     MISSING_SCHEMA_LOCATION("ROOM_MISSING_SCHEMA_LOCATION"),
-    MISSING_INDEX_ON_FOREIGN_KEY_CHILD("ROOM_MISSING_FOREIGN_KEY_CHILD_INDEX");
+    MISSING_INDEX_ON_FOREIGN_KEY_CHILD("ROOM_MISSING_FOREIGN_KEY_CHILD_INDEX"),
+    DEFAULT_CONSTRUCTOR("ROOM_DEFAULT_CONSTRUCTOR");
 
     companion object {
         val PUBLIC_KEY_MAP = Warning.values().associateBy { it.publicKey }
diff --git a/room/compiler/src/main/kotlin/android/arch/persistence/room/writer/TableInfoValidationWriter.kt b/room/compiler/src/main/kotlin/android/arch/persistence/room/writer/TableInfoValidationWriter.kt
index fe9e743..e54f986 100644
--- a/room/compiler/src/main/kotlin/android/arch/persistence/room/writer/TableInfoValidationWriter.kt
+++ b/room/compiler/src/main/kotlin/android/arch/persistence/room/writer/TableInfoValidationWriter.kt
@@ -75,9 +75,26 @@
                         /*parent column names*/ refColumnNames)
             }
 
-            addStatement("final $T $L = new $T($S, $L, $L)",
+            val indicesSetVar = scope.getTmpVar("_indices$suffix")
+            val indicesType = ParameterizedTypeName.get(HashSet::class.typeName(),
+                    RoomTypeNames.TABLE_INFO_INDEX)
+            addStatement("final $T $L = new $T($L)", indicesType, indicesSetVar,
+                    indicesType, entity.indices.size)
+            entity.indices.forEach { index ->
+                val columnNames = index.fields
+                        .joinToString(",") { "\"${it.columnName}\"" }
+                addStatement("$L.add(new $T($S, $L, $T.asList($L)))",
+                        indicesSetVar,
+                        RoomTypeNames.TABLE_INFO_INDEX,
+                        index.name,
+                        index.unique,
+                        Arrays::class.typeName(),
+                        columnNames)
+            }
+
+            addStatement("final $T $L = new $T($S, $L, $L, $L)",
                     RoomTypeNames.TABLE_INFO, expectedInfoVar, RoomTypeNames.TABLE_INFO,
-                    entity.tableName, columnListVar, foreignKeySetVar)
+                    entity.tableName, columnListVar, foreignKeySetVar, indicesSetVar)
 
             val existingVar = scope.getTmpVar("_existing$suffix")
             addStatement("final $T $L = $T.read($N, $S)",
diff --git a/room/compiler/src/test/data/databasewriter/output/ComplexDatabase.java b/room/compiler/src/test/data/databasewriter/output/ComplexDatabase.java
index 80d73a9..cfdc110 100644
--- a/room/compiler/src/test/data/databasewriter/output/ComplexDatabase.java
+++ b/room/compiler/src/test/data/databasewriter/output/ComplexDatabase.java
@@ -11,6 +11,7 @@
 import android.arch.persistence.room.util.TableInfo;
 import android.arch.persistence.room.util.TableInfo.Column;
 import android.arch.persistence.room.util.TableInfo.ForeignKey;
+import android.arch.persistence.room.util.TableInfo.Index;
 import java.lang.IllegalStateException;
 import java.lang.Override;
 import java.lang.String;
@@ -59,7 +60,8 @@
                 _columnsUser.put("lastName", new TableInfo.Column("lastName", "TEXT", false, 0));
                 _columnsUser.put("ageColumn", new TableInfo.Column("ageColumn", "INTEGER", true, 0));
                 final HashSet<TableInfo.ForeignKey> _foreignKeysUser = new HashSet<TableInfo.ForeignKey>(0);
-                final TableInfo _infoUser = new TableInfo("User", _columnsUser, _foreignKeysUser);
+                final HashSet<TableInfo.Index> _indicesUser = new HashSet<TableInfo.Index>(0);
+                final TableInfo _infoUser = new TableInfo("User", _columnsUser, _foreignKeysUser, _indicesUser);
                 final TableInfo _existingUser = TableInfo.read(_db, "User");
                 if (! _infoUser.equals(_existingUser)) {
                     throw new IllegalStateException("Migration didn't properly handle User(foo.bar.User).\n"
diff --git a/room/compiler/src/test/kotlin/android/arch/persistence/room/processor/EntityProcessorTest.kt b/room/compiler/src/test/kotlin/android/arch/persistence/room/processor/EntityProcessorTest.kt
index 533d8c4..4abf13d 100644
--- a/room/compiler/src/test/kotlin/android/arch/persistence/room/processor/EntityProcessorTest.kt
+++ b/room/compiler/src/test/kotlin/android/arch/persistence/room/processor/EntityProcessorTest.kt
@@ -1002,6 +1002,21 @@
     }
 
     @Test
+    fun primaryKey_nonNull_notNeeded() {
+        listOf("long", "Long", "Integer", "int").forEach { type ->
+            singleEntity(
+                    """
+                @PrimaryKey
+                public $type id;
+                """) { entity, _ ->
+                assertThat(entity.primaryKey.fields.size, `is`(1))
+                assertThat(entity.primaryKey.fields.firstOrNull()?.name, `is`("id"))
+                assertThat(entity.primaryKey.autoGenerateId, `is`(false))
+            }.compilesWithoutError()
+        }
+    }
+
+    @Test
     fun primaryKey_autoGenerateBadType() {
         listOf("String", "float", "Float", "Double", "double").forEach { type ->
             singleEntity(
@@ -1270,7 +1285,7 @@
                 public String b;
 
                 static class Baz {
-                    public String bb;
+                    public Integer bb;
                 }
             }
                 """) { _, _ ->
@@ -1386,6 +1401,71 @@
     }
 
     @Test
+    fun primaryKey_integerOverrideEmbedded() {
+        val parent = JavaFileObjects.forSourceLines("foo.bar.Base",
+                """
+                package foo.bar;
+                import android.support.annotation.NonNull;
+                import android.arch.persistence.room.*;
+
+                public class Base {
+                    long baseId;
+                    String name, lastName;
+                    @Embedded(prefix = "bar_")
+                    @PrimaryKey
+                    public Foo foo;
+
+                    static class Foo {
+                        public Integer a;
+                    }
+                }
+                """)
+        singleEntity(
+                """
+                @PrimaryKey
+                public int id;
+                """,
+                baseClass = "foo.bar.Base",
+                jfos = listOf(parent)) { _, _ ->
+        }.compilesWithoutError().withNoteContaining(
+                "PrimaryKey[foo > a] is overridden by PrimaryKey[id]")
+    }
+
+    @Test
+    fun primaryKey_singleStringPrimaryKeyOverrideEmbedded() {
+        val parent = JavaFileObjects.forSourceLines("foo.bar.Base",
+                """
+                package foo.bar;
+                import android.support.annotation.NonNull;
+                import android.arch.persistence.room.*;
+
+                public class Base {
+                    long baseId;
+                    String name, lastName;
+                    @Embedded(prefix = "bar_")
+                    @PrimaryKey
+                    public Foo foo;
+
+                    static class Foo {
+                        public String a;
+                    }
+                }
+                """)
+        singleEntity(
+                """
+                @PrimaryKey
+                public int id;
+                """,
+                baseClass = "foo.bar.Base",
+                jfos = listOf(parent)) { _, _ ->
+        }.failsToCompile().withErrorContaining(ProcessorErrors.primaryKeyNull("foo"))
+                .and().withErrorContaining(ProcessorErrors.primaryKeyNull("foo > a"))
+                .and().withNoteContaining(
+                "PrimaryKey[foo > a] is overridden by PrimaryKey[id]")
+                .and().withErrorCount(2)
+    }
+
+    @Test
     fun relationInEntity() {
         singleEntity(
                 """
diff --git a/room/compiler/src/test/kotlin/android/arch/persistence/room/processor/PojoProcessorTest.kt b/room/compiler/src/test/kotlin/android/arch/persistence/room/processor/PojoProcessorTest.kt
index ebb8372..4f14fdb 100644
--- a/room/compiler/src/test/kotlin/android/arch/persistence/room/processor/PojoProcessorTest.kt
+++ b/room/compiler/src/test/kotlin/android/arch/persistence/room/processor/PojoProcessorTest.kt
@@ -694,6 +694,21 @@
     }
 
     @Test
+    fun constructor_multipleMatching_withNoArg() {
+        singleRun("""
+            String mName;
+            String mLastName;
+            public MyPojo() {
+            }
+            public MyPojo(String name, String lastName) {
+            }
+        """) { pojo ->
+            assertThat(pojo.constructor?.params?.size ?: -1, `is`(0))
+        }.compilesWithoutError().withWarningContaining(
+                ProcessorErrors.TOO_MANY_POJO_CONSTRUCTORS_CHOOSING_NO_ARG)
+    }
+
+    @Test
     fun recursion_1Level() {
         singleRun(
                 """
diff --git a/room/integration-tests/kotlintestapp/schemas/android.arch.persistence.room.integration.kotlintestapp.TestDatabase/1.json b/room/integration-tests/kotlintestapp/schemas/android.arch.persistence.room.integration.kotlintestapp.TestDatabase/1.json
index 6425de7..e6bb21c 100644
--- a/room/integration-tests/kotlintestapp/schemas/android.arch.persistence.room.integration.kotlintestapp.TestDatabase/1.json
+++ b/room/integration-tests/kotlintestapp/schemas/android.arch.persistence.room.integration.kotlintestapp.TestDatabase/1.json
@@ -2,7 +2,7 @@
   "formatVersion": 1,
   "database": {
     "version": 1,
-    "identityHash": "7beb328c9cd44a7782dfaa18c30ecb83",
+    "identityHash": "933c7e2810b0f89ab84faa68bbea5852",
     "entities": [
       {
         "tableName": "Book",
@@ -161,11 +161,37 @@
             ]
           }
         ]
+      },
+      {
+        "tableName": "NoArgClass",
+        "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `class_name` TEXT NOT NULL, PRIMARY KEY(`id`))",
+        "fields": [
+          {
+            "fieldPath": "id",
+            "columnName": "id",
+            "affinity": "INTEGER",
+            "notNull": true
+          },
+          {
+            "fieldPath": "class_name",
+            "columnName": "class_name",
+            "affinity": "TEXT",
+            "notNull": true
+          }
+        ],
+        "primaryKey": {
+          "columnNames": [
+            "id"
+          ],
+          "autoGenerate": false
+        },
+        "indices": [],
+        "foreignKeys": []
       }
     ],
     "setupQueries": [
       "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
-      "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, \"7beb328c9cd44a7782dfaa18c30ecb83\")"
+      "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, \"933c7e2810b0f89ab84faa68bbea5852\")"
     ]
   }
 }
\ No newline at end of file
diff --git a/room/integration-tests/kotlintestapp/src/androidTest/java/android/arch/persistence/room/integration/kotlintestapp/TestDatabase.kt b/room/integration-tests/kotlintestapp/src/androidTest/java/android/arch/persistence/room/integration/kotlintestapp/TestDatabase.kt
index b9344af..74d8853 100644
--- a/room/integration-tests/kotlintestapp/src/androidTest/java/android/arch/persistence/room/integration/kotlintestapp/TestDatabase.kt
+++ b/room/integration-tests/kotlintestapp/src/androidTest/java/android/arch/persistence/room/integration/kotlintestapp/TestDatabase.kt
@@ -23,9 +23,11 @@
 import android.arch.persistence.room.integration.kotlintestapp.vo.Author
 import android.arch.persistence.room.integration.kotlintestapp.vo.Book
 import android.arch.persistence.room.integration.kotlintestapp.vo.BookAuthor
+import android.arch.persistence.room.integration.kotlintestapp.vo.NoArgClass
 import android.arch.persistence.room.integration.kotlintestapp.vo.Publisher
 
-@Database(entities = arrayOf(Book::class, Author::class, Publisher::class, BookAuthor::class),
+@Database(entities = arrayOf(Book::class, Author::class, Publisher::class, BookAuthor::class,
+        NoArgClass::class),
         version = 1)
 abstract class TestDatabase : RoomDatabase() {
 
diff --git a/room/integration-tests/kotlintestapp/src/androidTest/java/android/arch/persistence/room/integration/kotlintestapp/migration/MigrationKotlinTest.kt b/room/integration-tests/kotlintestapp/src/androidTest/java/android/arch/persistence/room/integration/kotlintestapp/migration/MigrationKotlinTest.kt
index eb1a9b8..4265e19 100644
--- a/room/integration-tests/kotlintestapp/src/androidTest/java/android/arch/persistence/room/integration/kotlintestapp/migration/MigrationKotlinTest.kt
+++ b/room/integration-tests/kotlintestapp/src/androidTest/java/android/arch/persistence/room/integration/kotlintestapp/migration/MigrationKotlinTest.kt
@@ -290,6 +290,8 @@
                     + " (`id` INTEGER NOT NULL, `name` TEXT, PRIMARY KEY(`id`),"
                     + " FOREIGN KEY(`name`) REFERENCES `Entity1`(`name`)"
                     + " ON UPDATE NO ACTION ON DELETE NO ACTION DEFERRABLE INITIALLY DEFERRED)")
+            database.execSQL("CREATE UNIQUE INDEX `index_entity1` ON "
+                    + MigrationDbKotlin.Entity1.TABLE_NAME + " (`name`)")
         }
     }
 
diff --git a/room/integration-tests/kotlintestapp/src/androidTest/java/android/arch/persistence/room/integration/kotlintestapp/vo/NoArgClass.kt b/room/integration-tests/kotlintestapp/src/androidTest/java/android/arch/persistence/room/integration/kotlintestapp/vo/NoArgClass.kt
new file mode 100644
index 0000000..e1e1a7d
--- /dev/null
+++ b/room/integration-tests/kotlintestapp/src/androidTest/java/android/arch/persistence/room/integration/kotlintestapp/vo/NoArgClass.kt
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.arch.persistence.room.integration.kotlintestapp.vo
+
+import android.arch.persistence.room.Entity
+import android.arch.persistence.room.PrimaryKey
+
+/**
+ * just here to ensure that we handle no-arg constructors fine from kotlin.
+ */
+@Entity
+data class NoArgClass(@PrimaryKey var id: Long = 0, var class_name: String = "")
\ No newline at end of file
diff --git a/room/integration-tests/testapp/src/androidTest/java/android/arch/persistence/room/integration/testapp/PKeyTestDatabase.java b/room/integration-tests/testapp/src/androidTest/java/android/arch/persistence/room/integration/testapp/PKeyTestDatabase.java
index b6339a8..63b9507 100644
--- a/room/integration-tests/testapp/src/androidTest/java/android/arch/persistence/room/integration/testapp/PKeyTestDatabase.java
+++ b/room/integration-tests/testapp/src/androidTest/java/android/arch/persistence/room/integration/testapp/PKeyTestDatabase.java
@@ -23,17 +23,19 @@
 import android.arch.persistence.room.RoomDatabase;
 import android.arch.persistence.room.integration.testapp.vo.IntAutoIncPKeyEntity;
 import android.arch.persistence.room.integration.testapp.vo.IntegerAutoIncPKeyEntity;
+import android.arch.persistence.room.integration.testapp.vo.IntegerPKeyEntity;
 import android.arch.persistence.room.integration.testapp.vo.ObjectPKeyEntity;
 
 import java.util.List;
 
 @Database(entities = {IntAutoIncPKeyEntity.class, IntegerAutoIncPKeyEntity.class,
-        ObjectPKeyEntity.class}, version = 1,
+        ObjectPKeyEntity.class, IntegerPKeyEntity.class}, version = 1,
         exportSchema = false)
 public abstract class PKeyTestDatabase extends RoomDatabase {
     public abstract IntPKeyDao intPKeyDao();
-    public abstract IntegerPKeyDao integerPKeyDao();
+    public abstract IntegerAutoIncPKeyDao integerAutoIncPKeyDao();
     public abstract ObjectPKeyDao objectPKeyDao();
+    public abstract IntegerPKeyDao integerPKeyDao();
 
     @Dao
     public interface IntPKeyDao {
@@ -53,7 +55,7 @@
     }
 
     @Dao
-    public interface IntegerPKeyDao {
+    public interface IntegerAutoIncPKeyDao {
         @Insert
         void insertMe(IntegerAutoIncPKeyEntity item);
 
@@ -75,4 +77,13 @@
         @Insert
         void insertMe(ObjectPKeyEntity item);
     }
+
+    @Dao
+    public interface IntegerPKeyDao {
+        @Insert
+        void insertMe(IntegerPKeyEntity item);
+
+        @Query("select * from IntegerPKeyEntity")
+        List<IntegerPKeyEntity> loadAll();
+    }
 }
diff --git a/room/integration-tests/testapp/src/androidTest/java/android/arch/persistence/room/integration/testapp/migration/MigrationTest.java b/room/integration-tests/testapp/src/androidTest/java/android/arch/persistence/room/integration/testapp/migration/MigrationTest.java
index 725d53f..7fe2bc9 100644
--- a/room/integration-tests/testapp/src/androidTest/java/android/arch/persistence/room/integration/testapp/migration/MigrationTest.java
+++ b/room/integration-tests/testapp/src/androidTest/java/android/arch/persistence/room/integration/testapp/migration/MigrationTest.java
@@ -318,6 +318,8 @@
                     + " (`id` INTEGER NOT NULL, `name` TEXT COLLATE NOCASE, PRIMARY KEY(`id`),"
                     + " FOREIGN KEY(`name`) REFERENCES `Entity1`(`name`)"
                     + " ON UPDATE NO ACTION ON DELETE NO ACTION DEFERRABLE INITIALLY DEFERRED)");
+            database.execSQL("CREATE UNIQUE INDEX `index_entity1` ON "
+                    + MigrationDb.Entity1.TABLE_NAME + " (`name`)");
         }
     };
 
diff --git a/room/integration-tests/testapp/src/androidTest/java/android/arch/persistence/room/integration/testapp/test/PrimaryKeyTest.java b/room/integration-tests/testapp/src/androidTest/java/android/arch/persistence/room/integration/testapp/test/PrimaryKeyTest.java
index 8d213f2..fda4373 100644
--- a/room/integration-tests/testapp/src/androidTest/java/android/arch/persistence/room/integration/testapp/test/PrimaryKeyTest.java
+++ b/room/integration-tests/testapp/src/androidTest/java/android/arch/persistence/room/integration/testapp/test/PrimaryKeyTest.java
@@ -26,6 +26,7 @@
 import android.arch.persistence.room.integration.testapp.PKeyTestDatabase;
 import android.arch.persistence.room.integration.testapp.vo.IntAutoIncPKeyEntity;
 import android.arch.persistence.room.integration.testapp.vo.IntegerAutoIncPKeyEntity;
+import android.arch.persistence.room.integration.testapp.vo.IntegerPKeyEntity;
 import android.arch.persistence.room.integration.testapp.vo.ObjectPKeyEntity;
 import android.database.sqlite.SQLiteConstraintException;
 import android.support.test.InstrumentationRegistry;
@@ -37,6 +38,7 @@
 import org.junit.runner.RunWith;
 
 import java.util.Arrays;
+import java.util.List;
 
 @RunWith(AndroidJUnit4.class)
 @SmallTest
@@ -53,8 +55,8 @@
     public void integerTest() {
         IntegerAutoIncPKeyEntity entity = new IntegerAutoIncPKeyEntity();
         entity.data = "foo";
-        mDatabase.integerPKeyDao().insertMe(entity);
-        IntegerAutoIncPKeyEntity loaded = mDatabase.integerPKeyDao().getMe(1);
+        mDatabase.integerAutoIncPKeyDao().insertMe(entity);
+        IntegerAutoIncPKeyEntity loaded = mDatabase.integerAutoIncPKeyDao().getMe(1);
         assertThat(loaded, notNullValue());
         assertThat(loaded.data, is(entity.data));
     }
@@ -64,8 +66,8 @@
         IntegerAutoIncPKeyEntity entity = new IntegerAutoIncPKeyEntity();
         entity.pKey = 0;
         entity.data = "foo";
-        mDatabase.integerPKeyDao().insertMe(entity);
-        IntegerAutoIncPKeyEntity loaded = mDatabase.integerPKeyDao().getMe(0);
+        mDatabase.integerAutoIncPKeyDao().insertMe(entity);
+        IntegerAutoIncPKeyEntity loaded = mDatabase.integerAutoIncPKeyDao().getMe(0);
         assertThat(loaded, notNullValue());
         assertThat(loaded.data, is(entity.data));
     }
@@ -102,8 +104,8 @@
     public void getInsertedIdFromInteger() {
         IntegerAutoIncPKeyEntity entity = new IntegerAutoIncPKeyEntity();
         entity.data = "foo";
-        final long id = mDatabase.integerPKeyDao().insertAndGetId(entity);
-        assertThat(mDatabase.integerPKeyDao().getMe((int) id).data, is("foo"));
+        final long id = mDatabase.integerAutoIncPKeyDao().insertAndGetId(entity);
+        assertThat(mDatabase.integerAutoIncPKeyDao().getMe((int) id).data, is("foo"));
     }
 
     @Test
@@ -112,8 +114,9 @@
         entity.data = "foo";
         IntegerAutoIncPKeyEntity entity2 = new IntegerAutoIncPKeyEntity();
         entity2.data = "foo2";
-        final long[] ids = mDatabase.integerPKeyDao().insertAndGetIds(entity, entity2);
-        assertThat(mDatabase.integerPKeyDao().loadDataById(ids), is(Arrays.asList("foo", "foo2")));
+        final long[] ids = mDatabase.integerAutoIncPKeyDao().insertAndGetIds(entity, entity2);
+        assertThat(mDatabase.integerAutoIncPKeyDao().loadDataById(ids),
+                is(Arrays.asList("foo", "foo2")));
     }
 
     @Test
@@ -129,4 +132,16 @@
         assertNotNull("Was expecting an exception", throwable);
         assertThat(throwable, instanceOf(SQLiteConstraintException.class));
     }
+
+    @Test
+    public void insertNullPrimaryKeyForInteger() throws Exception {
+        IntegerPKeyEntity entity = new IntegerPKeyEntity();
+        entity.data = "data";
+        mDatabase.integerPKeyDao().insertMe(entity);
+
+        List<IntegerPKeyEntity> list = mDatabase.integerPKeyDao().loadAll();
+        assertThat(list.size(), is(1));
+        assertThat(list.get(0).data, is("data"));
+        assertNotNull(list.get(0).pKey);
+    }
 }
diff --git a/room/integration-tests/testapp/src/androidTest/java/android/arch/persistence/room/integration/testapp/vo/IntegerPKeyEntity.java b/room/integration-tests/testapp/src/androidTest/java/android/arch/persistence/room/integration/testapp/vo/IntegerPKeyEntity.java
new file mode 100644
index 0000000..cae1843
--- /dev/null
+++ b/room/integration-tests/testapp/src/androidTest/java/android/arch/persistence/room/integration/testapp/vo/IntegerPKeyEntity.java
@@ -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.
+ */
+
+package android.arch.persistence.room.integration.testapp.vo;
+
+import android.arch.persistence.room.Entity;
+import android.arch.persistence.room.PrimaryKey;
+
+@Entity
+public class IntegerPKeyEntity {
+    @PrimaryKey
+    public Integer pKey;
+    public String data;
+}
diff --git a/room/runtime/src/androidTest/java/android/arch/persistence/room/migration/TableInfoTest.java b/room/runtime/src/androidTest/java/android/arch/persistence/room/migration/TableInfoTest.java
index 8b7025b..d88c02f 100644
--- a/room/runtime/src/androidTest/java/android/arch/persistence/room/migration/TableInfoTest.java
+++ b/room/runtime/src/androidTest/java/android/arch/persistence/room/migration/TableInfoTest.java
@@ -37,6 +37,7 @@
 import org.junit.runner.RunWith;
 
 import java.io.IOException;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -179,6 +180,35 @@
                 Collections.<TableInfo.ForeignKey>emptySet())));
     }
 
+    @Test
+    public void readIndices() {
+        mDb = createDatabase(
+                "CREATE TABLE foo (n INTEGER, indexed TEXT, unique_indexed TEXT,"
+                        + "a INTEGER, b INTEGER);",
+                "CREATE INDEX foo_indexed ON foo(indexed);",
+                "CREATE UNIQUE INDEX foo_unique_indexed ON foo(unique_indexed COLLATE NOCASE"
+                        + " DESC);",
+                "CREATE INDEX " + TableInfo.Index.DEFAULT_PREFIX + "foo_composite_indexed"
+                        + " ON foo(a, b);"
+        );
+        TableInfo info = TableInfo.read(mDb, "foo");
+        assertThat(info, is(new TableInfo(
+                "foo",
+                toMap(new TableInfo.Column("n", "INTEGER", false, 0),
+                        new TableInfo.Column("indexed", "TEXT", false, 0),
+                        new TableInfo.Column("unique_indexed", "TEXT", false, 0),
+                        new TableInfo.Column("a", "INTEGER", false, 0),
+                        new TableInfo.Column("b", "INTEGER", false, 0)),
+                Collections.<TableInfo.ForeignKey>emptySet(),
+                toSet(new TableInfo.Index("index_foo_blahblah", false,
+                        Arrays.asList("a", "b")),
+                        new TableInfo.Index("foo_unique_indexed", true,
+                                Arrays.asList("unique_indexed")),
+                        new TableInfo.Index("foo_indexed", false,
+                                Arrays.asList("indexed"))))
+        ));
+    }
+
     private static Map<String, TableInfo.Column> toMap(TableInfo.Column... columns) {
         Map<String, TableInfo.Column> result = new HashMap<>();
         for (TableInfo.Column column : columns) {
@@ -187,6 +217,14 @@
         return result;
     }
 
+    private static <T> Set<T> toSet(T... ts) {
+        final HashSet<T> result = new HashSet<T>();
+        for (T t : ts) {
+            result.add(t);
+        }
+        return result;
+    }
+
     @After
     public void closeDb() throws IOException {
         if (mDb != null && mDb.isOpen()) {
diff --git a/room/runtime/src/main/java/android/arch/persistence/room/util/TableInfo.java b/room/runtime/src/main/java/android/arch/persistence/room/util/TableInfo.java
index bcd2e9e..a115147 100644
--- a/room/runtime/src/main/java/android/arch/persistence/room/util/TableInfo.java
+++ b/room/runtime/src/main/java/android/arch/persistence/room/util/TableInfo.java
@@ -20,6 +20,7 @@
 import android.database.Cursor;
 import android.os.Build;
 import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
 import android.support.annotation.RestrictTo;
 
 import java.util.ArrayList;
@@ -29,6 +30,7 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.TreeMap;
 
 /**
  * A data class that holds the information about a table.
@@ -56,11 +58,70 @@
 
     public final Set<ForeignKey> foreignKeys;
 
+    /**
+     * Sometimes, Index information is not available (older versions). If so, we skip their
+     * verification.
+     */
+    @Nullable
+    public final Set<Index> indices;
+
     @SuppressWarnings("unused")
-    public TableInfo(String name, Map<String, Column> columns, Set<ForeignKey> foreignKeys) {
+    public TableInfo(String name, Map<String, Column> columns, Set<ForeignKey> foreignKeys,
+            Set<Index> indices) {
         this.name = name;
         this.columns = Collections.unmodifiableMap(columns);
         this.foreignKeys = Collections.unmodifiableSet(foreignKeys);
+        this.indices = indices == null ? null : Collections.unmodifiableSet(indices);
+    }
+
+    /**
+     * For backward compatibility with dbs created with older versions.
+     */
+    @SuppressWarnings("unused")
+    public TableInfo(String name, Map<String, Column> columns, Set<ForeignKey> foreignKeys) {
+        this(name, columns, foreignKeys, Collections.<Index>emptySet());
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        TableInfo tableInfo = (TableInfo) o;
+
+        if (name != null ? !name.equals(tableInfo.name) : tableInfo.name != null) return false;
+        if (columns != null ? !columns.equals(tableInfo.columns) : tableInfo.columns != null) {
+            return false;
+        }
+        if (foreignKeys != null ? !foreignKeys.equals(tableInfo.foreignKeys)
+                : tableInfo.foreignKeys != null) {
+            return false;
+        }
+        if (indices == null || tableInfo.indices == null) {
+            // if one us is missing index information, seems like we couldn't acquire the
+            // information so we better skip.
+            return true;
+        }
+        return indices.equals(tableInfo.indices);
+    }
+
+    @Override
+    public int hashCode() {
+        int result = name != null ? name.hashCode() : 0;
+        result = 31 * result + (columns != null ? columns.hashCode() : 0);
+        result = 31 * result + (foreignKeys != null ? foreignKeys.hashCode() : 0);
+        // skip index, it is not reliable for comparison.
+        return result;
+    }
+
+    @Override
+    public String toString() {
+        return "TableInfo{"
+                + "name='" + name + '\''
+                + ", columns=" + columns
+                + ", foreignKeys=" + foreignKeys
+                + ", indices=" + indices
+                + '}';
     }
 
     /**
@@ -74,7 +135,8 @@
     public static TableInfo read(SupportSQLiteDatabase database, String tableName) {
         Map<String, Column> columns = readColumns(database, tableName);
         Set<ForeignKey> foreignKeys = readForeignKeys(database, tableName);
-        return new TableInfo(tableName, columns, foreignKeys);
+        Set<Index> indices = readIndices(database, tableName);
+        return new TableInfo(tableName, columns, foreignKeys, indices);
     }
 
     private static Set<ForeignKey> readForeignKeys(SupportSQLiteDatabase database,
@@ -167,34 +229,74 @@
         return columns;
     }
 
-    @Override
-    public boolean equals(Object o) {
-        if (this == o) return true;
-        if (o == null || getClass() != o.getClass()) return false;
-
-        TableInfo tableInfo = (TableInfo) o;
-
-        if (!name.equals(tableInfo.name)) return false;
-        //noinspection SimplifiableIfStatement
-        if (!columns.equals(tableInfo.columns)) return false;
-        return foreignKeys.equals(tableInfo.foreignKeys);
+    /**
+     * @return null if we cannot read the indices due to older sqlite implementations.
+     */
+    @Nullable
+    private static Set<Index> readIndices(SupportSQLiteDatabase database, String tableName) {
+        Cursor cursor = database.query("PRAGMA index_list(`" + tableName + "`)");
+        try {
+            final int nameColumnIndex = cursor.getColumnIndex("name");
+            final int originColumnIndex = cursor.getColumnIndex("origin");
+            final int uniqueIndex = cursor.getColumnIndex("unique");
+            if (nameColumnIndex == -1 || originColumnIndex == -1 || uniqueIndex == -1) {
+                // we cannot read them so better not validate any index.
+                return null;
+            }
+            HashSet<Index> indices = new HashSet<>();
+            while (cursor.moveToNext()) {
+                String origin = cursor.getString(originColumnIndex);
+                if (!"c".equals(origin)) {
+                    // Ignore auto-created indices
+                    continue;
+                }
+                String name = cursor.getString(nameColumnIndex);
+                boolean unique = cursor.getInt(uniqueIndex) == 1;
+                Index index = readIndex(database, name, unique);
+                if (index == null) {
+                    // we cannot read it properly so better not read it
+                    return null;
+                }
+                indices.add(index);
+            }
+            return indices;
+        } finally {
+            cursor.close();
+        }
     }
 
-    @Override
-    public int hashCode() {
-        int result = name.hashCode();
-        result = 31 * result + columns.hashCode();
-        result = 31 * result + foreignKeys.hashCode();
-        return result;
-    }
+    /**
+     * @return null if we cannot read the index due to older sqlite implementations.
+     */
+    @Nullable
+    private static Index readIndex(SupportSQLiteDatabase database, String name, boolean unique) {
+        Cursor cursor = database.query("PRAGMA index_xinfo(`" + name + "`)");
+        try {
+            final int seqnoColumnIndex = cursor.getColumnIndex("seqno");
+            final int cidColumnIndex = cursor.getColumnIndex("cid");
+            final int nameColumnIndex = cursor.getColumnIndex("name");
+            if (seqnoColumnIndex == -1 || cidColumnIndex == -1 || nameColumnIndex == -1) {
+                // we cannot read them so better not validate any index.
+                return null;
+            }
+            final TreeMap<Integer, String> results = new TreeMap<>();
 
-    @Override
-    public String toString() {
-        return "TableInfo{"
-                + "name='" + name + '\''
-                + ", columns=" + columns
-                + ", foreignKeys=" + foreignKeys
-                + '}';
+            while (cursor.moveToNext()) {
+                int cid = cursor.getInt(cidColumnIndex);
+                if (cid < 0) {
+                    // Ignore SQLite row ID
+                    continue;
+                }
+                int seq = cursor.getInt(seqnoColumnIndex);
+                String columnName = cursor.getString(nameColumnIndex);
+                results.put(seq, columnName);
+            }
+            final List<String> columns = new ArrayList<>(results.size());
+            columns.addAll(results.values());
+            return new Index(name, unique, columns);
+        } finally {
+            cursor.close();
+        }
     }
 
     /**
@@ -379,4 +481,65 @@
             }
         }
     }
+
+    /**
+     * Holds the information about an SQLite index
+     *
+     * @hide
+     */
+    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+    public static class Index {
+        // should match the value in Index.kt
+        public static final String DEFAULT_PREFIX = "index_";
+        public final String name;
+        public final boolean unique;
+        public final List<String> columns;
+
+        public Index(String name, boolean unique, List<String> columns) {
+            this.name = name;
+            this.unique = unique;
+            this.columns = columns;
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) return true;
+            if (o == null || getClass() != o.getClass()) return false;
+
+            Index index = (Index) o;
+            if (unique != index.unique) {
+                return false;
+            }
+            if (!columns.equals(index.columns)) {
+                return false;
+            }
+            if (name.startsWith(Index.DEFAULT_PREFIX)) {
+                return index.name.startsWith(Index.DEFAULT_PREFIX);
+            } else {
+                return name.equals(index.name);
+            }
+        }
+
+        @Override
+        public int hashCode() {
+            int result;
+            if (name.startsWith(DEFAULT_PREFIX)) {
+                result = DEFAULT_PREFIX.hashCode();
+            } else {
+                result = name.hashCode();
+            }
+            result = 31 * result + (unique ? 1 : 0);
+            result = 31 * result + columns.hashCode();
+            return result;
+        }
+
+        @Override
+        public String toString() {
+            return "Index{"
+                    + "name='" + name + '\''
+                    + ", unique=" + unique
+                    + ", columns=" + columns
+                    + '}';
+        }
+    }
 }
diff --git a/room/testing/src/main/java/android/arch/persistence/room/testing/MigrationTestHelper.java b/room/testing/src/main/java/android/arch/persistence/room/testing/MigrationTestHelper.java
index a27fe0f..18e0a14 100644
--- a/room/testing/src/main/java/android/arch/persistence/room/testing/MigrationTestHelper.java
+++ b/room/testing/src/main/java/android/arch/persistence/room/testing/MigrationTestHelper.java
@@ -29,6 +29,7 @@
 import android.arch.persistence.room.migration.bundle.EntityBundle;
 import android.arch.persistence.room.migration.bundle.FieldBundle;
 import android.arch.persistence.room.migration.bundle.ForeignKeyBundle;
+import android.arch.persistence.room.migration.bundle.IndexBundle;
 import android.arch.persistence.room.migration.bundle.SchemaBundle;
 import android.arch.persistence.room.util.TableInfo;
 import android.content.Context;
@@ -285,7 +286,19 @@
 
     private static TableInfo toTableInfo(EntityBundle entityBundle) {
         return new TableInfo(entityBundle.getTableName(), toColumnMap(entityBundle),
-                toForeignKeys(entityBundle.getForeignKeys()));
+                toForeignKeys(entityBundle.getForeignKeys()), toIndices(entityBundle.getIndices()));
+    }
+
+    private static Set<TableInfo.Index> toIndices(List<IndexBundle> indices) {
+        if (indices == null) {
+            return Collections.emptySet();
+        }
+        Set<TableInfo.Index> result = new HashSet<>();
+        for (IndexBundle bundle : indices) {
+            result.add(new TableInfo.Index(bundle.getName(), bundle.isUnique(),
+                    bundle.getColumnNames()));
+        }
+        return result;
     }
 
     private static Set<TableInfo.ForeignKey> toForeignKeys(
diff --git a/samples/SupportLeanbackDemos/AndroidManifest.xml b/samples/SupportLeanbackDemos/AndroidManifest.xml
index 7b8b946..f8a1646 100644
--- a/samples/SupportLeanbackDemos/AndroidManifest.xml
+++ b/samples/SupportLeanbackDemos/AndroidManifest.xml
@@ -115,25 +115,9 @@
             android:launchMode="singleTask"
             android:exported="true" />
 
-        <activity android:name="PlaybackOverlayActivity"
-            android:configChanges=
-                "screenSize|smallestScreenSize|screenLayout|orientation"
-            android:resizeableActivity="true"
-            android:supportsPictureInPicture="true"
-            android:launchMode="singleTask"
-            android:exported="true" />
-
-        <activity android:name="PlaybackOverlaySupportActivity"
-            android:configChanges=
-                "screenSize|smallestScreenSize|screenLayout|orientation"
-            android:resizeableActivity="true"
-            android:supportsPictureInPicture="true"
-            android:launchMode="singleTask"
-            android:exported="true" />
-
         <activity android:name="VerticalGridActivity"
-            android:theme="@style/Theme.Example.Leanback.VerticalGrid"
-            android:exported="true" />
+                  android:theme="@style/Theme.Example.Leanback.VerticalGrid"
+                  android:exported="true" />
 
         <activity android:name="VerticalGridSupportActivity"
             android:theme="@style/Theme.Example.Leanback.VerticalGrid"
diff --git a/samples/SupportLeanbackDemos/src/com/example/android/leanback/DetailsFragment.java b/samples/SupportLeanbackDemos/src/com/example/android/leanback/DetailsFragment.java
index bb282f4..c8177b6 100644
--- a/samples/SupportLeanbackDemos/src/com/example/android/leanback/DetailsFragment.java
+++ b/samples/SupportLeanbackDemos/src/com/example/android/leanback/DetailsFragment.java
@@ -116,7 +116,7 @@
                     actions.clear(ACTION_RENT);
                     dor.setItem(mPhotoItem.getTitle() + "(Rented)");
                 } else if (action.getId() == ACTION_PLAY) {
-                    Intent intent = new Intent(context, PlaybackOverlayActivity.class);
+                    Intent intent = new Intent(context, PlaybackActivity.class);
                     getActivity().startActivity(intent);
                 }
             }
diff --git a/samples/SupportLeanbackDemos/src/com/example/android/leanback/DetailsSupportFragment.java b/samples/SupportLeanbackDemos/src/com/example/android/leanback/DetailsSupportFragment.java
index 8e7a127..0f15590 100644
--- a/samples/SupportLeanbackDemos/src/com/example/android/leanback/DetailsSupportFragment.java
+++ b/samples/SupportLeanbackDemos/src/com/example/android/leanback/DetailsSupportFragment.java
@@ -119,7 +119,7 @@
                     actions.clear(ACTION_RENT);
                     dor.setItem(mPhotoItem.getTitle() + "(Rented)");
                 } else if (action.getId() == ACTION_PLAY) {
-                    Intent intent = new Intent(context, PlaybackOverlaySupportActivity.class);
+                    Intent intent = new Intent(context, PlaybackSupportActivity.class);
                     getActivity().startActivity(intent);
                 }
             }
diff --git a/samples/SupportLeanbackDemos/src/com/example/android/leanback/MainActivity.java b/samples/SupportLeanbackDemos/src/com/example/android/leanback/MainActivity.java
index 116003f..15a0769 100644
--- a/samples/SupportLeanbackDemos/src/com/example/android/leanback/MainActivity.java
+++ b/samples/SupportLeanbackDemos/src/com/example/android/leanback/MainActivity.java
@@ -121,10 +121,6 @@
                     R.string.playback_description);
             addAction(actions, PlaybackTransportControlSupportActivity.class,
                     R.string.playback_support, R.string.playback_support_description);
-            addAction(actions, PlaybackOverlayActivity.class, R.string.playbackoverlay,
-                    R.string.playbackoverlay_description);
-            addAction(actions, PlaybackOverlaySupportActivity.class,
-                    R.string.playbackoverlay_support, R.string.playbackoverlay_support_description);
             addAction(actions, VideoActivity.class, R.string.video_playback,
                     R.string.playback_description);
             addAction(actions, VideoSupportActivity.class, R.string.video_playback_support,
diff --git a/samples/SupportLeanbackDemos/src/com/example/android/leanback/NewDetailsFragment.java b/samples/SupportLeanbackDemos/src/com/example/android/leanback/NewDetailsFragment.java
index 4d5b4cc..0afe524 100644
--- a/samples/SupportLeanbackDemos/src/com/example/android/leanback/NewDetailsFragment.java
+++ b/samples/SupportLeanbackDemos/src/com/example/android/leanback/NewDetailsFragment.java
@@ -16,6 +16,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.graphics.Bitmap;
+import android.graphics.drawable.Drawable;
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.Handler;
@@ -174,7 +175,7 @@
                             mDetailsBackground.switchToVideo();
                         }
                     } else {
-                        Intent intent = new Intent(context, PlaybackOverlayActivity.class);
+                        Intent intent = new Intent(context, PlaybackActivity.class);
                         getActivity().startActivity(intent);
                     }
                 } else if (action.getId() == ACTION_RENT) {
@@ -189,14 +190,14 @@
                         setupMainVideo();
                         mDetailsBackground.switchToVideo();
                     } else {
-                        Intent intent = new Intent(context, PlaybackOverlayActivity.class);
+                        Intent intent = new Intent(context, PlaybackActivity.class);
                         getActivity().startActivity(intent);
                     }
                 } else if (action.getId() == ACTION_PLAY) {
                     if (TEST_BACKGROUND_PLAYER) {
                         mDetailsBackground.switchToVideo();
                     } else {
-                        Intent intent = new Intent(context, PlaybackOverlayActivity.class);
+                        Intent intent = new Intent(context, PlaybackActivity.class);
                         getActivity().startActivity(intent);
                     }
                 }
@@ -306,6 +307,10 @@
                         adapter.set(ACTION_BUY, mActionBuy);
                         break;
                 }
+                // one line text with icon
+                Drawable d = ResourcesCompat.getDrawable(context.getResources(),
+                        R.drawable.ic_action_a, context.getTheme());
+                adapter.set(202, new Action(202, "Top", null, d));
                 dor.setActionsAdapter(adapter);
                 mRowsAdapter.add(0, dor);
                 setSelectedPosition(0, true);
diff --git a/samples/SupportLeanbackDemos/src/com/example/android/leanback/NewDetailsSupportFragment.java b/samples/SupportLeanbackDemos/src/com/example/android/leanback/NewDetailsSupportFragment.java
index db7d594..6002cf3 100644
--- a/samples/SupportLeanbackDemos/src/com/example/android/leanback/NewDetailsSupportFragment.java
+++ b/samples/SupportLeanbackDemos/src/com/example/android/leanback/NewDetailsSupportFragment.java
@@ -19,6 +19,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.graphics.Bitmap;
+import android.graphics.drawable.Drawable;
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.Handler;
@@ -177,7 +178,7 @@
                             mDetailsBackground.switchToVideo();
                         }
                     } else {
-                        Intent intent = new Intent(context, PlaybackOverlaySupportActivity.class);
+                        Intent intent = new Intent(context, PlaybackSupportActivity.class);
                         getActivity().startActivity(intent);
                     }
                 } else if (action.getId() == ACTION_RENT) {
@@ -192,14 +193,14 @@
                         setupMainVideo();
                         mDetailsBackground.switchToVideo();
                     } else {
-                        Intent intent = new Intent(context, PlaybackOverlaySupportActivity.class);
+                        Intent intent = new Intent(context, PlaybackSupportActivity.class);
                         getActivity().startActivity(intent);
                     }
                 } else if (action.getId() == ACTION_PLAY) {
                     if (TEST_BACKGROUND_PLAYER) {
                         mDetailsBackground.switchToVideo();
                     } else {
-                        Intent intent = new Intent(context, PlaybackOverlaySupportActivity.class);
+                        Intent intent = new Intent(context, PlaybackSupportActivity.class);
                         getActivity().startActivity(intent);
                     }
                 }
@@ -309,6 +310,10 @@
                         adapter.set(ACTION_BUY, mActionBuy);
                         break;
                 }
+                // one line text with icon
+                Drawable d = ResourcesCompat.getDrawable(context.getResources(),
+                        R.drawable.ic_action_a, context.getTheme());
+                adapter.set(202, new Action(202, "Top", null, d));
                 dor.setActionsAdapter(adapter);
                 mRowsAdapter.add(0, dor);
                 setSelectedPosition(0, true);
diff --git a/samples/SupportLeanbackDemos/src/com/example/android/leanback/PlaybackControlHelper.java b/samples/SupportLeanbackDemos/src/com/example/android/leanback/PlaybackControlHelper.java
deleted file mode 100644
index e0becaa..0000000
--- a/samples/SupportLeanbackDemos/src/com/example/android/leanback/PlaybackControlHelper.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 com.example.android.leanback;
-
-import android.content.Context;
-import android.graphics.drawable.Drawable;
-import android.os.Handler;
-import android.support.v17.leanback.app.PlaybackControlGlue;
-import android.support.v17.leanback.widget.Action;
-import android.support.v17.leanback.widget.ArrayObjectAdapter;
-import android.support.v17.leanback.widget.ControlButtonPresenterSelector;
-import android.support.v17.leanback.widget.PlaybackControlsRow;
-import android.support.v17.leanback.widget.PlaybackControlsRowPresenter;
-import android.support.v17.leanback.widget.PresenterSelector;
-import android.support.v17.leanback.widget.SparseArrayObjectAdapter;
-import android.view.KeyEvent;
-import android.view.View;
-import android.widget.Toast;
-
-abstract class PlaybackControlHelper extends PlaybackControlGlue {
-    /**
-     * Change the location of the thumbs up/down controls
-     */
-    private static final boolean THUMBS_PRIMARY = true;
-
-    private static final String FAUX_TITLE = "A short song of silence";
-    private static final String FAUX_SUBTITLE = "2014";
-    private static final int FAUX_DURATION = 33 * 1000;
-
-    // These should match the playback service FF behavior
-    private static int[] sFastForwardSpeeds = { 2, 3, 4, 5 };
-
-    private boolean mIsPlaying;
-    private int mSpeed = PlaybackControlGlue.PLAYBACK_SPEED_PAUSED;
-    private long mStartTime;
-    private long mStartPosition = 0;
-
-    private PlaybackControlsRow.RepeatAction mRepeatAction;
-    private PlaybackControlsRow.ThumbsUpAction mThumbsUpAction;
-    private PlaybackControlsRow.ThumbsDownAction mThumbsDownAction;
-    private PlaybackControlsRow.PictureInPictureAction mPipAction;
-
-    private Handler mHandler = new Handler();
-    // simulating whether the media is yet prepared and ready to play
-    private boolean mInitialized = true;
-
-    private final Runnable mUpdateProgressRunnable = new Runnable() {
-        @Override
-        public void run() {
-            updateProgress();
-            mHandler.postDelayed(this, getUpdatePeriod());
-        }
-    };
-
-    PlaybackControlHelper(Context context, PlaybackOverlayFragment fragment) {
-        super(context, fragment, sFastForwardSpeeds);
-        mThumbsUpAction = new PlaybackControlsRow.ThumbsUpAction(context);
-        mThumbsUpAction.setIndex(PlaybackControlsRow.ThumbsUpAction.INDEX_OUTLINE);
-        mThumbsDownAction = new PlaybackControlsRow.ThumbsDownAction(context);
-        mThumbsDownAction.setIndex(PlaybackControlsRow.ThumbsDownAction.INDEX_OUTLINE);
-        mRepeatAction = new PlaybackControlsRow.RepeatAction(context);
-        mPipAction = new PlaybackControlsRow.PictureInPictureAction(context);
-    }
-
-    @Override
-    public PlaybackControlsRowPresenter createControlsRowAndPresenter() {
-        PlaybackControlsRowPresenter presenter = super.createControlsRowAndPresenter();
-
-        ArrayObjectAdapter adapter = new ArrayObjectAdapter(new ControlButtonPresenterSelector());
-        getControlsRow().setSecondaryActionsAdapter(adapter);
-        if (!THUMBS_PRIMARY) {
-            adapter.add(mThumbsDownAction);
-        }
-        if (android.os.Build.VERSION.SDK_INT > 23) {
-            adapter.add(mPipAction);
-        }
-        adapter.add(mRepeatAction);
-        if (!THUMBS_PRIMARY) {
-            adapter.add(mThumbsUpAction);
-        }
-
-        return presenter;
-    }
-
-    @Override
-    protected SparseArrayObjectAdapter createPrimaryActionsAdapter(
-            PresenterSelector presenterSelector) {
-        SparseArrayObjectAdapter adapter = new SparseArrayObjectAdapter(presenterSelector);
-        if (THUMBS_PRIMARY) {
-            adapter.set(PlaybackControlGlue.ACTION_CUSTOM_LEFT_FIRST, mThumbsUpAction);
-            adapter.set(PlaybackControlGlue.ACTION_CUSTOM_RIGHT_FIRST, mThumbsDownAction);
-        }
-        return adapter;
-    }
-
-    @Override
-    public void onActionClicked(Action action) {
-        if (shouldDispatchAction(action)) {
-            dispatchAction(action);
-            return;
-        }
-        super.onActionClicked(action);
-    }
-
-    @Override
-    public boolean onKey(View view, int keyCode, KeyEvent keyEvent) {
-        if (keyEvent.getAction() == KeyEvent.ACTION_DOWN) {
-            Action action = getControlsRow().getActionForKeyCode(keyEvent.getKeyCode());
-            if (shouldDispatchAction(action)) {
-                dispatchAction(action);
-                return true;
-            }
-        }
-        return super.onKey(view, keyCode, keyEvent);
-    }
-
-    private boolean shouldDispatchAction(Action action) {
-        return action == mRepeatAction || action == mThumbsUpAction || action == mThumbsDownAction;
-    }
-
-    private void dispatchAction(Action action) {
-        Toast.makeText(getContext(), action.toString(), Toast.LENGTH_SHORT).show();
-        PlaybackControlsRow.MultiAction multiAction = (PlaybackControlsRow.MultiAction) action;
-        multiAction.nextIndex();
-        notifyActionChanged(multiAction);
-    }
-
-    private void notifyActionChanged(PlaybackControlsRow.MultiAction action) {
-        int index;
-        index = getPrimaryActionsAdapter().indexOf(action);
-        if (index >= 0) {
-            getPrimaryActionsAdapter().notifyArrayItemRangeChanged(index, 1);
-        } else {
-            index = getSecondaryActionsAdapter().indexOf(action);
-            if (index >= 0) {
-                getSecondaryActionsAdapter().notifyArrayItemRangeChanged(index, 1);
-            }
-        }
-    }
-
-    private SparseArrayObjectAdapter getPrimaryActionsAdapter() {
-        return (SparseArrayObjectAdapter) getControlsRow().getPrimaryActionsAdapter();
-    }
-
-    private ArrayObjectAdapter getSecondaryActionsAdapter() {
-        return (ArrayObjectAdapter) getControlsRow().getSecondaryActionsAdapter();
-    }
-
-    @Override
-    public boolean hasValidMedia() {
-        return mInitialized;
-    }
-
-    @Override
-    public boolean isMediaPlaying() {
-        return mIsPlaying;
-    }
-
-    @Override
-    public CharSequence getMediaTitle() {
-        return FAUX_TITLE;
-    }
-
-    @Override
-    public CharSequence getMediaSubtitle() {
-        return FAUX_SUBTITLE;
-    }
-
-    @Override
-    public int getMediaDuration() {
-        return mInitialized ? FAUX_DURATION : 0;
-    }
-
-    @Override
-    public Drawable getMediaArt() {
-        return null;
-    }
-
-    @Override
-    public long getSupportedActions() {
-        return PlaybackControlGlue.ACTION_PLAY_PAUSE |
-                PlaybackControlGlue.ACTION_FAST_FORWARD |
-                PlaybackControlGlue.ACTION_REWIND;
-    }
-
-    @Override
-    public int getCurrentSpeedId() {
-        return mSpeed;
-    }
-
-    @Override
-    public int getCurrentPosition() {
-        int speed;
-        if (mSpeed == PlaybackControlGlue.PLAYBACK_SPEED_PAUSED) {
-            speed = 0;
-        } else if (mSpeed == PlaybackControlGlue.PLAYBACK_SPEED_NORMAL) {
-            speed = 1;
-        } else if (mSpeed >= PlaybackControlGlue.PLAYBACK_SPEED_FAST_L0) {
-            int index = mSpeed - PlaybackControlGlue.PLAYBACK_SPEED_FAST_L0;
-            speed = getFastForwardSpeeds()[index];
-        } else if (mSpeed <= -PlaybackControlGlue.PLAYBACK_SPEED_FAST_L0) {
-            int index = -mSpeed - PlaybackControlGlue.PLAYBACK_SPEED_FAST_L0;
-            speed = -getRewindSpeeds()[index];
-        } else {
-            return -1;
-        }
-        long position = mStartPosition +
-                (System.currentTimeMillis() - mStartTime) * speed;
-        if (position > getMediaDuration()) {
-            position = getMediaDuration();
-            onPlaybackComplete(true);
-        } else if (position < 0) {
-            position = 0;
-            onPlaybackComplete(false);
-        }
-        return (int) position;
-    }
-
-    void onPlaybackComplete(final boolean ended) {
-        mHandler.post(new Runnable() {
-            @Override
-            public void run() {
-                if (mRepeatAction.getIndex() == PlaybackControlsRow.RepeatAction.INDEX_NONE) {
-                    pausePlayback();
-                } else {
-                    startPlayback(PlaybackControlGlue.PLAYBACK_SPEED_NORMAL);
-                }
-                mStartPosition = 0;
-                onStateChanged();
-            }
-        });
-    }
-
-    @Override
-    protected void startPlayback(int speed) {
-        if (speed == mSpeed) {
-            return;
-        }
-        mStartPosition = getCurrentPosition();
-        mSpeed = speed;
-        mIsPlaying = true;
-        mStartTime = System.currentTimeMillis();
-    }
-
-    @Override
-    protected void pausePlayback() {
-        if (mSpeed == PlaybackControlGlue.PLAYBACK_SPEED_PAUSED) {
-            return;
-        }
-        mStartPosition = getCurrentPosition();
-        mSpeed = PlaybackControlGlue.PLAYBACK_SPEED_PAUSED;
-        mIsPlaying = false;
-    }
-
-    @Override
-    protected void skipToNext() {
-        // Not supported
-    }
-
-    @Override
-    protected void skipToPrevious() {
-        // Not supported
-    }
-
-    @Override
-    public void enableProgressUpdating(boolean enable) {
-        mHandler.removeCallbacks(mUpdateProgressRunnable);
-        if (enable) {
-            mUpdateProgressRunnable.run();
-        }
-    }
-
-    public boolean isInitialized() {
-        return mInitialized;
-    }
-
-    public void setInitialized(boolean initialized) {
-        if (mInitialized != initialized) {
-            mInitialized = initialized;
-            onMetadataChanged();
-            onStateChanged();
-        }
-    }
-};
diff --git a/samples/SupportLeanbackDemos/src/com/example/android/leanback/PlaybackControlSupportHelper.java b/samples/SupportLeanbackDemos/src/com/example/android/leanback/PlaybackControlSupportHelper.java
deleted file mode 100644
index 4ae5b37..0000000
--- a/samples/SupportLeanbackDemos/src/com/example/android/leanback/PlaybackControlSupportHelper.java
+++ /dev/null
@@ -1,301 +0,0 @@
-// CHECKSTYLE:OFF Generated code
-/* This file is auto-generated from PlaybackControlHelper.java.  DO NOT MODIFY. */
-
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES 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.leanback;
-
-import android.content.Context;
-import android.graphics.drawable.Drawable;
-import android.os.Handler;
-import android.support.v17.leanback.app.PlaybackControlSupportGlue;
-import android.support.v17.leanback.widget.Action;
-import android.support.v17.leanback.widget.ArrayObjectAdapter;
-import android.support.v17.leanback.widget.ControlButtonPresenterSelector;
-import android.support.v17.leanback.widget.PlaybackControlsRow;
-import android.support.v17.leanback.widget.PlaybackControlsRowPresenter;
-import android.support.v17.leanback.widget.PresenterSelector;
-import android.support.v17.leanback.widget.SparseArrayObjectAdapter;
-import android.view.KeyEvent;
-import android.view.View;
-import android.widget.Toast;
-
-abstract class PlaybackControlSupportHelper extends PlaybackControlSupportGlue {
-    /**
-     * Change the location of the thumbs up/down controls
-     */
-    private static final boolean THUMBS_PRIMARY = true;
-
-    private static final String FAUX_TITLE = "A short song of silence";
-    private static final String FAUX_SUBTITLE = "2014";
-    private static final int FAUX_DURATION = 33 * 1000;
-
-    // These should match the playback service FF behavior
-    private static int[] sFastForwardSpeeds = { 2, 3, 4, 5 };
-
-    private boolean mIsPlaying;
-    private int mSpeed = PlaybackControlSupportGlue.PLAYBACK_SPEED_PAUSED;
-    private long mStartTime;
-    private long mStartPosition = 0;
-
-    private PlaybackControlsRow.RepeatAction mRepeatAction;
-    private PlaybackControlsRow.ThumbsUpAction mThumbsUpAction;
-    private PlaybackControlsRow.ThumbsDownAction mThumbsDownAction;
-    private PlaybackControlsRow.PictureInPictureAction mPipAction;
-
-    private Handler mHandler = new Handler();
-    // simulating whether the media is yet prepared and ready to play
-    private boolean mInitialized = true;
-
-    private final Runnable mUpdateProgressRunnable = new Runnable() {
-        @Override
-        public void run() {
-            updateProgress();
-            mHandler.postDelayed(this, getUpdatePeriod());
-        }
-    };
-
-    PlaybackControlSupportHelper(Context context, PlaybackOverlaySupportFragment fragment) {
-        super(context, fragment, sFastForwardSpeeds);
-        mThumbsUpAction = new PlaybackControlsRow.ThumbsUpAction(context);
-        mThumbsUpAction.setIndex(PlaybackControlsRow.ThumbsUpAction.INDEX_OUTLINE);
-        mThumbsDownAction = new PlaybackControlsRow.ThumbsDownAction(context);
-        mThumbsDownAction.setIndex(PlaybackControlsRow.ThumbsDownAction.INDEX_OUTLINE);
-        mRepeatAction = new PlaybackControlsRow.RepeatAction(context);
-        mPipAction = new PlaybackControlsRow.PictureInPictureAction(context);
-    }
-
-    @Override
-    public PlaybackControlsRowPresenter createControlsRowAndPresenter() {
-        PlaybackControlsRowPresenter presenter = super.createControlsRowAndPresenter();
-
-        ArrayObjectAdapter adapter = new ArrayObjectAdapter(new ControlButtonPresenterSelector());
-        getControlsRow().setSecondaryActionsAdapter(adapter);
-        if (!THUMBS_PRIMARY) {
-            adapter.add(mThumbsDownAction);
-        }
-        if (android.os.Build.VERSION.SDK_INT > 23) {
-            adapter.add(mPipAction);
-        }
-        adapter.add(mRepeatAction);
-        if (!THUMBS_PRIMARY) {
-            adapter.add(mThumbsUpAction);
-        }
-
-        return presenter;
-    }
-
-    @Override
-    protected SparseArrayObjectAdapter createPrimaryActionsAdapter(
-            PresenterSelector presenterSelector) {
-        SparseArrayObjectAdapter adapter = new SparseArrayObjectAdapter(presenterSelector);
-        if (THUMBS_PRIMARY) {
-            adapter.set(PlaybackControlSupportGlue.ACTION_CUSTOM_LEFT_FIRST, mThumbsUpAction);
-            adapter.set(PlaybackControlSupportGlue.ACTION_CUSTOM_RIGHT_FIRST, mThumbsDownAction);
-        }
-        return adapter;
-    }
-
-    @Override
-    public void onActionClicked(Action action) {
-        if (shouldDispatchAction(action)) {
-            dispatchAction(action);
-            return;
-        }
-        super.onActionClicked(action);
-    }
-
-    @Override
-    public boolean onKey(View view, int keyCode, KeyEvent keyEvent) {
-        if (keyEvent.getAction() == KeyEvent.ACTION_DOWN) {
-            Action action = getControlsRow().getActionForKeyCode(keyEvent.getKeyCode());
-            if (shouldDispatchAction(action)) {
-                dispatchAction(action);
-                return true;
-            }
-        }
-        return super.onKey(view, keyCode, keyEvent);
-    }
-
-    private boolean shouldDispatchAction(Action action) {
-        return action == mRepeatAction || action == mThumbsUpAction || action == mThumbsDownAction;
-    }
-
-    private void dispatchAction(Action action) {
-        Toast.makeText(getContext(), action.toString(), Toast.LENGTH_SHORT).show();
-        PlaybackControlsRow.MultiAction multiAction = (PlaybackControlsRow.MultiAction) action;
-        multiAction.nextIndex();
-        notifyActionChanged(multiAction);
-    }
-
-    private void notifyActionChanged(PlaybackControlsRow.MultiAction action) {
-        int index;
-        index = getPrimaryActionsAdapter().indexOf(action);
-        if (index >= 0) {
-            getPrimaryActionsAdapter().notifyArrayItemRangeChanged(index, 1);
-        } else {
-            index = getSecondaryActionsAdapter().indexOf(action);
-            if (index >= 0) {
-                getSecondaryActionsAdapter().notifyArrayItemRangeChanged(index, 1);
-            }
-        }
-    }
-
-    private SparseArrayObjectAdapter getPrimaryActionsAdapter() {
-        return (SparseArrayObjectAdapter) getControlsRow().getPrimaryActionsAdapter();
-    }
-
-    private ArrayObjectAdapter getSecondaryActionsAdapter() {
-        return (ArrayObjectAdapter) getControlsRow().getSecondaryActionsAdapter();
-    }
-
-    @Override
-    public boolean hasValidMedia() {
-        return mInitialized;
-    }
-
-    @Override
-    public boolean isMediaPlaying() {
-        return mIsPlaying;
-    }
-
-    @Override
-    public CharSequence getMediaTitle() {
-        return FAUX_TITLE;
-    }
-
-    @Override
-    public CharSequence getMediaSubtitle() {
-        return FAUX_SUBTITLE;
-    }
-
-    @Override
-    public int getMediaDuration() {
-        return mInitialized ? FAUX_DURATION : 0;
-    }
-
-    @Override
-    public Drawable getMediaArt() {
-        return null;
-    }
-
-    @Override
-    public long getSupportedActions() {
-        return PlaybackControlSupportGlue.ACTION_PLAY_PAUSE |
-                PlaybackControlSupportGlue.ACTION_FAST_FORWARD |
-                PlaybackControlSupportGlue.ACTION_REWIND;
-    }
-
-    @Override
-    public int getCurrentSpeedId() {
-        return mSpeed;
-    }
-
-    @Override
-    public int getCurrentPosition() {
-        int speed;
-        if (mSpeed == PlaybackControlSupportGlue.PLAYBACK_SPEED_PAUSED) {
-            speed = 0;
-        } else if (mSpeed == PlaybackControlSupportGlue.PLAYBACK_SPEED_NORMAL) {
-            speed = 1;
-        } else if (mSpeed >= PlaybackControlSupportGlue.PLAYBACK_SPEED_FAST_L0) {
-            int index = mSpeed - PlaybackControlSupportGlue.PLAYBACK_SPEED_FAST_L0;
-            speed = getFastForwardSpeeds()[index];
-        } else if (mSpeed <= -PlaybackControlSupportGlue.PLAYBACK_SPEED_FAST_L0) {
-            int index = -mSpeed - PlaybackControlSupportGlue.PLAYBACK_SPEED_FAST_L0;
-            speed = -getRewindSpeeds()[index];
-        } else {
-            return -1;
-        }
-        long position = mStartPosition +
-                (System.currentTimeMillis() - mStartTime) * speed;
-        if (position > getMediaDuration()) {
-            position = getMediaDuration();
-            onPlaybackComplete(true);
-        } else if (position < 0) {
-            position = 0;
-            onPlaybackComplete(false);
-        }
-        return (int) position;
-    }
-
-    void onPlaybackComplete(final boolean ended) {
-        mHandler.post(new Runnable() {
-            @Override
-            public void run() {
-                if (mRepeatAction.getIndex() == PlaybackControlsRow.RepeatAction.INDEX_NONE) {
-                    pausePlayback();
-                } else {
-                    startPlayback(PlaybackControlSupportGlue.PLAYBACK_SPEED_NORMAL);
-                }
-                mStartPosition = 0;
-                onStateChanged();
-            }
-        });
-    }
-
-    @Override
-    protected void startPlayback(int speed) {
-        if (speed == mSpeed) {
-            return;
-        }
-        mStartPosition = getCurrentPosition();
-        mSpeed = speed;
-        mIsPlaying = true;
-        mStartTime = System.currentTimeMillis();
-    }
-
-    @Override
-    protected void pausePlayback() {
-        if (mSpeed == PlaybackControlSupportGlue.PLAYBACK_SPEED_PAUSED) {
-            return;
-        }
-        mStartPosition = getCurrentPosition();
-        mSpeed = PlaybackControlSupportGlue.PLAYBACK_SPEED_PAUSED;
-        mIsPlaying = false;
-    }
-
-    @Override
-    protected void skipToNext() {
-        // Not supported
-    }
-
-    @Override
-    protected void skipToPrevious() {
-        // Not supported
-    }
-
-    @Override
-    public void enableProgressUpdating(boolean enable) {
-        mHandler.removeCallbacks(mUpdateProgressRunnable);
-        if (enable) {
-            mUpdateProgressRunnable.run();
-        }
-    }
-
-    public boolean isInitialized() {
-        return mInitialized;
-    }
-
-    public void setInitialized(boolean initialized) {
-        if (mInitialized != initialized) {
-            mInitialized = initialized;
-            onMetadataChanged();
-            onStateChanged();
-        }
-    }
-};
diff --git a/samples/SupportLeanbackDemos/src/com/example/android/leanback/PlaybackOverlayActivity.java b/samples/SupportLeanbackDemos/src/com/example/android/leanback/PlaybackOverlayActivity.java
deleted file mode 100644
index 764b169..0000000
--- a/samples/SupportLeanbackDemos/src/com/example/android/leanback/PlaybackOverlayActivity.java
+++ /dev/null
@@ -1,51 +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 com.example.android.leanback;
-
-import android.app.Activity;
-import android.os.Bundle;
-
-import java.util.ArrayList;
-import java.util.List;
-
-public class PlaybackOverlayActivity extends Activity {
-    private List<PictureInPictureListener> mListeners = new ArrayList<>();
-
-    /** Called when the activity is first created. */
-    @Override
-    public void onCreate(Bundle savedInstanceState)
-    {
-        super.onCreate(savedInstanceState);
-        setContentView(R.layout.playback_controls);
-    }
-
-    @Override
-    public void onPictureInPictureModeChanged(boolean isInPictureInPictureMode) {
-        for (PictureInPictureListener listener : mListeners) {
-            listener.onPictureInPictureModeChanged(isInPictureInPictureMode);
-        }
-    }
-
-    public void registerPictureInPictureListener(PictureInPictureListener listener) {
-        mListeners.add(listener);
-    }
-
-    public void unregisterPictureInPictureListener(PictureInPictureListener listener) {
-        mListeners.remove(listener);
-    }
-
-    public interface PictureInPictureListener {
-        void onPictureInPictureModeChanged(boolean isInPictureInPictureMode);
-    }
-}
diff --git a/samples/SupportLeanbackDemos/src/com/example/android/leanback/PlaybackOverlayFragment.java b/samples/SupportLeanbackDemos/src/com/example/android/leanback/PlaybackOverlayFragment.java
deleted file mode 100644
index 369c464..0000000
--- a/samples/SupportLeanbackDemos/src/com/example/android/leanback/PlaybackOverlayFragment.java
+++ /dev/null
@@ -1,192 +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 com.example.android.leanback;
-
-import android.content.Context;
-import android.os.Build;
-import android.os.Bundle;
-import android.os.Handler;
-import android.support.v17.leanback.widget.Action;
-import android.support.v17.leanback.widget.ArrayObjectAdapter;
-import android.support.v17.leanback.widget.ClassPresenterSelector;
-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.OnItemViewClickedListener;
-import android.support.v17.leanback.widget.OnItemViewSelectedListener;
-import android.support.v17.leanback.widget.PlaybackControlsRow;
-import android.support.v17.leanback.widget.PlaybackControlsRowPresenter;
-import android.support.v17.leanback.widget.Presenter;
-import android.support.v17.leanback.widget.Row;
-import android.support.v17.leanback.widget.RowPresenter;
-import android.support.v17.leanback.widget.SparseArrayObjectAdapter;
-import android.util.Log;
-
-public class PlaybackOverlayFragment
-        extends android.support.v17.leanback.app.PlaybackOverlayFragment
-        implements PlaybackOverlayActivity.PictureInPictureListener {
-    private static final String TAG = "leanback.PlaybackControlsFragment";
-
-    /**
-     * Change this to choose a different overlay background.
-     */
-    private static final int BACKGROUND_TYPE = PlaybackOverlayFragment.BG_LIGHT;
-
-    /**
-     * Change the number of related content rows.
-     */
-    private static final int RELATED_CONTENT_ROWS = 3;
-
-    /**
-     * Change this to select hidden
-     */
-    private static final boolean SECONDARY_HIDDEN = false;
-
-    private static final int ROW_CONTROLS = 0;
-
-    private PlaybackControlHelper mGlue;
-    final Handler mHandler = new Handler();
-
-    // Artificial delay to simulate a media being prepared. The onRowChanged callback should be
-    // called and the playback row UI should be updated after this delay.
-    private static final int MEDIA_PREPARATION_DELAY = 500;
-
-    private OnItemViewClickedListener mOnItemViewClickedListener = new OnItemViewClickedListener() {
-        @Override
-        public void onItemClicked(Presenter.ViewHolder itemViewHolder, Object item,
-                                  RowPresenter.ViewHolder rowViewHolder, Row row) {
-            Log.i(TAG, "onItemClicked: " + item + " row " + row);
-            if (item instanceof Action) {
-                mGlue.onActionClicked((Action) item);
-            }
-        }
-    };
-
-    private OnItemViewSelectedListener mOnItemViewSelectedListener =
-            new OnItemViewSelectedListener() {
-                @Override
-                public void onItemSelected(Presenter.ViewHolder itemViewHolder, Object item,
-                                           RowPresenter.ViewHolder rowViewHolder, Row row) {
-                    Log.i(TAG, "onItemSelected: " + item + " row " + row);
-                }
-    };
-
-    @Override
-    public SparseArrayObjectAdapter getAdapter() {
-        return (SparseArrayObjectAdapter) super.getAdapter();
-    }
-
-    @Override
-    public void onCreate(Bundle savedInstanceState) {
-        Log.i(TAG, "onCreate");
-        super.onCreate(savedInstanceState);
-
-        setBackgroundType(BACKGROUND_TYPE);
-        setOnItemViewSelectedListener(mOnItemViewSelectedListener);
-
-        createComponents(getActivity());
-    }
-
-    private void createComponents(Context context) {
-        mGlue = new PlaybackControlHelper(context, this) {
-            @Override
-            public int getUpdatePeriod() {
-                long totalTime = getControlsRow().getDuration();
-                if (getView() == null || getView().getWidth() == 0 || totalTime <= 0) {
-                    return 1000;
-                }
-                return 16;
-            }
-
-            @Override
-            protected void onRowChanged(PlaybackControlsRow row) {
-                if (getAdapter() == null) {
-                    return;
-                }
-                int index = getAdapter().indexOf(row);
-                if (index >= 0) {
-                    getAdapter().notifyArrayItemRangeChanged(index, 1);
-                }
-            }
-
-            @Override
-            public void onActionClicked(Action action) {
-                if (action.getId() == R.id.lb_control_picture_in_picture) {
-                    if (Build.VERSION.SDK_INT >= 24) {
-                        getActivity().enterPictureInPictureMode();
-                    }
-                    return;
-                }
-                super.onActionClicked(action);
-            }
-        };
-
-        mGlue.setInitialized(false);
-        mHandler.postDelayed(new Runnable() {
-            @Override
-            public void run() {
-                mGlue.setInitialized(true);
-            }
-        }, MEDIA_PREPARATION_DELAY);
-        mGlue.setOnItemViewClickedListener(mOnItemViewClickedListener);
-
-        PlaybackControlsRowPresenter playbackControlsRowPresenter =
-                mGlue.createControlsRowAndPresenter();
-        playbackControlsRowPresenter.setSecondaryActionsHidden(SECONDARY_HIDDEN);
-        ClassPresenterSelector selector = new ClassPresenterSelector();
-        selector.addClassPresenter(ListRow.class, new ListRowPresenter());
-        selector.addClassPresenter(PlaybackControlsRow.class, playbackControlsRowPresenter);
-
-        setAdapter(new SparseArrayObjectAdapter(selector));
-
-        // Add the controls row
-        getAdapter().set(ROW_CONTROLS, mGlue.getControlsRow());
-
-        // Add related content rows
-        for (int i = 0; i < RELATED_CONTENT_ROWS; ++i) {
-            ArrayObjectAdapter listRowAdapter = new ArrayObjectAdapter(new StringPresenter());
-            listRowAdapter.add("Some related content");
-            listRowAdapter.add("Other related content");
-            HeaderItem header = new HeaderItem(i, "Row " + i);
-            getAdapter().set(ROW_CONTROLS + 1 + i, new ListRow(header, listRowAdapter));
-        }
-
-    }
-
-    @Override
-    public void onStart() {
-        super.onStart();
-        mGlue.setFadingEnabled(true);
-        mGlue.enableProgressUpdating(true);
-        ((PlaybackOverlayActivity) getActivity()).registerPictureInPictureListener(this);
-    }
-
-    @Override
-    public void onStop() {
-        mGlue.enableProgressUpdating(false);
-        ((PlaybackOverlayActivity) getActivity()).unregisterPictureInPictureListener(this);
-        super.onStop();
-    }
-
-    @Override
-    public void onPictureInPictureModeChanged(boolean isInPictureInPictureMode) {
-        if (isInPictureInPictureMode) {
-            // Hide the controls in picture-in-picture mode.
-            setFadingEnabled(true);
-            fadeOut();
-        } else {
-            setFadingEnabled(mGlue.isPlaying());
-        }
-    }
-}
diff --git a/samples/SupportLeanbackDemos/src/com/example/android/leanback/PlaybackOverlaySupportActivity.java b/samples/SupportLeanbackDemos/src/com/example/android/leanback/PlaybackOverlaySupportActivity.java
deleted file mode 100644
index 56f1df9..0000000
--- a/samples/SupportLeanbackDemos/src/com/example/android/leanback/PlaybackOverlaySupportActivity.java
+++ /dev/null
@@ -1,54 +0,0 @@
-// CHECKSTYLE:OFF Generated code
-/* This file is auto-generated from PlaybackOverlayActivity.java.  DO NOT MODIFY. */
-
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
- * in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
-package com.example.android.leanback;
-
-import android.support.v4.app.FragmentActivity;
-import android.os.Bundle;
-
-import java.util.ArrayList;
-import java.util.List;
-
-public class PlaybackOverlaySupportActivity extends FragmentActivity {
-    private List<PictureInPictureListener> mListeners = new ArrayList<>();
-
-    /** Called when the activity is first created. */
-    @Override
-    public void onCreate(Bundle savedInstanceState)
-    {
-        super.onCreate(savedInstanceState);
-        setContentView(R.layout.playback_controls_support);
-    }
-
-    @Override
-    public void onPictureInPictureModeChanged(boolean isInPictureInPictureMode) {
-        for (PictureInPictureListener listener : mListeners) {
-            listener.onPictureInPictureModeChanged(isInPictureInPictureMode);
-        }
-    }
-
-    public void registerPictureInPictureListener(PictureInPictureListener listener) {
-        mListeners.add(listener);
-    }
-
-    public void unregisterPictureInPictureListener(PictureInPictureListener listener) {
-        mListeners.remove(listener);
-    }
-
-    public interface PictureInPictureListener {
-        void onPictureInPictureModeChanged(boolean isInPictureInPictureMode);
-    }
-}
diff --git a/samples/SupportLeanbackDemos/src/com/example/android/leanback/PlaybackOverlaySupportFragment.java b/samples/SupportLeanbackDemos/src/com/example/android/leanback/PlaybackOverlaySupportFragment.java
deleted file mode 100644
index 5642557..0000000
--- a/samples/SupportLeanbackDemos/src/com/example/android/leanback/PlaybackOverlaySupportFragment.java
+++ /dev/null
@@ -1,195 +0,0 @@
-// CHECKSTYLE:OFF Generated code
-/* This file is auto-generated from PlaybackOverlayFragment.java.  DO NOT MODIFY. */
-
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
- * in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
-package com.example.android.leanback;
-
-import android.content.Context;
-import android.os.Build;
-import android.os.Bundle;
-import android.os.Handler;
-import android.support.v17.leanback.widget.Action;
-import android.support.v17.leanback.widget.ArrayObjectAdapter;
-import android.support.v17.leanback.widget.ClassPresenterSelector;
-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.OnItemViewClickedListener;
-import android.support.v17.leanback.widget.OnItemViewSelectedListener;
-import android.support.v17.leanback.widget.PlaybackControlsRow;
-import android.support.v17.leanback.widget.PlaybackControlsRowPresenter;
-import android.support.v17.leanback.widget.Presenter;
-import android.support.v17.leanback.widget.Row;
-import android.support.v17.leanback.widget.RowPresenter;
-import android.support.v17.leanback.widget.SparseArrayObjectAdapter;
-import android.util.Log;
-
-public class PlaybackOverlaySupportFragment
-        extends android.support.v17.leanback.app.PlaybackOverlaySupportFragment
-        implements PlaybackOverlaySupportActivity.PictureInPictureListener {
-    private static final String TAG = "leanback.PlaybackControlsFragment";
-
-    /**
-     * Change this to choose a different overlay background.
-     */
-    private static final int BACKGROUND_TYPE = PlaybackOverlaySupportFragment.BG_LIGHT;
-
-    /**
-     * Change the number of related content rows.
-     */
-    private static final int RELATED_CONTENT_ROWS = 3;
-
-    /**
-     * Change this to select hidden
-     */
-    private static final boolean SECONDARY_HIDDEN = false;
-
-    private static final int ROW_CONTROLS = 0;
-
-    private PlaybackControlSupportHelper mGlue;
-    final Handler mHandler = new Handler();
-
-    // Artificial delay to simulate a media being prepared. The onRowChanged callback should be
-    // called and the playback row UI should be updated after this delay.
-    private static final int MEDIA_PREPARATION_DELAY = 500;
-
-    private OnItemViewClickedListener mOnItemViewClickedListener = new OnItemViewClickedListener() {
-        @Override
-        public void onItemClicked(Presenter.ViewHolder itemViewHolder, Object item,
-                                  RowPresenter.ViewHolder rowViewHolder, Row row) {
-            Log.i(TAG, "onItemClicked: " + item + " row " + row);
-            if (item instanceof Action) {
-                mGlue.onActionClicked((Action) item);
-            }
-        }
-    };
-
-    private OnItemViewSelectedListener mOnItemViewSelectedListener =
-            new OnItemViewSelectedListener() {
-                @Override
-                public void onItemSelected(Presenter.ViewHolder itemViewHolder, Object item,
-                                           RowPresenter.ViewHolder rowViewHolder, Row row) {
-                    Log.i(TAG, "onItemSelected: " + item + " row " + row);
-                }
-    };
-
-    @Override
-    public SparseArrayObjectAdapter getAdapter() {
-        return (SparseArrayObjectAdapter) super.getAdapter();
-    }
-
-    @Override
-    public void onCreate(Bundle savedInstanceState) {
-        Log.i(TAG, "onCreate");
-        super.onCreate(savedInstanceState);
-
-        setBackgroundType(BACKGROUND_TYPE);
-        setOnItemViewSelectedListener(mOnItemViewSelectedListener);
-
-        createComponents(getActivity());
-    }
-
-    private void createComponents(Context context) {
-        mGlue = new PlaybackControlSupportHelper(context, this) {
-            @Override
-            public int getUpdatePeriod() {
-                long totalTime = getControlsRow().getDuration();
-                if (getView() == null || getView().getWidth() == 0 || totalTime <= 0) {
-                    return 1000;
-                }
-                return 16;
-            }
-
-            @Override
-            protected void onRowChanged(PlaybackControlsRow row) {
-                if (getAdapter() == null) {
-                    return;
-                }
-                int index = getAdapter().indexOf(row);
-                if (index >= 0) {
-                    getAdapter().notifyArrayItemRangeChanged(index, 1);
-                }
-            }
-
-            @Override
-            public void onActionClicked(Action action) {
-                if (action.getId() == R.id.lb_control_picture_in_picture) {
-                    if (Build.VERSION.SDK_INT >= 24) {
-                        getActivity().enterPictureInPictureMode();
-                    }
-                    return;
-                }
-                super.onActionClicked(action);
-            }
-        };
-
-        mGlue.setInitialized(false);
-        mHandler.postDelayed(new Runnable() {
-            @Override
-            public void run() {
-                mGlue.setInitialized(true);
-            }
-        }, MEDIA_PREPARATION_DELAY);
-        mGlue.setOnItemViewClickedListener(mOnItemViewClickedListener);
-
-        PlaybackControlsRowPresenter playbackControlsRowPresenter =
-                mGlue.createControlsRowAndPresenter();
-        playbackControlsRowPresenter.setSecondaryActionsHidden(SECONDARY_HIDDEN);
-        ClassPresenterSelector selector = new ClassPresenterSelector();
-        selector.addClassPresenter(ListRow.class, new ListRowPresenter());
-        selector.addClassPresenter(PlaybackControlsRow.class, playbackControlsRowPresenter);
-
-        setAdapter(new SparseArrayObjectAdapter(selector));
-
-        // Add the controls row
-        getAdapter().set(ROW_CONTROLS, mGlue.getControlsRow());
-
-        // Add related content rows
-        for (int i = 0; i < RELATED_CONTENT_ROWS; ++i) {
-            ArrayObjectAdapter listRowAdapter = new ArrayObjectAdapter(new StringPresenter());
-            listRowAdapter.add("Some related content");
-            listRowAdapter.add("Other related content");
-            HeaderItem header = new HeaderItem(i, "Row " + i);
-            getAdapter().set(ROW_CONTROLS + 1 + i, new ListRow(header, listRowAdapter));
-        }
-
-    }
-
-    @Override
-    public void onStart() {
-        super.onStart();
-        mGlue.setFadingEnabled(true);
-        mGlue.enableProgressUpdating(true);
-        ((PlaybackOverlaySupportActivity) getActivity()).registerPictureInPictureListener(this);
-    }
-
-    @Override
-    public void onStop() {
-        mGlue.enableProgressUpdating(false);
-        ((PlaybackOverlaySupportActivity) getActivity()).unregisterPictureInPictureListener(this);
-        super.onStop();
-    }
-
-    @Override
-    public void onPictureInPictureModeChanged(boolean isInPictureInPictureMode) {
-        if (isInPictureInPictureMode) {
-            // Hide the controls in picture-in-picture mode.
-            setFadingEnabled(true);
-            fadeOut();
-        } else {
-            setFadingEnabled(mGlue.isPlaying());
-        }
-    }
-}
diff --git a/samples/SupportLeanbackDemos/src/com/example/android/leanback/SearchSupportFragment.java b/samples/SupportLeanbackDemos/src/com/example/android/leanback/SearchSupportFragment.java
index b4e9b69..b638344 100644
--- a/samples/SupportLeanbackDemos/src/com/example/android/leanback/SearchSupportFragment.java
+++ b/samples/SupportLeanbackDemos/src/com/example/android/leanback/SearchSupportFragment.java
@@ -73,11 +73,13 @@
                 diff.putLong(IMAGE, newItem.getImageResourceId());
             }
 
-            if (!oldItem.getTitle().equals(newItem.getTitle())) {
+            if (oldItem.getTitle() != null && newItem.getTitle() != null
+                    && !oldItem.getTitle().equals(newItem.getTitle())) {
                 diff.putString(TITLE, newItem.getTitle());
             }
 
-            if (!oldItem.getContent().equals(newItem.getContent())) {
+            if (oldItem.getContent() != null && newItem.getContent() != null
+                    && !oldItem.getContent().equals(newItem.getContent())) {
                 diff.putString(CONTENT, newItem.getContent());
             }
             return diff;
@@ -138,11 +140,11 @@
             if (mFirstRowAdapter == null) {
                 mFirstRowAdapter = createFirstListRowAdapter();
             } else {
-                mFirstRowAdapter.setItems(createDataSetOne(), mDiffCallback);
+                mFirstRowAdapter.setItems(createDataSetOneDebug(), mDiffCallback);
             }
             mIsDataSetOnePresented = true;
         } else {
-            mFirstRowAdapter.setItems(createDataSetTwo(), mDiffCallback);
+            mFirstRowAdapter.setItems(createDataSetTwoDebug(), mDiffCallback);
             mIsDataSetOnePresented = false;
         }
         mRowsAdapter.add(new ListRow(header, mFirstRowAdapter));
@@ -180,7 +182,7 @@
 
     private ArrayObjectAdapter createFirstListRowAdapter() {
         ArrayObjectAdapter listRowAdapter = new ArrayObjectAdapter(new CardPresenter());
-        listRowAdapter.setItems(createDataSetOne(), mDiffCallback);
+        listRowAdapter.setItems(createDataSetOneDebug(), mDiffCallback);
         mIsDataSetOnePresented = true;
         return listRowAdapter;
     }
@@ -322,4 +324,31 @@
         return photoItems;
     }
 
+
+    private ArrayList<PhotoItem> createDataSetOneDebug() {
+        ArrayList<PhotoItem> photoItems = new ArrayList<>();
+        photoItems.add(new PhotoItem(
+                "Hello world",
+                R.drawable.gallery_photo_1,
+                1));
+        return photoItems;
+    }
+
+    /**
+     * Create a new data set (data set one) for the last row of this browse fragment. It will be
+     * changed by another set of data when user click one of the photo items in the list.
+     * Different with other rows in the browsing fragment, the photo item in last row all have been
+     * allocated with a unique id. And the id will be used to jduge if two photo items are the same
+     * or not.
+     *
+     * @return List of photoItem
+     */
+    private ArrayList<PhotoItem> createDataSetTwoDebug() {
+        ArrayList<PhotoItem> photoItems = new ArrayList<>();
+        photoItems.add(new PhotoItem(
+                "Hello world Hello world",
+                R.drawable.gallery_photo_1,
+                1));
+        return photoItems;
+    }
 }
diff --git a/samples/SupportWearDemos/AndroidManifest.xml b/samples/SupportWearDemos/AndroidManifest.xml
index e1309ae9..957a539 100644
--- a/samples/SupportWearDemos/AndroidManifest.xml
+++ b/samples/SupportWearDemos/AndroidManifest.xml
@@ -18,6 +18,9 @@
     package="com.example.android.support.wear" >
     <uses-feature android:name="android.hardware.type.watch" />
 
+    <!-- Required for ambient mode support. -->
+    <uses-permission android:name="android.permission.WAKE_LOCK" />
+
     <application android:icon="@drawable/app_sample_code" android:label="SupportWearDemos"
             android:theme="@android:style/Theme.DeviceDefault">
         <activity android:name=".app.SimpleWearableRecyclerViewDemo" />
@@ -25,12 +28,15 @@
         <activity android:name=".app.CircularProgressLayoutDemo" />
         <activity android:name=".app.RoundedDrawableDemo" />
         <activity android:name=".app.drawers.WearableDrawersDemo" android:exported="true" />
+        <activity android:name=".app.AmbientModeDemo" />
         <activity android:name=".app.MainDemoActivity">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
                 <category android:name="android.intent.category.LAUNCHER" />
             </intent-filter>
         </activity>
+
+        <uses-library android:name="com.google.android.wearable" android:required="true" />
     </application>
 
 </manifest>
diff --git a/samples/SupportWearDemos/res/layout/ambient_demo.xml b/samples/SupportWearDemos/res/layout/ambient_demo.xml
new file mode 100644
index 0000000..ed7c01f
--- /dev/null
+++ b/samples/SupportWearDemos/res/layout/ambient_demo.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.
+  -->
+<merge xmlns:android="http://schemas.android.com/apk/res/android"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent" >
+    <TextView
+        android:id="@+id/ambient_text"
+        android:layout_gravity="center"
+        android:layout_height="wrap_content"
+        android:layout_width="wrap_content"
+        android:textColor="@android:color/holo_orange_dark"
+        android:text="hello world!!"/>
+</merge>
diff --git a/samples/SupportWearDemos/src/com/example/android/support/wear/app/AmbientModeDemo.java b/samples/SupportWearDemos/src/com/example/android/support/wear/app/AmbientModeDemo.java
new file mode 100644
index 0000000..70270d2
--- /dev/null
+++ b/samples/SupportWearDemos/src/com/example/android/support/wear/app/AmbientModeDemo.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.example.android.support.wear.app;
+
+import android.graphics.Color;
+import android.os.Bundle;
+import android.support.v4.app.FragmentActivity;
+import android.support.wear.ambient.AmbientMode;
+import android.widget.TextView;
+
+import com.example.android.support.wear.R;
+
+/**
+ * Main activity for the AmbientMode demo.
+ */
+public class AmbientModeDemo extends FragmentActivity implements
+        AmbientMode.AmbientCallbackProvider {
+    private TextView mStateTextView;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.ambient_demo);
+        mStateTextView = findViewById(R.id.ambient_text);
+        AmbientMode.AmbientController controller = AmbientMode.attachAmbientSupport(this);
+        controller.setAutoResumeEnabled(true);
+    }
+
+    @Override
+    public AmbientMode.AmbientCallback getAmbientCallback() {
+        return new MyAmbientCallback();
+    }
+
+    private class MyAmbientCallback extends AmbientMode.AmbientCallback {
+
+        @Override
+        public void onEnterAmbient(Bundle ambientDetails) {
+            // Handle entering ambient mode
+            mStateTextView.setText("Ambient");
+            mStateTextView.setTextColor(Color.WHITE);
+            mStateTextView.getPaint().setAntiAlias(false);
+        }
+
+        @Override
+        public void onExitAmbient() {
+            // Handle exiting ambient mode
+            mStateTextView.setText("Interactive");
+            mStateTextView.setTextColor(Color.GREEN);
+            mStateTextView.getPaint().setAntiAlias(true);
+        }
+    }
+}
diff --git a/samples/SupportWearDemos/src/com/example/android/support/wear/app/MainDemoActivity.java b/samples/SupportWearDemos/src/com/example/android/support/wear/app/MainDemoActivity.java
index 398adc1..0227559 100644
--- a/samples/SupportWearDemos/src/com/example/android/support/wear/app/MainDemoActivity.java
+++ b/samples/SupportWearDemos/src/com/example/android/support/wear/app/MainDemoActivity.java
@@ -62,6 +62,8 @@
                 this, WearableDrawersDemo.class));
         contentMap.put("Rounded Drawable", new Intent(
                 this, RoundedDrawableDemo.class));
+        contentMap.put("Ambient Fragment", new Intent(
+                this, AmbientModeDemo.class));
 
         return contentMap;
     }
diff --git a/tv-provider/Android.mk b/tv-provider/Android.mk
index 4fa8af4..9427d0d 100644
--- a/tv-provider/Android.mk
+++ b/tv-provider/Android.mk
@@ -23,7 +23,7 @@
 LOCAL_USE_AAPT2 := true
 LOCAL_MODULE := android-support-tv-provider
 LOCAL_SDK_VERSION := $(SUPPORT_CURRENT_SDK_VERSION)
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
+LOCAL_SRC_FILES := $(call all-java-files-under, src/main/java)
 LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
 LOCAL_SHARED_ANDROID_LIBRARIES := \
     android-support-compat \
diff --git a/tv-provider/build.gradle b/tv-provider/build.gradle
index 42d2d90..0545458 100644
--- a/tv-provider/build.gradle
+++ b/tv-provider/build.gradle
@@ -11,11 +11,6 @@
     defaultConfig {
         minSdkVersion 21
     }
-
-    sourceSets {
-        main.java.srcDirs = ['src']
-        main.res.srcDir 'res'
-    }
 }
 
 supportLibrary {
diff --git a/tv-provider/lint-baseline.xml b/tv-provider/lint-baseline.xml
index d5fde3a..9814796 100644
--- a/tv-provider/lint-baseline.xml
+++ b/tv-provider/lint-baseline.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<issues format="4" by="lint 3.0.0-alpha9">
+<issues format="4" by="lint 3.0.0-beta6">
 
     <issue
         id="WrongConstant"
@@ -7,8 +7,8 @@
         errorLine1="        return i == null ? INVALID_INT_VALUE : i;"
         errorLine2="                           ~~~~~~~~~~~~~~~~~">
         <location
-            file="src/android/support/media/tv/BasePreviewProgram.java"
-            line="129"
+            file="src/main/java/android/support/media/tv/BasePreviewProgram.java"
+            line="130"
             column="28"/>
     </issue>
 
@@ -18,8 +18,8 @@
         errorLine1="        return i == null ? INVALID_INT_VALUE : i;"
         errorLine2="                           ~~~~~~~~~~~~~~~~~">
         <location
-            file="src/android/support/media/tv/BasePreviewProgram.java"
-            line="139"
+            file="src/main/java/android/support/media/tv/BasePreviewProgram.java"
+            line="140"
             column="28"/>
     </issue>
 
@@ -29,8 +29,8 @@
         errorLine1="        return i == null ? INVALID_INT_VALUE : i;"
         errorLine2="                           ~~~~~~~~~~~~~~~~~">
         <location
-            file="src/android/support/media/tv/BasePreviewProgram.java"
-            line="149"
+            file="src/main/java/android/support/media/tv/BasePreviewProgram.java"
+            line="150"
             column="28"/>
     </issue>
 
@@ -40,8 +40,8 @@
         errorLine1="        return i == null ? INVALID_INT_VALUE : i;"
         errorLine2="                           ~~~~~~~~~~~~~~~~~">
         <location
-            file="src/android/support/media/tv/BasePreviewProgram.java"
-            line="167"
+            file="src/main/java/android/support/media/tv/BasePreviewProgram.java"
+            line="168"
             column="28"/>
     </issue>
 
@@ -51,8 +51,8 @@
         errorLine1="        return i == null ? INVALID_INT_VALUE : i;"
         errorLine2="                           ~~~~~~~~~~~~~~~~~">
         <location
-            file="src/android/support/media/tv/BasePreviewProgram.java"
-            line="218"
+            file="src/main/java/android/support/media/tv/BasePreviewProgram.java"
+            line="219"
             column="28"/>
     </issue>
 
@@ -62,7 +62,7 @@
         errorLine1="        return i == null ? INVALID_INT_VALUE : i;"
         errorLine2="                           ~~~~~~~~~~~~~~~~~">
         <location
-            file="src/android/support/media/tv/BaseProgram.java"
+            file="src/main/java/android/support/media/tv/BaseProgram.java"
             line="257"
             column="28"/>
     </issue>
@@ -73,7 +73,7 @@
         errorLine1="            mValues.put(Programs.COLUMN_BROADCAST_GENRE, Programs.Genres.encode(genres));"
         errorLine2="                                                                                ~~~~~~">
         <location
-            file="src/android/support/media/tv/Program.java"
+            file="src/main/java/android/support/media/tv/Program.java"
             line="286"
             column="81"/>
     </issue>
@@ -84,7 +84,7 @@
         errorLine1="        return i == null ? INVALID_INT_VALUE : i;"
         errorLine2="                           ~~~~~~~~~~~~~~~~~">
         <location
-            file="src/android/support/media/tv/WatchNextProgram.java"
+            file="src/main/java/android/support/media/tv/WatchNextProgram.java"
             line="99"
             column="28"/>
     </issue>
diff --git a/tv-provider/src/android/support/media/tv/BasePreviewProgram.java b/tv-provider/src/main/java/android/support/media/tv/BasePreviewProgram.java
similarity index 100%
rename from tv-provider/src/android/support/media/tv/BasePreviewProgram.java
rename to tv-provider/src/main/java/android/support/media/tv/BasePreviewProgram.java
diff --git a/tv-provider/src/android/support/media/tv/BaseProgram.java b/tv-provider/src/main/java/android/support/media/tv/BaseProgram.java
similarity index 100%
rename from tv-provider/src/android/support/media/tv/BaseProgram.java
rename to tv-provider/src/main/java/android/support/media/tv/BaseProgram.java
diff --git a/tv-provider/src/android/support/media/tv/Channel.java b/tv-provider/src/main/java/android/support/media/tv/Channel.java
similarity index 100%
rename from tv-provider/src/android/support/media/tv/Channel.java
rename to tv-provider/src/main/java/android/support/media/tv/Channel.java
diff --git a/tv-provider/src/android/support/media/tv/ChannelLogoUtils.java b/tv-provider/src/main/java/android/support/media/tv/ChannelLogoUtils.java
similarity index 100%
rename from tv-provider/src/android/support/media/tv/ChannelLogoUtils.java
rename to tv-provider/src/main/java/android/support/media/tv/ChannelLogoUtils.java
diff --git a/tv-provider/src/android/support/media/tv/CollectionUtils.java b/tv-provider/src/main/java/android/support/media/tv/CollectionUtils.java
similarity index 100%
rename from tv-provider/src/android/support/media/tv/CollectionUtils.java
rename to tv-provider/src/main/java/android/support/media/tv/CollectionUtils.java
diff --git a/tv-provider/src/android/support/media/tv/PreviewProgram.java b/tv-provider/src/main/java/android/support/media/tv/PreviewProgram.java
similarity index 100%
rename from tv-provider/src/android/support/media/tv/PreviewProgram.java
rename to tv-provider/src/main/java/android/support/media/tv/PreviewProgram.java
diff --git a/tv-provider/src/android/support/media/tv/Program.java b/tv-provider/src/main/java/android/support/media/tv/Program.java
similarity index 100%
rename from tv-provider/src/android/support/media/tv/Program.java
rename to tv-provider/src/main/java/android/support/media/tv/Program.java
diff --git a/tv-provider/src/android/support/media/tv/TvContractCompat.java b/tv-provider/src/main/java/android/support/media/tv/TvContractCompat.java
similarity index 100%
rename from tv-provider/src/android/support/media/tv/TvContractCompat.java
rename to tv-provider/src/main/java/android/support/media/tv/TvContractCompat.java
diff --git a/tv-provider/src/android/support/media/tv/TvContractUtils.java b/tv-provider/src/main/java/android/support/media/tv/TvContractUtils.java
similarity index 100%
rename from tv-provider/src/android/support/media/tv/TvContractUtils.java
rename to tv-provider/src/main/java/android/support/media/tv/TvContractUtils.java
diff --git a/tv-provider/src/android/support/media/tv/WatchNextProgram.java b/tv-provider/src/main/java/android/support/media/tv/WatchNextProgram.java
similarity index 100%
rename from tv-provider/src/android/support/media/tv/WatchNextProgram.java
rename to tv-provider/src/main/java/android/support/media/tv/WatchNextProgram.java
diff --git a/v17/leanback/api/26.0.0.ignore b/v17/leanback/api/26.0.0.ignore
new file mode 100644
index 0000000..81d1fe5
--- /dev/null
+++ b/v17/leanback/api/26.0.0.ignore
@@ -0,0 +1,2 @@
+036d6d4
+07abbac
diff --git a/v17/leanback/api/current.txt b/v17/leanback/api/current.txt
index 00e764b..4ee4d94 100644
--- a/v17/leanback/api/current.txt
+++ b/v17/leanback/api/current.txt
@@ -658,53 +658,6 @@
     method protected final void startEnterAnimation(boolean);
   }
 
-  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 deprecated void fadeOut();
@@ -746,62 +699,6 @@
     method public void setPlaybackSeekUiClient(android.support.v17.leanback.widget.PlaybackSeekUi.Client);
   }
 
-  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 deprecated void fadeOut();
@@ -926,7 +823,7 @@
     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 deprecated void setSpeechRecognitionCallback(android.support.v17.leanback.widget.SpeechRecognitionCallback);
     method public void setTitle(java.lang.String);
     method public void startRecognition();
   }
@@ -956,7 +853,7 @@
     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 deprecated void setSpeechRecognitionCallback(android.support.v17.leanback.widget.SpeechRecognitionCallback);
     method public void setTitle(java.lang.String);
     method public void startRecognition();
   }
@@ -2903,7 +2800,7 @@
     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 deprecated 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();
@@ -3059,7 +2956,7 @@
     method public void showNotListening();
   }
 
-  public abstract interface SpeechRecognitionCallback {
+  public abstract deprecated interface SpeechRecognitionCallback {
     method public abstract void recognizeSpeech();
   }
 
diff --git a/v17/leanback/src/android/support/v17/leanback/app/BaseFragment.java b/v17/leanback/src/android/support/v17/leanback/app/BaseFragment.java
index 278c1ac..bdb213f 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/BaseFragment.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/BaseFragment.java
@@ -18,6 +18,8 @@
 
 import android.annotation.SuppressLint;
 import android.os.Bundle;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
 import android.support.v17.leanback.transition.TransitionHelper;
 import android.support.v17.leanback.transition.TransitionListener;
 import android.support.v17.leanback.util.StateMachine;
@@ -180,7 +182,7 @@
     }
 
     @Override
-    public void onViewCreated(View view, Bundle savedInstanceState) {
+    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
         super.onViewCreated(view, savedInstanceState);
         mStateMachine.fireEvent(EVT_ON_CREATEVIEW);
     }
diff --git a/v17/leanback/src/android/support/v17/leanback/app/BaseRowFragment.java b/v17/leanback/src/android/support/v17/leanback/app/BaseRowFragment.java
index ac67d2b..2d79f3e 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/BaseRowFragment.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/BaseRowFragment.java
@@ -17,6 +17,8 @@
 package android.support.v17.leanback.app;
 
 import android.os.Bundle;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
 import android.support.v17.leanback.widget.ItemBridgeAdapter;
 import android.support.v17.leanback.widget.ListRow;
 import android.support.v17.leanback.widget.ObjectAdapter;
@@ -78,7 +80,7 @@
     }
 
     @Override
-    public void onViewCreated(View view, Bundle savedInstanceState) {
+    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
         if (savedInstanceState != null) {
             mSelectedPosition = savedInstanceState.getInt(CURRENT_SELECTED_POSITION, -1);
         }
diff --git a/v17/leanback/src/android/support/v17/leanback/app/BrandedFragment.java b/v17/leanback/src/android/support/v17/leanback/app/BrandedFragment.java
index b80bd7c..1f6ad29 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/BrandedFragment.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/BrandedFragment.java
@@ -18,6 +18,8 @@
 
 import android.graphics.drawable.Drawable;
 import android.os.Bundle;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
 import android.support.v17.leanback.R;
 import android.support.v17.leanback.widget.SearchOrbView;
 import android.support.v17.leanback.widget.TitleHelper;
@@ -146,7 +148,7 @@
     }
 
     @Override
-    public void onViewCreated(View view, Bundle savedInstanceState) {
+    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
         super.onViewCreated(view, savedInstanceState);
         if (savedInstanceState != null) {
             mShowingTitle = savedInstanceState.getBoolean(TITLE_SHOW);
diff --git a/v17/leanback/src/android/support/v17/leanback/app/HeadersFragment.java b/v17/leanback/src/android/support/v17/leanback/app/HeadersFragment.java
index 12cdcd7..dd037d2 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/HeadersFragment.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/HeadersFragment.java
@@ -23,6 +23,8 @@
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.GradientDrawable;
 import android.os.Bundle;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
 import android.support.v17.leanback.R;
 import android.support.v17.leanback.widget.ClassPresenterSelector;
 import android.support.v17.leanback.widget.DividerPresenter;
@@ -163,7 +165,7 @@
     }
 
     @Override
-    public void onViewCreated(View view, Bundle savedInstanceState) {
+    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
         super.onViewCreated(view, savedInstanceState);
         final VerticalGridView listView = getVerticalGridView();
         if (listView == null) {
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 74affd6..b69d5a7 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/OnboardingFragment.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/OnboardingFragment.java
@@ -29,6 +29,7 @@
 import android.graphics.Color;
 import android.os.Bundle;
 import android.support.annotation.ColorInt;
+import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
 import android.support.v17.leanback.R;
 import android.support.v17.leanback.widget.PagingIndicator;
@@ -353,7 +354,7 @@
     }
 
     @Override
-    public void onViewCreated(View view, Bundle savedInstanceState) {
+    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
         super.onViewCreated(view, savedInstanceState);
         if (savedInstanceState == null) {
             mCurrentPageIndex = 0;
diff --git a/v17/leanback/src/android/support/v17/leanback/app/PlaybackControlGlue.java b/v17/leanback/src/android/support/v17/leanback/app/PlaybackControlGlue.java
deleted file mode 100644
index d74fd11..0000000
--- a/v17/leanback/src/android/support/v17/leanback/app/PlaybackControlGlue.java
+++ /dev/null
@@ -1,337 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
- * in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
-package android.support.v17.leanback.app;
-
-import android.content.Context;
-import android.support.v17.leanback.media.PlaybackGlueHost;
-import android.support.v17.leanback.widget.Action;
-import android.support.v17.leanback.widget.OnActionClickedListener;
-import android.support.v17.leanback.widget.OnItemViewClickedListener;
-import android.support.v17.leanback.widget.PlaybackControlsRow;
-import android.support.v17.leanback.widget.PlaybackControlsRowPresenter;
-import android.support.v17.leanback.widget.PlaybackRowPresenter;
-import android.support.v17.leanback.widget.Presenter;
-import android.support.v17.leanback.widget.PresenterSelector;
-import android.support.v17.leanback.widget.Row;
-import android.support.v17.leanback.widget.RowPresenter;
-import android.support.v17.leanback.widget.SparseArrayObjectAdapter;
-import android.view.InputEvent;
-import android.view.KeyEvent;
-import android.view.View;
-
-/**
- * A helper class for managing a {@link android.support.v17.leanback.widget.PlaybackControlsRow}
- * and {@link PlaybackGlueHost} that implements a
- * recommended approach to handling standard playback control actions such as play/pause,
- * fast forward/rewind at progressive speed levels, and skip to next/previous. This helper class
- * is a glue layer in that manages the configuration of and interaction between the
- * leanback UI components by defining a functional interface to the media player.
- *
- * <p>You can instantiate a concrete subclass such as MediaPlayerGlue or you must
- * subclass this abstract helper.  To create a subclass you must implement all of the
- * abstract methods and the subclass must invoke {@link #onMetadataChanged()} and
- * {@link #onStateChanged()} appropriately.
- * </p>
- *
- * <p>To use an instance of the glue layer, first construct an instance.  Constructor parameters
- * inform the glue what speed levels are supported for fast forward/rewind.
- * </p>
- *
- * <p>If you have your own controls row you must pass it to {@link #setControlsRow}.
- * The row will be updated by the glue layer based on the media metadata and playback state.
- * Alternatively, you may call {@link #createControlsRowAndPresenter()} which will set a controls
- * row and return a row presenter you can use to present the row.
- * </p>
- *
- * <p>The helper sets a {@link android.support.v17.leanback.widget.SparseArrayObjectAdapter}
- * on the controls row as the primary actions adapter, and adds actions to it. You can provide
- * additional actions by overriding {@link #createPrimaryActionsAdapter}. This helper does not
- * deal in secondary actions so those you may add separately.
- * </p>
- *
- * <p>Provide a click listener on your fragment and if an action is clicked, call
- * {@link #onActionClicked}. If you set a listener by calling {@link #setOnItemViewClickedListener},
- * your listener will be called for all unhandled actions.
- * </p>
- *
- * <p>This helper implements a key event handler. If you pass a
- * {@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)}.
- * </p>
- *
- * <p>To update the controls row progress during playback, override {@link #enableProgressUpdating}
- * to manage the lifecycle of a periodic callback to {@link #updateProgress()}.
- * {@link #getUpdatePeriod()} provides a recommended update period.
- * </p>
- * @deprecated Use {@link android.support.v17.leanback.media.PlaybackControlGlue}
- */
-@Deprecated
-public abstract class PlaybackControlGlue extends
-        android.support.v17.leanback.media.PlaybackControlGlue {
-
-    OnItemViewClickedListener mExternalOnItemViewClickedListener;
-
-    /**
-     * Constructor for the glue.
-     *
-     * @param context
-     * @param seekSpeeds Array of seek speeds for fast forward and rewind.
-     */
-    public PlaybackControlGlue(Context context, int[] seekSpeeds) {
-        super(context, seekSpeeds, seekSpeeds);
-    }
-
-    /**
-     * Constructor for the glue.
-     *
-     * @param context
-     * @param fastForwardSpeeds Array of seek speeds for fast forward.
-     * @param rewindSpeeds Array of seek speeds for rewind.
-     */
-    public PlaybackControlGlue(Context context,
-                               int[] fastForwardSpeeds,
-                               int[] rewindSpeeds) {
-        super(context, fastForwardSpeeds, rewindSpeeds);
-    }
-
-    /**
-     * Constructor for the glue.
-     *
-     * @param context
-     * @param fragment Optional; if using a {@link PlaybackOverlayFragment}, pass it in.
-     * @param seekSpeeds Array of seek speeds for fast forward and rewind.
-     */
-    public PlaybackControlGlue(Context context,
-                               PlaybackOverlayFragment fragment,
-                               int[] seekSpeeds) {
-        this(context, fragment, seekSpeeds, seekSpeeds);
-    }
-
-    /**
-     * Constructor for the glue.
-     *
-     * @param context
-     * @param fragment Optional; if using a {@link PlaybackOverlayFragment}, pass it in.
-     * @param fastForwardSpeeds Array of seek speeds for fast forward.
-     * @param rewindSpeeds Array of seek speeds for rewind.
-     */
-    public PlaybackControlGlue(Context context,
-                               PlaybackOverlayFragment fragment,
-                               int[] fastForwardSpeeds,
-                               int[] rewindSpeeds) {
-        super(context, fastForwardSpeeds, rewindSpeeds);
-        setHost(fragment == null ? (PlaybackGlueHost) null : new PlaybackGlueHostOld(fragment));
-    }
-
-    @Override
-    protected void onAttachedToHost(PlaybackGlueHost host) {
-        super.onAttachedToHost(host);
-        if (host instanceof PlaybackGlueHostOld) {
-            ((PlaybackGlueHostOld) host).mGlue = this;
-        }
-    }
-
-    /**
-     * Returns the fragment.
-     */
-    public PlaybackOverlayFragment getFragment() {
-        if (getHost() instanceof PlaybackGlueHostOld) {
-            return ((PlaybackGlueHostOld)getHost()).mFragment;
-        }
-        return null;
-    }
-
-    /**
-     * Start playback at the given speed.
-     * @deprecated use {@link #play()} instead.
-     *
-     * @param speed The desired playback speed.  For normal playback this will be
-     *              {@link #PLAYBACK_SPEED_NORMAL}; higher positive values for fast forward,
-     *              and negative values for rewind.
-     */
-    @Deprecated
-    protected void startPlayback(int speed) {}
-
-    /**
-     * Pause playback.
-     * @deprecated use {@link #pause()} instead.
-     */
-    @Deprecated
-    protected void pausePlayback() {}
-
-    /**
-     * Skip to the next track.
-     * @deprecated use {@link #next()} instead.
-     */
-    @Deprecated
-    protected void skipToNext() {}
-
-    /**
-     * Skip to the previous track.
-     * @deprecated use {@link #previous()} instead.
-     */
-    @Deprecated
-    protected void skipToPrevious() {}
-
-    @Override
-    public final void next() {
-        skipToNext();
-    }
-
-    @Override
-    public final void previous() {
-        skipToPrevious();
-    }
-
-    @Override
-    public final void play(int speed) {
-        startPlayback(speed);
-    }
-
-    @Override
-    public final void pause() {
-        pausePlayback();
-    }
-
-    /**
-     * This method invoked when the playback controls row has changed. The adapter
-     * containing this row should be notified.
-     */
-    protected void onRowChanged(PlaybackControlsRow row) {
-    }
-
-    /**
-     * Set the {@link OnItemViewClickedListener} to be called if the click event
-     * is not handled internally.
-     * @param listener
-     * @deprecated Don't call this. Instead use the listener on the fragment yourself.
-     */
-    @Deprecated
-    public void setOnItemViewClickedListener(OnItemViewClickedListener listener) {
-        mExternalOnItemViewClickedListener = listener;
-    }
-
-    /**
-     * Returns the {@link OnItemViewClickedListener}.
-     * @deprecated Don't call this. Instead use the listener on the fragment yourself.
-     */
-    @Deprecated
-    public OnItemViewClickedListener getOnItemViewClickedListener() {
-        return mExternalOnItemViewClickedListener;
-    }
-
-    @Override
-    protected void onCreateControlsRowAndPresenter() {
-        // backward compatible, we dont create row / presenter by default.
-        // User is expected to call createControlsRowAndPresenter() or setControlsRow()
-        // explicitly.
-    }
-
-    /**
-     * Helper method for instantiating a
-     * {@link android.support.v17.leanback.widget.PlaybackControlsRow} and corresponding
-     * {@link android.support.v17.leanback.widget.PlaybackControlsRowPresenter}.
-     */
-    public PlaybackControlsRowPresenter createControlsRowAndPresenter() {
-        super.onCreateControlsRowAndPresenter();
-        return getControlsRowPresenter();
-    }
-
-    @Override
-    protected SparseArrayObjectAdapter createPrimaryActionsAdapter(
-            PresenterSelector presenterSelector) {
-        return super.createPrimaryActionsAdapter(presenterSelector);
-    }
-
-    /**
-     * Interface allowing the application to handle input events.
-     * @deprecated Use
-     * {@link PlaybackGlueHost#setOnKeyInterceptListener(View.OnKeyListener)}.
-     */
-    @Deprecated
-    public interface InputEventHandler {
-        /**
-         * Called when an {@link InputEvent} is received.
-         *
-         * @return If the event should be consumed, return true. To allow the event to
-         * continue on to the next handler, return false.
-         */
-        boolean handleInputEvent(InputEvent event);
-    }
-
-    static final class PlaybackGlueHostOld extends PlaybackGlueHost {
-        final PlaybackOverlayFragment mFragment;
-        PlaybackControlGlue mGlue;
-        OnActionClickedListener mActionClickedListener;
-
-        public PlaybackGlueHostOld(PlaybackOverlayFragment fragment) {
-            mFragment = fragment;
-            mFragment.setOnItemViewClickedListener(new OnItemViewClickedListener() {
-                @Override
-                public void onItemClicked(Presenter.ViewHolder itemViewHolder, Object item,
-                                          RowPresenter.ViewHolder rowViewHolder, Row row) {
-                    if (item instanceof Action
-                            && rowViewHolder instanceof PlaybackRowPresenter.ViewHolder
-                            && mActionClickedListener != null) {
-                        mActionClickedListener.onActionClicked((Action) item);
-                    } else if (mGlue != null && mGlue.getOnItemViewClickedListener() != null) {
-                        mGlue.getOnItemViewClickedListener().onItemClicked(itemViewHolder,
-                                item, rowViewHolder, row);
-                    }
-                }
-            });
-        }
-
-        @Override
-        public void setFadingEnabled(boolean enable) {
-            mFragment.setFadingEnabled(enable);
-        }
-
-        @Override
-        public void setOnKeyInterceptListener(final View.OnKeyListener onKeyListener) {
-            mFragment.setEventHandler( new InputEventHandler() {
-                @Override
-                public boolean handleInputEvent(InputEvent event) {
-                    if (event instanceof KeyEvent) {
-                        KeyEvent keyEvent = (KeyEvent) event;
-                        return onKeyListener.onKey(null, keyEvent.getKeyCode(), keyEvent);
-                    }
-                    return false;
-                }
-            });
-        }
-
-        @Override
-        public void setOnActionClickedListener(final OnActionClickedListener listener) {
-            mActionClickedListener = listener;
-        }
-
-        @Override
-        public void setHostCallback(HostCallback callback) {
-            mFragment.setHostCallback(callback);
-        }
-
-        @Override
-        public void fadeOut() {
-            mFragment.fadeOut();
-        }
-
-        @Override
-        public void notifyPlaybackRowChanged() {
-            mGlue.onRowChanged(mGlue.getControlsRow());
-        }
-    }
-}
diff --git a/v17/leanback/src/android/support/v17/leanback/app/PlaybackControlSupportGlue.java b/v17/leanback/src/android/support/v17/leanback/app/PlaybackControlSupportGlue.java
deleted file mode 100644
index b3d19ae..0000000
--- a/v17/leanback/src/android/support/v17/leanback/app/PlaybackControlSupportGlue.java
+++ /dev/null
@@ -1,202 +0,0 @@
-/* This file is auto-generated from PlaybackControlGlue.java.  DO NOT MODIFY. */
-
-package android.support.v17.leanback.app;
-
-import android.content.Context;
-import android.support.v17.leanback.media.PlaybackGlueHost;
-import android.support.v17.leanback.widget.Action;
-import android.support.v17.leanback.widget.OnActionClickedListener;
-import android.support.v17.leanback.widget.OnItemViewClickedListener;
-import android.support.v17.leanback.widget.PlaybackRowPresenter;
-import android.support.v17.leanback.widget.Presenter;
-import android.support.v17.leanback.widget.Row;
-import android.support.v17.leanback.widget.RowPresenter;
-import android.view.InputEvent;
-import android.view.KeyEvent;
-import android.view.View;
-
-/**
- * @deprecated Use {@link android.support.v17.leanback.media.PlaybackControlGlue} and
- * {@link PlaybackSupportFragmentGlueHost} for {@link PlaybackSupportFragment}.
- */
-@Deprecated
-public abstract class PlaybackControlSupportGlue extends PlaybackControlGlue {
-    /**
-     * The adapter key for the first custom control on the left side
-     * of the predefined primary controls.
-     */
-    public static final int ACTION_CUSTOM_LEFT_FIRST = PlaybackControlGlue.ACTION_CUSTOM_LEFT_FIRST;
-
-    /**
-     * The adapter key for the skip to previous control.
-     */
-    public static final int ACTION_SKIP_TO_PREVIOUS = PlaybackControlGlue.ACTION_SKIP_TO_PREVIOUS;
-
-    /**
-     * The adapter key for the rewind control.
-     */
-    public static final int ACTION_REWIND = PlaybackControlGlue.ACTION_REWIND;
-
-    /**
-     * The adapter key for the play/pause control.
-     */
-    public static final int ACTION_PLAY_PAUSE = PlaybackControlGlue.ACTION_PLAY_PAUSE;
-
-    /**
-     * The adapter key for the fast forward control.
-     */
-    public static final int ACTION_FAST_FORWARD = PlaybackControlGlue.ACTION_FAST_FORWARD;
-
-    /**
-     * The adapter key for the skip to next control.
-     */
-    public static final int ACTION_SKIP_TO_NEXT = PlaybackControlGlue.ACTION_SKIP_TO_NEXT;
-
-    /**
-     * The adapter key for the first custom control on the right side
-     * of the predefined primary controls.
-     */
-    public static final int ACTION_CUSTOM_RIGHT_FIRST =
-            PlaybackControlGlue.ACTION_CUSTOM_RIGHT_FIRST;
-
-    /**
-     * Invalid playback speed.
-     */
-    public static final int PLAYBACK_SPEED_INVALID = PlaybackControlGlue.PLAYBACK_SPEED_INVALID;
-
-    /**
-     * Speed representing playback state that is paused.
-     */
-    public static final int PLAYBACK_SPEED_PAUSED = PlaybackControlGlue.PLAYBACK_SPEED_PAUSED;
-
-    /**
-     * Speed representing playback state that is playing normally.
-     */
-    public static final int PLAYBACK_SPEED_NORMAL = PlaybackControlGlue.PLAYBACK_SPEED_NORMAL;
-
-    /**
-     * The initial (level 0) fast forward playback speed.
-     * The negative of this value is for rewind at the same speed.
-     */
-    public static final int PLAYBACK_SPEED_FAST_L0 = PlaybackControlGlue.PLAYBACK_SPEED_FAST_L0;
-
-    /**
-     * The level 1 fast forward playback speed.
-     * The negative of this value is for rewind at the same speed.
-     */
-    public static final int PLAYBACK_SPEED_FAST_L1 = PlaybackControlGlue.PLAYBACK_SPEED_FAST_L1;
-
-    /**
-     * The level 2 fast forward playback speed.
-     * The negative of this value is for rewind at the same speed.
-     */
-    public static final int PLAYBACK_SPEED_FAST_L2 = PlaybackControlGlue.PLAYBACK_SPEED_FAST_L2;
-
-    /**
-     * The level 3 fast forward playback speed.
-     * The negative of this value is for rewind at the same speed.
-     */
-    public static final int PLAYBACK_SPEED_FAST_L3 = PlaybackControlGlue.PLAYBACK_SPEED_FAST_L3;
-
-    /**
-     * The level 4 fast forward playback speed.
-     * The negative of this value is for rewind at the same speed.
-     */
-    public static final int PLAYBACK_SPEED_FAST_L4 = PlaybackControlGlue.PLAYBACK_SPEED_FAST_L4;
-
-    public PlaybackControlSupportGlue(Context context, int[] seekSpeeds) {
-        this(context, null, seekSpeeds, seekSpeeds);
-    }
-
-    public PlaybackControlSupportGlue(
-            Context context, int[] fastForwardSpeeds, int[] rewindSpeeds) {
-        this(context, null, fastForwardSpeeds, rewindSpeeds);
-    }
-
-    public PlaybackControlSupportGlue(
-            Context context,
-            PlaybackOverlaySupportFragment fragment,
-            int[] seekSpeeds) {
-        this(context, fragment, seekSpeeds, seekSpeeds);
-    }
-
-    public PlaybackControlSupportGlue(
-            Context context,
-            PlaybackOverlaySupportFragment fragment,
-            int[] fastForwardSpeeds,
-            int[] rewindSpeeds) {
-        super(context, fastForwardSpeeds, rewindSpeeds);
-        setHost(fragment == null ? null : new PlaybackSupportGlueHostOld(fragment));
-    }
-
-    @Override
-    protected void onAttachedToHost(PlaybackGlueHost host) {
-        super.onAttachedToHost(host);
-        if (host instanceof PlaybackSupportGlueHostOld) {
-            ((PlaybackSupportGlueHostOld) host).mGlue = this;
-        }
-    }
-
-    static final class PlaybackSupportGlueHostOld extends PlaybackGlueHost {
-        final PlaybackOverlaySupportFragment mFragment;
-        PlaybackControlSupportGlue mGlue;
-        OnActionClickedListener mActionClickedListener;
-
-        public PlaybackSupportGlueHostOld(PlaybackOverlaySupportFragment fragment) {
-            mFragment = fragment;
-            mFragment.setOnItemViewClickedListener(new OnItemViewClickedListener() {
-                @Override
-                public void onItemClicked(Presenter.ViewHolder itemViewHolder, Object item,
-                                          RowPresenter.ViewHolder rowViewHolder, Row row) {
-                    if (item instanceof Action
-                            && rowViewHolder instanceof PlaybackRowPresenter.ViewHolder
-                            && mActionClickedListener != null) {
-                        mActionClickedListener.onActionClicked((Action) item);
-                    } else if (mGlue != null && mGlue.getOnItemViewClickedListener() != null) {
-                        mGlue.getOnItemViewClickedListener().onItemClicked(itemViewHolder,
-                                item, rowViewHolder, row);
-                    }
-                }
-            });
-        }
-
-        @Override
-        public void setFadingEnabled(boolean enable) {
-            mFragment.setFadingEnabled(enable);
-        }
-
-        @Override
-        public void setOnKeyInterceptListener(final View.OnKeyListener onKeyListenerr) {
-            mFragment.setEventHandler( new InputEventHandler() {
-                @Override
-                public boolean handleInputEvent(InputEvent event) {
-                    if (event instanceof KeyEvent) {
-                        KeyEvent keyEvent = (KeyEvent) event;
-                        return onKeyListenerr.onKey(null, keyEvent.getKeyCode(), keyEvent);
-                    }
-                    return false;
-                }
-            });
-        }
-
-        @Override
-        public void setOnActionClickedListener(final OnActionClickedListener listener) {
-            mActionClickedListener = listener;
-        }
-
-        @Override
-        public void setHostCallback(HostCallback callback) {
-            mFragment.setHostCallback(callback);
-        }
-
-        @Override
-        public void fadeOut() {
-            mFragment.fadeOut();
-        }
-
-        @Override
-        public void notifyPlaybackRowChanged() {
-            mGlue.onRowChanged(mGlue.getControlsRow());
-        }
-    }
-}
diff --git a/v17/leanback/src/android/support/v17/leanback/app/PlaybackFragment.java b/v17/leanback/src/android/support/v17/leanback/app/PlaybackFragment.java
index 1279521..33e787c 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/PlaybackFragment.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/PlaybackFragment.java
@@ -27,6 +27,8 @@
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Message;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
 import android.support.v17.leanback.R;
 import android.support.v17.leanback.animation.LogAccelerateInterpolator;
 import android.support.v17.leanback.animation.LogDecelerateInterpolator;
@@ -450,7 +452,7 @@
     }
 
     @Override
-    public void onViewCreated(View view, Bundle savedInstanceState) {
+    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
         super.onViewCreated(view, savedInstanceState);
         // controls view are initially visible, make it invisible
         // if app has called hideControlsOverlay() before view created.
diff --git a/v17/leanback/src/android/support/v17/leanback/app/PlaybackOverlayFragment.java b/v17/leanback/src/android/support/v17/leanback/app/PlaybackOverlayFragment.java
deleted file mode 100644
index d4b532b..0000000
--- a/v17/leanback/src/android/support/v17/leanback/app/PlaybackOverlayFragment.java
+++ /dev/null
@@ -1,863 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
- * in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
-package android.support.v17.leanback.app;
-
-import android.animation.Animator;
-import android.animation.AnimatorInflater;
-import android.animation.TimeInterpolator;
-import android.animation.ValueAnimator;
-import android.animation.ValueAnimator.AnimatorUpdateListener;
-import android.content.Context;
-import android.graphics.Color;
-import android.graphics.drawable.ColorDrawable;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.Message;
-import android.support.v17.leanback.R;
-import android.support.v17.leanback.animation.LogAccelerateInterpolator;
-import android.support.v17.leanback.animation.LogDecelerateInterpolator;
-import android.support.v17.leanback.media.PlaybackGlueHost;
-import android.support.v17.leanback.widget.ItemAlignmentFacet;
-import android.support.v17.leanback.widget.ItemBridgeAdapter;
-import android.support.v17.leanback.widget.ObjectAdapter;
-import android.support.v17.leanback.widget.ObjectAdapter.DataObserver;
-import android.support.v17.leanback.widget.PlaybackControlsRowPresenter;
-import android.support.v17.leanback.widget.PlaybackRowPresenter;
-import android.support.v17.leanback.widget.Presenter;
-import android.support.v17.leanback.widget.PresenterSelector;
-import android.support.v17.leanback.widget.RowPresenter;
-import android.support.v17.leanback.widget.VerticalGridView;
-import android.support.v7.widget.RecyclerView;
-import android.util.Log;
-import android.view.InputEvent;
-import android.view.KeyEvent;
-import android.view.LayoutInflater;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.animation.AccelerateInterpolator;
-
-import java.lang.ref.WeakReference;
-import java.util.ArrayList;
-
-/**
- * A fragment for displaying playback controls and related content.
- * <p>
- * A PlaybackOverlayFragment renders the elements of its {@link ObjectAdapter} as a set
- * of rows in a vertical list.  The Adapter's {@link PresenterSelector} must maintain subclasses
- * of {@link RowPresenter}.
- * </p>
- * <p>
- * An instance of {@link android.support.v17.leanback.widget.PlaybackControlsRow} is expected to be
- * at position 0 in the adapter.
- * </p>
- * <p>
- *  This class is now deprecated, please us
- * </p>
- * @deprecated Use {@link PlaybackFragment}.
- */
-@Deprecated
-public class PlaybackOverlayFragment extends DetailsFragment {
-
-    /**
-     * No background.
-     */
-    public static final int BG_NONE = 0;
-
-    /**
-     * A dark translucent background.
-     */
-    public static final int BG_DARK = 1;
-
-    /**
-     * A light translucent background.
-     */
-    public static final int BG_LIGHT = 2;
-
-    /**
-     * Listener allowing the application to receive notification of fade in and/or fade out
-     * completion events.
-     */
-    public static class OnFadeCompleteListener {
-        public void onFadeInComplete() {
-        }
-        public void onFadeOutComplete() {
-        }
-    }
-
-    static final String TAG = "PlaybackOF";
-    static final boolean DEBUG = false;
-    private static final int ANIMATION_MULTIPLIER = 1;
-
-    static int START_FADE_OUT = 1;
-
-    // Fading status
-    static final int IDLE = 0;
-    private static final int IN = 1;
-    static final int OUT = 2;
-
-    private int mOtherRowsCenterToBottom;
-    private int mPaddingBottom;
-    private View mRootView;
-    private int mBackgroundType = BG_DARK;
-    private int mBgDarkColor;
-    private int mBgLightColor;
-    private int mShowTimeMs;
-    private int mMajorFadeTranslateY, mMinorFadeTranslateY;
-    int mAnimationTranslateY;
-    OnFadeCompleteListener mFadeCompleteListener;
-    private PlaybackControlGlue.InputEventHandler mInputEventHandler;
-    boolean mFadingEnabled = true;
-    int mFadingStatus = IDLE;
-    int mBgAlpha;
-    private ValueAnimator mBgFadeInAnimator, mBgFadeOutAnimator;
-    private ValueAnimator mControlRowFadeInAnimator, mControlRowFadeOutAnimator;
-    private ValueAnimator mDescriptionFadeInAnimator, mDescriptionFadeOutAnimator;
-    private ValueAnimator mOtherRowFadeInAnimator, mOtherRowFadeOutAnimator;
-    boolean mResetControlsToPrimaryActionsPending;
-    PlaybackGlueHost.HostCallback mHostCallback;
-
-    private final Animator.AnimatorListener mFadeListener =
-            new Animator.AnimatorListener() {
-        @Override
-        public void onAnimationStart(Animator animation) {
-            enableVerticalGridAnimations(false);
-        }
-        @Override
-        public void onAnimationRepeat(Animator animation) {
-        }
-        @Override
-        public void onAnimationCancel(Animator animation) {
-        }
-        @Override
-        public void onAnimationEnd(Animator animation) {
-            if (DEBUG) Log.v(TAG, "onAnimationEnd " + mBgAlpha);
-            if (mBgAlpha > 0) {
-                enableVerticalGridAnimations(true);
-                startFadeTimer();
-                if (mFadeCompleteListener != null) {
-                    mFadeCompleteListener.onFadeInComplete();
-                }
-            } else {
-                VerticalGridView verticalView = getVerticalGridView();
-                // reset focus to the primary actions only if the selected row was the controls row
-                if (verticalView != null && verticalView.getSelectedPosition() == 0) {
-                    resetControlsToPrimaryActions(null);
-                }
-                if (mFadeCompleteListener != null) {
-                    mFadeCompleteListener.onFadeOutComplete();
-                }
-            }
-            mFadingStatus = IDLE;
-        }
-    };
-
-    static class FadeHandler extends Handler {
-        @Override
-        public void handleMessage(Message message) {
-            PlaybackOverlayFragment fragment;
-            if (message.what == START_FADE_OUT) {
-                fragment = ((WeakReference<PlaybackOverlayFragment>) message.obj).get();
-                if (fragment != null && fragment.mFadingEnabled) {
-                    fragment.fade(false);
-                }
-            }
-        }
-    }
-
-    static final Handler sHandler = new FadeHandler();
-
-    final WeakReference<PlaybackOverlayFragment> mFragmentReference =  new WeakReference(this);
-
-    private final VerticalGridView.OnTouchInterceptListener mOnTouchInterceptListener =
-            new VerticalGridView.OnTouchInterceptListener() {
-        @Override
-        public boolean onInterceptTouchEvent(MotionEvent event) {
-            return onInterceptInputEvent(event);
-        }
-    };
-
-    private final VerticalGridView.OnKeyInterceptListener mOnKeyInterceptListener =
-            new VerticalGridView.OnKeyInterceptListener() {
-        @Override
-        public boolean onInterceptKeyEvent(KeyEvent event) {
-            return onInterceptInputEvent(event);
-        }
-    };
-
-    void setBgAlpha(int alpha) {
-        mBgAlpha = alpha;
-        if (mRootView != null) {
-            mRootView.getBackground().setAlpha(alpha);
-        }
-    }
-
-    void enableVerticalGridAnimations(boolean enable) {
-        if (getVerticalGridView() != null) {
-            getVerticalGridView().setAnimateChildLayout(enable);
-        }
-    }
-
-    void resetControlsToPrimaryActions(ItemBridgeAdapter.ViewHolder vh) {
-        if (vh == null && getVerticalGridView() != null) {
-            vh = (ItemBridgeAdapter.ViewHolder) getVerticalGridView().findViewHolderForPosition(0);
-        }
-        if (vh == null) {
-            mResetControlsToPrimaryActionsPending = true;
-        } else if (vh.getPresenter() instanceof PlaybackControlsRowPresenter) {
-            mResetControlsToPrimaryActionsPending = false;
-            ((PlaybackControlsRowPresenter) vh.getPresenter()).showPrimaryActions(
-                    (PlaybackControlsRowPresenter.ViewHolder) vh.getViewHolder());
-        }
-    }
-
-    /**
-     * Enables or disables view fading.  If enabled,
-     * the view will be faded in when the fragment starts,
-     * and will fade out after a time period.  The timeout
-     * period is reset each time {@link #tickle} is called.
-     *
-     */
-    public void setFadingEnabled(boolean enabled) {
-        if (DEBUG) Log.v(TAG, "setFadingEnabled " + enabled);
-        if (enabled != mFadingEnabled) {
-            mFadingEnabled = enabled;
-            if (mFadingEnabled) {
-                if (isResumed() && mFadingStatus == IDLE
-                        && !sHandler.hasMessages(START_FADE_OUT, mFragmentReference)) {
-                    startFadeTimer();
-                }
-            } else {
-                // Ensure fully opaque
-                sHandler.removeMessages(START_FADE_OUT, mFragmentReference);
-                fade(true);
-            }
-        }
-    }
-
-    /**
-     * Returns true if view fading is enabled.
-     */
-    public boolean isFadingEnabled() {
-        return mFadingEnabled;
-    }
-
-    /**
-     * Sets the listener to be called when fade in or out has completed.
-     */
-    public void setFadeCompleteListener(OnFadeCompleteListener listener) {
-        mFadeCompleteListener = listener;
-    }
-
-    /**
-     * Returns the listener to be called when fade in or out has completed.
-     */
-    public OnFadeCompleteListener getFadeCompleteListener() {
-        return mFadeCompleteListener;
-    }
-
-    @Deprecated
-    public interface InputEventHandler extends PlaybackControlGlue.InputEventHandler {
-    }
-
-    /**
-     * Sets the input event handler.
-     */
-    @Deprecated
-    public final void setInputEventHandler(InputEventHandler handler) {
-        mInputEventHandler = handler;
-    }
-
-    /**
-     * Returns the input event handler.
-     */
-    @Deprecated
-    public final InputEventHandler getInputEventHandler() {
-        return (InputEventHandler)mInputEventHandler;
-    }
-
-    /**
-     * Sets the input event handler.
-     */
-    public final void setEventHandler(PlaybackControlGlue.InputEventHandler handler) {
-        mInputEventHandler = handler;
-    }
-
-    /**
-     * Returns the input event handler.
-     */
-    public final PlaybackControlGlue.InputEventHandler getEventHandler() {
-        return mInputEventHandler;
-    }
-
-    /**
-     * Tickles the playback controls.  Fades in the view if it was faded out,
-     * otherwise resets the fade out timer.  Tickling on input events is handled
-     * by the fragment.
-     */
-    public void tickle() {
-        if (DEBUG) Log.v(TAG, "tickle enabled " + mFadingEnabled + " isResumed " + isResumed());
-        if (!mFadingEnabled || !isResumed()) {
-            return;
-        }
-        if (sHandler.hasMessages(START_FADE_OUT, mFragmentReference)) {
-            // Restart the timer
-            startFadeTimer();
-        } else {
-            fade(true);
-        }
-    }
-
-    /**
-     * Fades out the playback overlay immediately.
-     */
-    public void fadeOut() {
-        sHandler.removeMessages(START_FADE_OUT, mFragmentReference);
-        fade(false);
-    }
-
-    /**
-     * Sets the {@link PlaybackGlueHost.HostCallback}. Implementor of this interface will
-     * take appropriate actions to take action when the hosting fragment starts/stops processing.
-     */
-    void setHostCallback(PlaybackGlueHost.HostCallback hostCallback) {
-        this.mHostCallback = hostCallback;
-    }
-
-    @Override
-    public void onStop() {
-        if (mHostCallback != null) {
-            mHostCallback.onHostStop();
-        }
-        super.onStop();
-    }
-
-    @Override
-    public void onPause() {
-        if (mHostCallback != null) {
-            mHostCallback.onHostPause();
-        }
-        super.onPause();
-    }
-
-    private boolean areControlsHidden() {
-        return mFadingStatus == IDLE && mBgAlpha == 0;
-    }
-
-    boolean onInterceptInputEvent(InputEvent event) {
-        final boolean controlsHidden = areControlsHidden();
-        if (DEBUG) Log.v(TAG, "onInterceptInputEvent hidden " + controlsHidden + " " + event);
-        boolean consumeEvent = false;
-        int keyCode = KeyEvent.KEYCODE_UNKNOWN;
-
-        if (mInputEventHandler != null) {
-            consumeEvent = mInputEventHandler.handleInputEvent(event);
-        }
-        if (event instanceof KeyEvent) {
-            keyCode = ((KeyEvent) event).getKeyCode();
-        }
-
-        switch (keyCode) {
-            case KeyEvent.KEYCODE_DPAD_CENTER:
-            case KeyEvent.KEYCODE_DPAD_DOWN:
-            case KeyEvent.KEYCODE_DPAD_UP:
-            case KeyEvent.KEYCODE_DPAD_LEFT:
-            case KeyEvent.KEYCODE_DPAD_RIGHT:
-                // Event may be consumed; regardless, if controls are hidden then these keys will
-                // bring up the controls.
-                if (controlsHidden) {
-                    consumeEvent = true;
-                }
-                tickle();
-                break;
-            case KeyEvent.KEYCODE_BACK:
-            case KeyEvent.KEYCODE_ESCAPE:
-                // If fading enabled and controls are not hidden, back will be consumed to fade
-                // them out (even if the key was consumed by the handler).
-                if (mFadingEnabled && !controlsHidden) {
-                    consumeEvent = true;
-                    sHandler.removeMessages(START_FADE_OUT, mFragmentReference);
-                    fade(false);
-                } else if (consumeEvent) {
-                    tickle();
-                }
-                break;
-            default:
-                if (consumeEvent) {
-                    tickle();
-                }
-        }
-        return consumeEvent;
-    }
-
-    @Override
-    public void onResume() {
-        super.onResume();
-        if (mFadingEnabled) {
-            setBgAlpha(0);
-            fade(true);
-        }
-        getVerticalGridView().setOnTouchInterceptListener(mOnTouchInterceptListener);
-        getVerticalGridView().setOnKeyInterceptListener(mOnKeyInterceptListener);
-        if (mHostCallback != null) {
-            mHostCallback.onHostResume();
-        }
-    }
-
-    void startFadeTimer() {
-        sHandler.removeMessages(START_FADE_OUT, mFragmentReference);
-        sHandler.sendMessageDelayed(sHandler.obtainMessage(START_FADE_OUT, mFragmentReference),
-                mShowTimeMs);
-    }
-
-    private static ValueAnimator loadAnimator(Context context, int resId) {
-        ValueAnimator animator = (ValueAnimator) AnimatorInflater.loadAnimator(context, resId);
-        animator.setDuration(animator.getDuration() * ANIMATION_MULTIPLIER);
-        return animator;
-    }
-
-    private void loadBgAnimator() {
-        AnimatorUpdateListener listener = new AnimatorUpdateListener() {
-            @Override
-            public void onAnimationUpdate(ValueAnimator arg0) {
-                setBgAlpha((Integer) arg0.getAnimatedValue());
-            }
-        };
-
-        Context context = FragmentUtil.getContext(this);
-        mBgFadeInAnimator = loadAnimator(context, R.animator.lb_playback_bg_fade_in);
-        mBgFadeInAnimator.addUpdateListener(listener);
-        mBgFadeInAnimator.addListener(mFadeListener);
-
-        mBgFadeOutAnimator = loadAnimator(context, R.animator.lb_playback_bg_fade_out);
-        mBgFadeOutAnimator.addUpdateListener(listener);
-        mBgFadeOutAnimator.addListener(mFadeListener);
-    }
-
-    private TimeInterpolator mLogDecelerateInterpolator = new LogDecelerateInterpolator(100,0);
-    private TimeInterpolator mLogAccelerateInterpolator = new LogAccelerateInterpolator(100,0);
-
-    View getControlRowView() {
-        if (getVerticalGridView() == null) {
-            return null;
-        }
-        RecyclerView.ViewHolder vh = getVerticalGridView().findViewHolderForPosition(0);
-        if (vh == null) {
-            return null;
-        }
-        return vh.itemView;
-    }
-
-    private void loadControlRowAnimator() {
-        final AnimatorListener listener = new AnimatorListener() {
-            @Override
-            void getViews(ArrayList<View> views) {
-                View view = getControlRowView();
-                if (view != null) {
-                    views.add(view);
-                }
-            }
-        };
-        final AnimatorUpdateListener updateListener = new AnimatorUpdateListener() {
-            @Override
-            public void onAnimationUpdate(ValueAnimator arg0) {
-                View view = getControlRowView();
-                if (view != null) {
-                    final float fraction = (Float) arg0.getAnimatedValue();
-                    if (DEBUG) Log.v(TAG, "fraction " + fraction);
-                    view.setAlpha(fraction);
-                    view.setTranslationY((float) mAnimationTranslateY * (1f - fraction));
-                }
-            }
-        };
-
-        Context context = FragmentUtil.getContext(this);
-        mControlRowFadeInAnimator = loadAnimator(context, R.animator.lb_playback_controls_fade_in);
-        mControlRowFadeInAnimator.addUpdateListener(updateListener);
-        mControlRowFadeInAnimator.addListener(listener);
-        mControlRowFadeInAnimator.setInterpolator(mLogDecelerateInterpolator);
-
-        mControlRowFadeOutAnimator = loadAnimator(context,
-                R.animator.lb_playback_controls_fade_out);
-        mControlRowFadeOutAnimator.addUpdateListener(updateListener);
-        mControlRowFadeOutAnimator.addListener(listener);
-        mControlRowFadeOutAnimator.setInterpolator(mLogAccelerateInterpolator);
-    }
-
-    private void loadOtherRowAnimator() {
-        final AnimatorListener listener = new AnimatorListener() {
-            @Override
-            void getViews(ArrayList<View> views) {
-                if (getVerticalGridView() == null) {
-                    return;
-                }
-                final int count = getVerticalGridView().getChildCount();
-                for (int i = 0; i < count; i++) {
-                    View view = getVerticalGridView().getChildAt(i);
-                    if (view != null) {
-                        views.add(view);
-                    }
-                }
-            }
-        };
-        final AnimatorUpdateListener updateListener = new AnimatorUpdateListener() {
-            @Override
-            public void onAnimationUpdate(ValueAnimator arg0) {
-                if (getVerticalGridView() == null) {
-                    return;
-                }
-                final float fraction = (Float) arg0.getAnimatedValue();
-                for (View view : listener.mViews) {
-                    if (getVerticalGridView().getChildPosition(view) > 0) {
-                        view.setAlpha(fraction);
-                        view.setTranslationY((float) mAnimationTranslateY * (1f - fraction));
-                    }
-                }
-            }
-        };
-
-        Context context = FragmentUtil.getContext(this);
-        mOtherRowFadeInAnimator = loadAnimator(context, R.animator.lb_playback_controls_fade_in);
-        mOtherRowFadeInAnimator.addListener(listener);
-        mOtherRowFadeInAnimator.addUpdateListener(updateListener);
-        mOtherRowFadeInAnimator.setInterpolator(mLogDecelerateInterpolator);
-
-        mOtherRowFadeOutAnimator = loadAnimator(context, R.animator.lb_playback_controls_fade_out);
-        mOtherRowFadeOutAnimator.addListener(listener);
-        mOtherRowFadeOutAnimator.addUpdateListener(updateListener);
-        mOtherRowFadeOutAnimator.setInterpolator(new AccelerateInterpolator());
-    }
-
-    private void loadDescriptionAnimator() {
-        AnimatorUpdateListener listener = new AnimatorUpdateListener() {
-            @Override
-            public void onAnimationUpdate(ValueAnimator arg0) {
-                if (getVerticalGridView() == null) {
-                    return;
-                }
-                ItemBridgeAdapter.ViewHolder adapterVh = (ItemBridgeAdapter.ViewHolder)
-                        getVerticalGridView().findViewHolderForPosition(0);
-                if (adapterVh != null && adapterVh.getViewHolder()
-                        instanceof PlaybackControlsRowPresenter.ViewHolder) {
-                    final Presenter.ViewHolder vh = ((PlaybackControlsRowPresenter.ViewHolder)
-                            adapterVh.getViewHolder()).mDescriptionViewHolder;
-                    if (vh != null) {
-                        vh.view.setAlpha((Float) arg0.getAnimatedValue());
-                    }
-                }
-            }
-        };
-
-        Context context = FragmentUtil.getContext(this);
-        mDescriptionFadeInAnimator = loadAnimator(context,
-                R.animator.lb_playback_description_fade_in);
-        mDescriptionFadeInAnimator.addUpdateListener(listener);
-        mDescriptionFadeInAnimator.setInterpolator(mLogDecelerateInterpolator);
-
-        mDescriptionFadeOutAnimator = loadAnimator(context,
-                R.animator.lb_playback_description_fade_out);
-        mDescriptionFadeOutAnimator.addUpdateListener(listener);
-    }
-
-    void fade(boolean fadeIn) {
-        if (DEBUG) Log.v(TAG, "fade " + fadeIn);
-        if (getView() == null) {
-            return;
-        }
-        if ((fadeIn && mFadingStatus == IN) || (!fadeIn && mFadingStatus == OUT)) {
-            if (DEBUG) Log.v(TAG, "requested fade in progress");
-            return;
-        }
-        if ((fadeIn && mBgAlpha == 255) || (!fadeIn && mBgAlpha == 0)) {
-            if (DEBUG) Log.v(TAG, "fade is no-op");
-            return;
-        }
-
-        mAnimationTranslateY = getVerticalGridView().getSelectedPosition() == 0
-                ? mMajorFadeTranslateY : mMinorFadeTranslateY;
-
-        if (mFadingStatus == IDLE) {
-            if (fadeIn) {
-                mBgFadeInAnimator.start();
-                mControlRowFadeInAnimator.start();
-                mOtherRowFadeInAnimator.start();
-                mDescriptionFadeInAnimator.start();
-            } else {
-                mBgFadeOutAnimator.start();
-                mControlRowFadeOutAnimator.start();
-                mOtherRowFadeOutAnimator.start();
-                mDescriptionFadeOutAnimator.start();
-            }
-        } else {
-            if (fadeIn) {
-                mBgFadeOutAnimator.reverse();
-                mControlRowFadeOutAnimator.reverse();
-                mOtherRowFadeOutAnimator.reverse();
-                mDescriptionFadeOutAnimator.reverse();
-            } else {
-                mBgFadeInAnimator.reverse();
-                mControlRowFadeInAnimator.reverse();
-                mOtherRowFadeInAnimator.reverse();
-                mDescriptionFadeInAnimator.reverse();
-            }
-        }
-        getView().announceForAccessibility(getString(fadeIn ? R.string.lb_playback_controls_shown
-                : R.string.lb_playback_controls_hidden));
-
-        // If fading in while control row is focused, set initial translationY so
-        // views slide in from below.
-        if (fadeIn && mFadingStatus == IDLE) {
-            final int count = getVerticalGridView().getChildCount();
-            for (int i = 0; i < count; i++) {
-                getVerticalGridView().getChildAt(i).setTranslationY(mAnimationTranslateY);
-            }
-        }
-
-        mFadingStatus = fadeIn ? IN : OUT;
-    }
-
-    /**
-     * Sets the list of rows for the fragment.
-     */
-    @Override
-    public void setAdapter(ObjectAdapter adapter) {
-        if (getAdapter() != null) {
-            getAdapter().unregisterObserver(mObserver);
-        }
-        super.setAdapter(adapter);
-        if (adapter != null) {
-            adapter.registerObserver(mObserver);
-        }
-    }
-
-    @Override
-    protected void setupPresenter(Presenter rowPresenter) {
-        if (rowPresenter instanceof PlaybackRowPresenter) {
-            if (rowPresenter.getFacet(ItemAlignmentFacet.class) == null) {
-                ItemAlignmentFacet itemAlignment = new ItemAlignmentFacet();
-                ItemAlignmentFacet.ItemAlignmentDef def =
-                        new ItemAlignmentFacet.ItemAlignmentDef();
-                def.setItemAlignmentOffset(0);
-                def.setItemAlignmentOffsetPercent(100);
-                itemAlignment.setAlignmentDefs(new ItemAlignmentFacet.ItemAlignmentDef[]
-                        {def});
-                rowPresenter.setFacet(ItemAlignmentFacet.class, itemAlignment);
-            }
-        } else {
-            super.setupPresenter(rowPresenter);
-        }
-    }
-
-    @Override
-    void setVerticalGridViewLayout(VerticalGridView listview) {
-        if (listview == null) {
-            return;
-        }
-
-        // we set the base line of alignment to -paddingBottom
-        listview.setWindowAlignmentOffset(-mPaddingBottom);
-        listview.setWindowAlignmentOffsetPercent(
-                VerticalGridView.WINDOW_ALIGN_OFFSET_PERCENT_DISABLED);
-
-        // align other rows that arent the last to center of screen, since our baseline is
-        // -mPaddingBottom, we need subtract that from mOtherRowsCenterToBottom.
-        listview.setItemAlignmentOffset(mOtherRowsCenterToBottom - mPaddingBottom);
-        listview.setItemAlignmentOffsetPercent(50);
-
-        // Push last row to the bottom padding
-        // Padding affects alignment when last row is focused
-        listview.setPadding(listview.getPaddingLeft(), listview.getPaddingTop(),
-                listview.getPaddingRight(), mPaddingBottom);
-        listview.setWindowAlignment(VerticalGridView.WINDOW_ALIGN_HIGH_EDGE);
-    }
-
-    @Override
-    public void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-
-        mOtherRowsCenterToBottom = getResources()
-                .getDimensionPixelSize(R.dimen.lb_playback_other_rows_center_to_bottom);
-        mPaddingBottom =
-                getResources().getDimensionPixelSize(R.dimen.lb_playback_controls_padding_bottom);
-        mBgDarkColor =
-                getResources().getColor(R.color.lb_playback_controls_background_dark);
-        mBgLightColor =
-                getResources().getColor(R.color.lb_playback_controls_background_light);
-        mShowTimeMs =
-                getResources().getInteger(R.integer.lb_playback_controls_show_time_ms);
-        mMajorFadeTranslateY =
-                getResources().getDimensionPixelSize(R.dimen.lb_playback_major_fade_translate_y);
-        mMinorFadeTranslateY =
-                getResources().getDimensionPixelSize(R.dimen.lb_playback_minor_fade_translate_y);
-
-        loadBgAnimator();
-        loadControlRowAnimator();
-        loadOtherRowAnimator();
-        loadDescriptionAnimator();
-    }
-
-    /**
-     * Sets the background type.
-     *
-     * @param type One of BG_LIGHT, BG_DARK, or BG_NONE.
-     */
-    public void setBackgroundType(int type) {
-        switch (type) {
-        case BG_LIGHT:
-        case BG_DARK:
-        case BG_NONE:
-            if (type != mBackgroundType) {
-                mBackgroundType = type;
-                updateBackground();
-            }
-            break;
-        default:
-            throw new IllegalArgumentException("Invalid background type");
-        }
-    }
-
-    /**
-     * Returns the background type.
-     */
-    public int getBackgroundType() {
-        return mBackgroundType;
-    }
-
-    private void updateBackground() {
-        if (mRootView != null) {
-            int color = mBgDarkColor;
-            switch (mBackgroundType) {
-                case BG_DARK: break;
-                case BG_LIGHT: color = mBgLightColor; break;
-                case BG_NONE: color = Color.TRANSPARENT; break;
-            }
-            mRootView.setBackground(new ColorDrawable(color));
-        }
-    }
-
-    void updateControlsBottomSpace(ItemBridgeAdapter.ViewHolder vh) {
-        // Add extra space between rows 0 and 1
-        if (vh == null && getVerticalGridView() != null) {
-            vh = (ItemBridgeAdapter.ViewHolder)
-                    getVerticalGridView().findViewHolderForPosition(0);
-        }
-        if (vh != null && vh.getPresenter() instanceof PlaybackControlsRowPresenter) {
-            final int adapterSize = getAdapter() == null ? 0 : getAdapter().size();
-            ((PlaybackControlsRowPresenter) vh.getPresenter()).showBottomSpace(
-                    (PlaybackControlsRowPresenter.ViewHolder) vh.getViewHolder(),
-                    adapterSize > 1);
-        }
-    }
-
-    private final ItemBridgeAdapter.AdapterListener mAdapterListener =
-            new ItemBridgeAdapter.AdapterListener() {
-        @Override
-        public void onAttachedToWindow(ItemBridgeAdapter.ViewHolder vh) {
-            if (DEBUG) Log.v(TAG, "onAttachedToWindow " + vh.getViewHolder().view);
-            if ((mFadingStatus == IDLE && mBgAlpha == 0) || mFadingStatus == OUT) {
-                if (DEBUG) Log.v(TAG, "setting alpha to 0");
-                vh.getViewHolder().view.setAlpha(0);
-            }
-            if (vh.getPosition() == 0 && mResetControlsToPrimaryActionsPending) {
-                resetControlsToPrimaryActions(vh);
-            }
-        }
-        @Override
-        public void onDetachedFromWindow(ItemBridgeAdapter.ViewHolder vh) {
-            if (DEBUG) Log.v(TAG, "onDetachedFromWindow " + vh.getViewHolder().view);
-            // Reset animation state
-            vh.getViewHolder().view.setAlpha(1f);
-            vh.getViewHolder().view.setTranslationY(0);
-            if (vh.getViewHolder() instanceof PlaybackControlsRowPresenter.ViewHolder) {
-                Presenter.ViewHolder descriptionVh = ((PlaybackControlsRowPresenter.ViewHolder)
-                        vh.getViewHolder()).mDescriptionViewHolder;
-                if (descriptionVh != null) {
-                    descriptionVh.view.setAlpha(1f);
-                }
-            }
-        }
-        @Override
-        public void onBind(ItemBridgeAdapter.ViewHolder vh) {
-            if (vh.getPosition() == 0) {
-                updateControlsBottomSpace(vh);
-            }
-        }
-    };
-
-    @Override
-    public View onCreateView(LayoutInflater inflater, ViewGroup container,
-            Bundle savedInstanceState) {
-        mRootView = super.onCreateView(inflater, container, savedInstanceState);
-        mBgAlpha = 255;
-        updateBackground();
-        getRowsFragment().setExternalAdapterListener(mAdapterListener);
-        return mRootView;
-    }
-
-    @Override
-    public void onDestroyView() {
-        mRootView = null;
-        if (mHostCallback != null) {
-            mHostCallback.onHostDestroy();
-        }
-        super.onDestroyView();
-    }
-
-    @Override
-    public void onStart() {
-        super.onStart();
-        // Workaround problem VideoView forcing itself to focused, let controls take focus.
-        getRowsFragment().getView().requestFocus();
-        if (mHostCallback != null) {
-            mHostCallback.onHostStart();
-        }
-    }
-
-    private final DataObserver mObserver = new DataObserver() {
-        @Override
-        public void onChanged() {
-            updateControlsBottomSpace(null);
-        }
-    };
-
-    static abstract class AnimatorListener implements Animator.AnimatorListener {
-        ArrayList<View> mViews = new ArrayList<View>();
-        ArrayList<Integer> mLayerType = new ArrayList<Integer>();
-
-        @Override
-        public void onAnimationCancel(Animator animation) {
-        }
-        @Override
-        public void onAnimationRepeat(Animator animation) {
-        }
-        @Override
-        public void onAnimationStart(Animator animation) {
-            getViews(mViews);
-            for (View view : mViews) {
-                mLayerType.add(view.getLayerType());
-                view.setLayerType(View.LAYER_TYPE_HARDWARE, null);
-            }
-        }
-        @Override
-        public void onAnimationEnd(Animator animation) {
-            for (int i = 0; i < mViews.size(); i++) {
-                mViews.get(i).setLayerType(mLayerType.get(i), null);
-            }
-            mLayerType.clear();
-            mViews.clear();
-        }
-        abstract void getViews(ArrayList<View> views);
-
-    };
-}
diff --git a/v17/leanback/src/android/support/v17/leanback/app/PlaybackOverlaySupportFragment.java b/v17/leanback/src/android/support/v17/leanback/app/PlaybackOverlaySupportFragment.java
deleted file mode 100644
index d751320..0000000
--- a/v17/leanback/src/android/support/v17/leanback/app/PlaybackOverlaySupportFragment.java
+++ /dev/null
@@ -1,866 +0,0 @@
-// CHECKSTYLE:OFF Generated code
-/* This file is auto-generated from PlaybackOverlayFragment.java.  DO NOT MODIFY. */
-
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
- * in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
-package android.support.v17.leanback.app;
-
-import android.animation.Animator;
-import android.animation.AnimatorInflater;
-import android.animation.TimeInterpolator;
-import android.animation.ValueAnimator;
-import android.animation.ValueAnimator.AnimatorUpdateListener;
-import android.content.Context;
-import android.graphics.Color;
-import android.graphics.drawable.ColorDrawable;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.Message;
-import android.support.v17.leanback.R;
-import android.support.v17.leanback.animation.LogAccelerateInterpolator;
-import android.support.v17.leanback.animation.LogDecelerateInterpolator;
-import android.support.v17.leanback.media.PlaybackGlueHost;
-import android.support.v17.leanback.widget.ItemAlignmentFacet;
-import android.support.v17.leanback.widget.ItemBridgeAdapter;
-import android.support.v17.leanback.widget.ObjectAdapter;
-import android.support.v17.leanback.widget.ObjectAdapter.DataObserver;
-import android.support.v17.leanback.widget.PlaybackControlsRowPresenter;
-import android.support.v17.leanback.widget.PlaybackRowPresenter;
-import android.support.v17.leanback.widget.Presenter;
-import android.support.v17.leanback.widget.PresenterSelector;
-import android.support.v17.leanback.widget.RowPresenter;
-import android.support.v17.leanback.widget.VerticalGridView;
-import android.support.v7.widget.RecyclerView;
-import android.util.Log;
-import android.view.InputEvent;
-import android.view.KeyEvent;
-import android.view.LayoutInflater;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.animation.AccelerateInterpolator;
-
-import java.lang.ref.WeakReference;
-import java.util.ArrayList;
-
-/**
- * A fragment for displaying playback controls and related content.
- * <p>
- * A PlaybackOverlaySupportFragment renders the elements of its {@link ObjectAdapter} as a set
- * of rows in a vertical list.  The Adapter's {@link PresenterSelector} must maintain subclasses
- * of {@link RowPresenter}.
- * </p>
- * <p>
- * An instance of {@link android.support.v17.leanback.widget.PlaybackControlsRow} is expected to be
- * at position 0 in the adapter.
- * </p>
- * <p>
- *  This class is now deprecated, please us
- * </p>
- * @deprecated Use {@link PlaybackSupportFragment}.
- */
-@Deprecated
-public class PlaybackOverlaySupportFragment extends DetailsSupportFragment {
-
-    /**
-     * No background.
-     */
-    public static final int BG_NONE = 0;
-
-    /**
-     * A dark translucent background.
-     */
-    public static final int BG_DARK = 1;
-
-    /**
-     * A light translucent background.
-     */
-    public static final int BG_LIGHT = 2;
-
-    /**
-     * Listener allowing the application to receive notification of fade in and/or fade out
-     * completion events.
-     */
-    public static class OnFadeCompleteListener {
-        public void onFadeInComplete() {
-        }
-        public void onFadeOutComplete() {
-        }
-    }
-
-    static final String TAG = "PlaybackOF";
-    static final boolean DEBUG = false;
-    private static final int ANIMATION_MULTIPLIER = 1;
-
-    static int START_FADE_OUT = 1;
-
-    // Fading status
-    static final int IDLE = 0;
-    private static final int IN = 1;
-    static final int OUT = 2;
-
-    private int mOtherRowsCenterToBottom;
-    private int mPaddingBottom;
-    private View mRootView;
-    private int mBackgroundType = BG_DARK;
-    private int mBgDarkColor;
-    private int mBgLightColor;
-    private int mShowTimeMs;
-    private int mMajorFadeTranslateY, mMinorFadeTranslateY;
-    int mAnimationTranslateY;
-    OnFadeCompleteListener mFadeCompleteListener;
-    private PlaybackControlGlue.InputEventHandler mInputEventHandler;
-    boolean mFadingEnabled = true;
-    int mFadingStatus = IDLE;
-    int mBgAlpha;
-    private ValueAnimator mBgFadeInAnimator, mBgFadeOutAnimator;
-    private ValueAnimator mControlRowFadeInAnimator, mControlRowFadeOutAnimator;
-    private ValueAnimator mDescriptionFadeInAnimator, mDescriptionFadeOutAnimator;
-    private ValueAnimator mOtherRowFadeInAnimator, mOtherRowFadeOutAnimator;
-    boolean mResetControlsToPrimaryActionsPending;
-    PlaybackGlueHost.HostCallback mHostCallback;
-
-    private final Animator.AnimatorListener mFadeListener =
-            new Animator.AnimatorListener() {
-        @Override
-        public void onAnimationStart(Animator animation) {
-            enableVerticalGridAnimations(false);
-        }
-        @Override
-        public void onAnimationRepeat(Animator animation) {
-        }
-        @Override
-        public void onAnimationCancel(Animator animation) {
-        }
-        @Override
-        public void onAnimationEnd(Animator animation) {
-            if (DEBUG) Log.v(TAG, "onAnimationEnd " + mBgAlpha);
-            if (mBgAlpha > 0) {
-                enableVerticalGridAnimations(true);
-                startFadeTimer();
-                if (mFadeCompleteListener != null) {
-                    mFadeCompleteListener.onFadeInComplete();
-                }
-            } else {
-                VerticalGridView verticalView = getVerticalGridView();
-                // reset focus to the primary actions only if the selected row was the controls row
-                if (verticalView != null && verticalView.getSelectedPosition() == 0) {
-                    resetControlsToPrimaryActions(null);
-                }
-                if (mFadeCompleteListener != null) {
-                    mFadeCompleteListener.onFadeOutComplete();
-                }
-            }
-            mFadingStatus = IDLE;
-        }
-    };
-
-    static class FadeHandler extends Handler {
-        @Override
-        public void handleMessage(Message message) {
-            PlaybackOverlaySupportFragment fragment;
-            if (message.what == START_FADE_OUT) {
-                fragment = ((WeakReference<PlaybackOverlaySupportFragment>) message.obj).get();
-                if (fragment != null && fragment.mFadingEnabled) {
-                    fragment.fade(false);
-                }
-            }
-        }
-    }
-
-    static final Handler sHandler = new FadeHandler();
-
-    final WeakReference<PlaybackOverlaySupportFragment> mFragmentReference =  new WeakReference(this);
-
-    private final VerticalGridView.OnTouchInterceptListener mOnTouchInterceptListener =
-            new VerticalGridView.OnTouchInterceptListener() {
-        @Override
-        public boolean onInterceptTouchEvent(MotionEvent event) {
-            return onInterceptInputEvent(event);
-        }
-    };
-
-    private final VerticalGridView.OnKeyInterceptListener mOnKeyInterceptListener =
-            new VerticalGridView.OnKeyInterceptListener() {
-        @Override
-        public boolean onInterceptKeyEvent(KeyEvent event) {
-            return onInterceptInputEvent(event);
-        }
-    };
-
-    void setBgAlpha(int alpha) {
-        mBgAlpha = alpha;
-        if (mRootView != null) {
-            mRootView.getBackground().setAlpha(alpha);
-        }
-    }
-
-    void enableVerticalGridAnimations(boolean enable) {
-        if (getVerticalGridView() != null) {
-            getVerticalGridView().setAnimateChildLayout(enable);
-        }
-    }
-
-    void resetControlsToPrimaryActions(ItemBridgeAdapter.ViewHolder vh) {
-        if (vh == null && getVerticalGridView() != null) {
-            vh = (ItemBridgeAdapter.ViewHolder) getVerticalGridView().findViewHolderForPosition(0);
-        }
-        if (vh == null) {
-            mResetControlsToPrimaryActionsPending = true;
-        } else if (vh.getPresenter() instanceof PlaybackControlsRowPresenter) {
-            mResetControlsToPrimaryActionsPending = false;
-            ((PlaybackControlsRowPresenter) vh.getPresenter()).showPrimaryActions(
-                    (PlaybackControlsRowPresenter.ViewHolder) vh.getViewHolder());
-        }
-    }
-
-    /**
-     * Enables or disables view fading.  If enabled,
-     * the view will be faded in when the fragment starts,
-     * and will fade out after a time period.  The timeout
-     * period is reset each time {@link #tickle} is called.
-     *
-     */
-    public void setFadingEnabled(boolean enabled) {
-        if (DEBUG) Log.v(TAG, "setFadingEnabled " + enabled);
-        if (enabled != mFadingEnabled) {
-            mFadingEnabled = enabled;
-            if (mFadingEnabled) {
-                if (isResumed() && mFadingStatus == IDLE
-                        && !sHandler.hasMessages(START_FADE_OUT, mFragmentReference)) {
-                    startFadeTimer();
-                }
-            } else {
-                // Ensure fully opaque
-                sHandler.removeMessages(START_FADE_OUT, mFragmentReference);
-                fade(true);
-            }
-        }
-    }
-
-    /**
-     * Returns true if view fading is enabled.
-     */
-    public boolean isFadingEnabled() {
-        return mFadingEnabled;
-    }
-
-    /**
-     * Sets the listener to be called when fade in or out has completed.
-     */
-    public void setFadeCompleteListener(OnFadeCompleteListener listener) {
-        mFadeCompleteListener = listener;
-    }
-
-    /**
-     * Returns the listener to be called when fade in or out has completed.
-     */
-    public OnFadeCompleteListener getFadeCompleteListener() {
-        return mFadeCompleteListener;
-    }
-
-    @Deprecated
-    public interface InputEventHandler extends PlaybackControlGlue.InputEventHandler {
-    }
-
-    /**
-     * Sets the input event handler.
-     */
-    @Deprecated
-    public final void setInputEventHandler(InputEventHandler handler) {
-        mInputEventHandler = handler;
-    }
-
-    /**
-     * Returns the input event handler.
-     */
-    @Deprecated
-    public final InputEventHandler getInputEventHandler() {
-        return (InputEventHandler)mInputEventHandler;
-    }
-
-    /**
-     * Sets the input event handler.
-     */
-    public final void setEventHandler(PlaybackControlGlue.InputEventHandler handler) {
-        mInputEventHandler = handler;
-    }
-
-    /**
-     * Returns the input event handler.
-     */
-    public final PlaybackControlGlue.InputEventHandler getEventHandler() {
-        return mInputEventHandler;
-    }
-
-    /**
-     * Tickles the playback controls.  Fades in the view if it was faded out,
-     * otherwise resets the fade out timer.  Tickling on input events is handled
-     * by the fragment.
-     */
-    public void tickle() {
-        if (DEBUG) Log.v(TAG, "tickle enabled " + mFadingEnabled + " isResumed " + isResumed());
-        if (!mFadingEnabled || !isResumed()) {
-            return;
-        }
-        if (sHandler.hasMessages(START_FADE_OUT, mFragmentReference)) {
-            // Restart the timer
-            startFadeTimer();
-        } else {
-            fade(true);
-        }
-    }
-
-    /**
-     * Fades out the playback overlay immediately.
-     */
-    public void fadeOut() {
-        sHandler.removeMessages(START_FADE_OUT, mFragmentReference);
-        fade(false);
-    }
-
-    /**
-     * Sets the {@link PlaybackGlueHost.HostCallback}. Implementor of this interface will
-     * take appropriate actions to take action when the hosting fragment starts/stops processing.
-     */
-    void setHostCallback(PlaybackGlueHost.HostCallback hostCallback) {
-        this.mHostCallback = hostCallback;
-    }
-
-    @Override
-    public void onStop() {
-        if (mHostCallback != null) {
-            mHostCallback.onHostStop();
-        }
-        super.onStop();
-    }
-
-    @Override
-    public void onPause() {
-        if (mHostCallback != null) {
-            mHostCallback.onHostPause();
-        }
-        super.onPause();
-    }
-
-    private boolean areControlsHidden() {
-        return mFadingStatus == IDLE && mBgAlpha == 0;
-    }
-
-    boolean onInterceptInputEvent(InputEvent event) {
-        final boolean controlsHidden = areControlsHidden();
-        if (DEBUG) Log.v(TAG, "onInterceptInputEvent hidden " + controlsHidden + " " + event);
-        boolean consumeEvent = false;
-        int keyCode = KeyEvent.KEYCODE_UNKNOWN;
-
-        if (mInputEventHandler != null) {
-            consumeEvent = mInputEventHandler.handleInputEvent(event);
-        }
-        if (event instanceof KeyEvent) {
-            keyCode = ((KeyEvent) event).getKeyCode();
-        }
-
-        switch (keyCode) {
-            case KeyEvent.KEYCODE_DPAD_CENTER:
-            case KeyEvent.KEYCODE_DPAD_DOWN:
-            case KeyEvent.KEYCODE_DPAD_UP:
-            case KeyEvent.KEYCODE_DPAD_LEFT:
-            case KeyEvent.KEYCODE_DPAD_RIGHT:
-                // Event may be consumed; regardless, if controls are hidden then these keys will
-                // bring up the controls.
-                if (controlsHidden) {
-                    consumeEvent = true;
-                }
-                tickle();
-                break;
-            case KeyEvent.KEYCODE_BACK:
-            case KeyEvent.KEYCODE_ESCAPE:
-                // If fading enabled and controls are not hidden, back will be consumed to fade
-                // them out (even if the key was consumed by the handler).
-                if (mFadingEnabled && !controlsHidden) {
-                    consumeEvent = true;
-                    sHandler.removeMessages(START_FADE_OUT, mFragmentReference);
-                    fade(false);
-                } else if (consumeEvent) {
-                    tickle();
-                }
-                break;
-            default:
-                if (consumeEvent) {
-                    tickle();
-                }
-        }
-        return consumeEvent;
-    }
-
-    @Override
-    public void onResume() {
-        super.onResume();
-        if (mFadingEnabled) {
-            setBgAlpha(0);
-            fade(true);
-        }
-        getVerticalGridView().setOnTouchInterceptListener(mOnTouchInterceptListener);
-        getVerticalGridView().setOnKeyInterceptListener(mOnKeyInterceptListener);
-        if (mHostCallback != null) {
-            mHostCallback.onHostResume();
-        }
-    }
-
-    void startFadeTimer() {
-        sHandler.removeMessages(START_FADE_OUT, mFragmentReference);
-        sHandler.sendMessageDelayed(sHandler.obtainMessage(START_FADE_OUT, mFragmentReference),
-                mShowTimeMs);
-    }
-
-    private static ValueAnimator loadAnimator(Context context, int resId) {
-        ValueAnimator animator = (ValueAnimator) AnimatorInflater.loadAnimator(context, resId);
-        animator.setDuration(animator.getDuration() * ANIMATION_MULTIPLIER);
-        return animator;
-    }
-
-    private void loadBgAnimator() {
-        AnimatorUpdateListener listener = new AnimatorUpdateListener() {
-            @Override
-            public void onAnimationUpdate(ValueAnimator arg0) {
-                setBgAlpha((Integer) arg0.getAnimatedValue());
-            }
-        };
-
-        Context context = getContext();
-        mBgFadeInAnimator = loadAnimator(context, R.animator.lb_playback_bg_fade_in);
-        mBgFadeInAnimator.addUpdateListener(listener);
-        mBgFadeInAnimator.addListener(mFadeListener);
-
-        mBgFadeOutAnimator = loadAnimator(context, R.animator.lb_playback_bg_fade_out);
-        mBgFadeOutAnimator.addUpdateListener(listener);
-        mBgFadeOutAnimator.addListener(mFadeListener);
-    }
-
-    private TimeInterpolator mLogDecelerateInterpolator = new LogDecelerateInterpolator(100,0);
-    private TimeInterpolator mLogAccelerateInterpolator = new LogAccelerateInterpolator(100,0);
-
-    View getControlRowView() {
-        if (getVerticalGridView() == null) {
-            return null;
-        }
-        RecyclerView.ViewHolder vh = getVerticalGridView().findViewHolderForPosition(0);
-        if (vh == null) {
-            return null;
-        }
-        return vh.itemView;
-    }
-
-    private void loadControlRowAnimator() {
-        final AnimatorListener listener = new AnimatorListener() {
-            @Override
-            void getViews(ArrayList<View> views) {
-                View view = getControlRowView();
-                if (view != null) {
-                    views.add(view);
-                }
-            }
-        };
-        final AnimatorUpdateListener updateListener = new AnimatorUpdateListener() {
-            @Override
-            public void onAnimationUpdate(ValueAnimator arg0) {
-                View view = getControlRowView();
-                if (view != null) {
-                    final float fraction = (Float) arg0.getAnimatedValue();
-                    if (DEBUG) Log.v(TAG, "fraction " + fraction);
-                    view.setAlpha(fraction);
-                    view.setTranslationY((float) mAnimationTranslateY * (1f - fraction));
-                }
-            }
-        };
-
-        Context context = getContext();
-        mControlRowFadeInAnimator = loadAnimator(context, R.animator.lb_playback_controls_fade_in);
-        mControlRowFadeInAnimator.addUpdateListener(updateListener);
-        mControlRowFadeInAnimator.addListener(listener);
-        mControlRowFadeInAnimator.setInterpolator(mLogDecelerateInterpolator);
-
-        mControlRowFadeOutAnimator = loadAnimator(context,
-                R.animator.lb_playback_controls_fade_out);
-        mControlRowFadeOutAnimator.addUpdateListener(updateListener);
-        mControlRowFadeOutAnimator.addListener(listener);
-        mControlRowFadeOutAnimator.setInterpolator(mLogAccelerateInterpolator);
-    }
-
-    private void loadOtherRowAnimator() {
-        final AnimatorListener listener = new AnimatorListener() {
-            @Override
-            void getViews(ArrayList<View> views) {
-                if (getVerticalGridView() == null) {
-                    return;
-                }
-                final int count = getVerticalGridView().getChildCount();
-                for (int i = 0; i < count; i++) {
-                    View view = getVerticalGridView().getChildAt(i);
-                    if (view != null) {
-                        views.add(view);
-                    }
-                }
-            }
-        };
-        final AnimatorUpdateListener updateListener = new AnimatorUpdateListener() {
-            @Override
-            public void onAnimationUpdate(ValueAnimator arg0) {
-                if (getVerticalGridView() == null) {
-                    return;
-                }
-                final float fraction = (Float) arg0.getAnimatedValue();
-                for (View view : listener.mViews) {
-                    if (getVerticalGridView().getChildPosition(view) > 0) {
-                        view.setAlpha(fraction);
-                        view.setTranslationY((float) mAnimationTranslateY * (1f - fraction));
-                    }
-                }
-            }
-        };
-
-        Context context = getContext();
-        mOtherRowFadeInAnimator = loadAnimator(context, R.animator.lb_playback_controls_fade_in);
-        mOtherRowFadeInAnimator.addListener(listener);
-        mOtherRowFadeInAnimator.addUpdateListener(updateListener);
-        mOtherRowFadeInAnimator.setInterpolator(mLogDecelerateInterpolator);
-
-        mOtherRowFadeOutAnimator = loadAnimator(context, R.animator.lb_playback_controls_fade_out);
-        mOtherRowFadeOutAnimator.addListener(listener);
-        mOtherRowFadeOutAnimator.addUpdateListener(updateListener);
-        mOtherRowFadeOutAnimator.setInterpolator(new AccelerateInterpolator());
-    }
-
-    private void loadDescriptionAnimator() {
-        AnimatorUpdateListener listener = new AnimatorUpdateListener() {
-            @Override
-            public void onAnimationUpdate(ValueAnimator arg0) {
-                if (getVerticalGridView() == null) {
-                    return;
-                }
-                ItemBridgeAdapter.ViewHolder adapterVh = (ItemBridgeAdapter.ViewHolder)
-                        getVerticalGridView().findViewHolderForPosition(0);
-                if (adapterVh != null && adapterVh.getViewHolder()
-                        instanceof PlaybackControlsRowPresenter.ViewHolder) {
-                    final Presenter.ViewHolder vh = ((PlaybackControlsRowPresenter.ViewHolder)
-                            adapterVh.getViewHolder()).mDescriptionViewHolder;
-                    if (vh != null) {
-                        vh.view.setAlpha((Float) arg0.getAnimatedValue());
-                    }
-                }
-            }
-        };
-
-        Context context = getContext();
-        mDescriptionFadeInAnimator = loadAnimator(context,
-                R.animator.lb_playback_description_fade_in);
-        mDescriptionFadeInAnimator.addUpdateListener(listener);
-        mDescriptionFadeInAnimator.setInterpolator(mLogDecelerateInterpolator);
-
-        mDescriptionFadeOutAnimator = loadAnimator(context,
-                R.animator.lb_playback_description_fade_out);
-        mDescriptionFadeOutAnimator.addUpdateListener(listener);
-    }
-
-    void fade(boolean fadeIn) {
-        if (DEBUG) Log.v(TAG, "fade " + fadeIn);
-        if (getView() == null) {
-            return;
-        }
-        if ((fadeIn && mFadingStatus == IN) || (!fadeIn && mFadingStatus == OUT)) {
-            if (DEBUG) Log.v(TAG, "requested fade in progress");
-            return;
-        }
-        if ((fadeIn && mBgAlpha == 255) || (!fadeIn && mBgAlpha == 0)) {
-            if (DEBUG) Log.v(TAG, "fade is no-op");
-            return;
-        }
-
-        mAnimationTranslateY = getVerticalGridView().getSelectedPosition() == 0
-                ? mMajorFadeTranslateY : mMinorFadeTranslateY;
-
-        if (mFadingStatus == IDLE) {
-            if (fadeIn) {
-                mBgFadeInAnimator.start();
-                mControlRowFadeInAnimator.start();
-                mOtherRowFadeInAnimator.start();
-                mDescriptionFadeInAnimator.start();
-            } else {
-                mBgFadeOutAnimator.start();
-                mControlRowFadeOutAnimator.start();
-                mOtherRowFadeOutAnimator.start();
-                mDescriptionFadeOutAnimator.start();
-            }
-        } else {
-            if (fadeIn) {
-                mBgFadeOutAnimator.reverse();
-                mControlRowFadeOutAnimator.reverse();
-                mOtherRowFadeOutAnimator.reverse();
-                mDescriptionFadeOutAnimator.reverse();
-            } else {
-                mBgFadeInAnimator.reverse();
-                mControlRowFadeInAnimator.reverse();
-                mOtherRowFadeInAnimator.reverse();
-                mDescriptionFadeInAnimator.reverse();
-            }
-        }
-        getView().announceForAccessibility(getString(fadeIn ? R.string.lb_playback_controls_shown
-                : R.string.lb_playback_controls_hidden));
-
-        // If fading in while control row is focused, set initial translationY so
-        // views slide in from below.
-        if (fadeIn && mFadingStatus == IDLE) {
-            final int count = getVerticalGridView().getChildCount();
-            for (int i = 0; i < count; i++) {
-                getVerticalGridView().getChildAt(i).setTranslationY(mAnimationTranslateY);
-            }
-        }
-
-        mFadingStatus = fadeIn ? IN : OUT;
-    }
-
-    /**
-     * Sets the list of rows for the fragment.
-     */
-    @Override
-    public void setAdapter(ObjectAdapter adapter) {
-        if (getAdapter() != null) {
-            getAdapter().unregisterObserver(mObserver);
-        }
-        super.setAdapter(adapter);
-        if (adapter != null) {
-            adapter.registerObserver(mObserver);
-        }
-    }
-
-    @Override
-    protected void setupPresenter(Presenter rowPresenter) {
-        if (rowPresenter instanceof PlaybackRowPresenter) {
-            if (rowPresenter.getFacet(ItemAlignmentFacet.class) == null) {
-                ItemAlignmentFacet itemAlignment = new ItemAlignmentFacet();
-                ItemAlignmentFacet.ItemAlignmentDef def =
-                        new ItemAlignmentFacet.ItemAlignmentDef();
-                def.setItemAlignmentOffset(0);
-                def.setItemAlignmentOffsetPercent(100);
-                itemAlignment.setAlignmentDefs(new ItemAlignmentFacet.ItemAlignmentDef[]
-                        {def});
-                rowPresenter.setFacet(ItemAlignmentFacet.class, itemAlignment);
-            }
-        } else {
-            super.setupPresenter(rowPresenter);
-        }
-    }
-
-    @Override
-    void setVerticalGridViewLayout(VerticalGridView listview) {
-        if (listview == null) {
-            return;
-        }
-
-        // we set the base line of alignment to -paddingBottom
-        listview.setWindowAlignmentOffset(-mPaddingBottom);
-        listview.setWindowAlignmentOffsetPercent(
-                VerticalGridView.WINDOW_ALIGN_OFFSET_PERCENT_DISABLED);
-
-        // align other rows that arent the last to center of screen, since our baseline is
-        // -mPaddingBottom, we need subtract that from mOtherRowsCenterToBottom.
-        listview.setItemAlignmentOffset(mOtherRowsCenterToBottom - mPaddingBottom);
-        listview.setItemAlignmentOffsetPercent(50);
-
-        // Push last row to the bottom padding
-        // Padding affects alignment when last row is focused
-        listview.setPadding(listview.getPaddingLeft(), listview.getPaddingTop(),
-                listview.getPaddingRight(), mPaddingBottom);
-        listview.setWindowAlignment(VerticalGridView.WINDOW_ALIGN_HIGH_EDGE);
-    }
-
-    @Override
-    public void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-
-        mOtherRowsCenterToBottom = getResources()
-                .getDimensionPixelSize(R.dimen.lb_playback_other_rows_center_to_bottom);
-        mPaddingBottom =
-                getResources().getDimensionPixelSize(R.dimen.lb_playback_controls_padding_bottom);
-        mBgDarkColor =
-                getResources().getColor(R.color.lb_playback_controls_background_dark);
-        mBgLightColor =
-                getResources().getColor(R.color.lb_playback_controls_background_light);
-        mShowTimeMs =
-                getResources().getInteger(R.integer.lb_playback_controls_show_time_ms);
-        mMajorFadeTranslateY =
-                getResources().getDimensionPixelSize(R.dimen.lb_playback_major_fade_translate_y);
-        mMinorFadeTranslateY =
-                getResources().getDimensionPixelSize(R.dimen.lb_playback_minor_fade_translate_y);
-
-        loadBgAnimator();
-        loadControlRowAnimator();
-        loadOtherRowAnimator();
-        loadDescriptionAnimator();
-    }
-
-    /**
-     * Sets the background type.
-     *
-     * @param type One of BG_LIGHT, BG_DARK, or BG_NONE.
-     */
-    public void setBackgroundType(int type) {
-        switch (type) {
-        case BG_LIGHT:
-        case BG_DARK:
-        case BG_NONE:
-            if (type != mBackgroundType) {
-                mBackgroundType = type;
-                updateBackground();
-            }
-            break;
-        default:
-            throw new IllegalArgumentException("Invalid background type");
-        }
-    }
-
-    /**
-     * Returns the background type.
-     */
-    public int getBackgroundType() {
-        return mBackgroundType;
-    }
-
-    private void updateBackground() {
-        if (mRootView != null) {
-            int color = mBgDarkColor;
-            switch (mBackgroundType) {
-                case BG_DARK: break;
-                case BG_LIGHT: color = mBgLightColor; break;
-                case BG_NONE: color = Color.TRANSPARENT; break;
-            }
-            mRootView.setBackground(new ColorDrawable(color));
-        }
-    }
-
-    void updateControlsBottomSpace(ItemBridgeAdapter.ViewHolder vh) {
-        // Add extra space between rows 0 and 1
-        if (vh == null && getVerticalGridView() != null) {
-            vh = (ItemBridgeAdapter.ViewHolder)
-                    getVerticalGridView().findViewHolderForPosition(0);
-        }
-        if (vh != null && vh.getPresenter() instanceof PlaybackControlsRowPresenter) {
-            final int adapterSize = getAdapter() == null ? 0 : getAdapter().size();
-            ((PlaybackControlsRowPresenter) vh.getPresenter()).showBottomSpace(
-                    (PlaybackControlsRowPresenter.ViewHolder) vh.getViewHolder(),
-                    adapterSize > 1);
-        }
-    }
-
-    private final ItemBridgeAdapter.AdapterListener mAdapterListener =
-            new ItemBridgeAdapter.AdapterListener() {
-        @Override
-        public void onAttachedToWindow(ItemBridgeAdapter.ViewHolder vh) {
-            if (DEBUG) Log.v(TAG, "onAttachedToWindow " + vh.getViewHolder().view);
-            if ((mFadingStatus == IDLE && mBgAlpha == 0) || mFadingStatus == OUT) {
-                if (DEBUG) Log.v(TAG, "setting alpha to 0");
-                vh.getViewHolder().view.setAlpha(0);
-            }
-            if (vh.getPosition() == 0 && mResetControlsToPrimaryActionsPending) {
-                resetControlsToPrimaryActions(vh);
-            }
-        }
-        @Override
-        public void onDetachedFromWindow(ItemBridgeAdapter.ViewHolder vh) {
-            if (DEBUG) Log.v(TAG, "onDetachedFromWindow " + vh.getViewHolder().view);
-            // Reset animation state
-            vh.getViewHolder().view.setAlpha(1f);
-            vh.getViewHolder().view.setTranslationY(0);
-            if (vh.getViewHolder() instanceof PlaybackControlsRowPresenter.ViewHolder) {
-                Presenter.ViewHolder descriptionVh = ((PlaybackControlsRowPresenter.ViewHolder)
-                        vh.getViewHolder()).mDescriptionViewHolder;
-                if (descriptionVh != null) {
-                    descriptionVh.view.setAlpha(1f);
-                }
-            }
-        }
-        @Override
-        public void onBind(ItemBridgeAdapter.ViewHolder vh) {
-            if (vh.getPosition() == 0) {
-                updateControlsBottomSpace(vh);
-            }
-        }
-    };
-
-    @Override
-    public View onCreateView(LayoutInflater inflater, ViewGroup container,
-            Bundle savedInstanceState) {
-        mRootView = super.onCreateView(inflater, container, savedInstanceState);
-        mBgAlpha = 255;
-        updateBackground();
-        getRowsSupportFragment().setExternalAdapterListener(mAdapterListener);
-        return mRootView;
-    }
-
-    @Override
-    public void onDestroyView() {
-        mRootView = null;
-        if (mHostCallback != null) {
-            mHostCallback.onHostDestroy();
-        }
-        super.onDestroyView();
-    }
-
-    @Override
-    public void onStart() {
-        super.onStart();
-        // Workaround problem VideoView forcing itself to focused, let controls take focus.
-        getRowsSupportFragment().getView().requestFocus();
-        if (mHostCallback != null) {
-            mHostCallback.onHostStart();
-        }
-    }
-
-    private final DataObserver mObserver = new DataObserver() {
-        @Override
-        public void onChanged() {
-            updateControlsBottomSpace(null);
-        }
-    };
-
-    static abstract class AnimatorListener implements Animator.AnimatorListener {
-        ArrayList<View> mViews = new ArrayList<View>();
-        ArrayList<Integer> mLayerType = new ArrayList<Integer>();
-
-        @Override
-        public void onAnimationCancel(Animator animation) {
-        }
-        @Override
-        public void onAnimationRepeat(Animator animation) {
-        }
-        @Override
-        public void onAnimationStart(Animator animation) {
-            getViews(mViews);
-            for (View view : mViews) {
-                mLayerType.add(view.getLayerType());
-                view.setLayerType(View.LAYER_TYPE_HARDWARE, null);
-            }
-        }
-        @Override
-        public void onAnimationEnd(Animator animation) {
-            for (int i = 0; i < mViews.size(); i++) {
-                mViews.get(i).setLayerType(mLayerType.get(i), null);
-            }
-            mLayerType.clear();
-            mViews.clear();
-        }
-        abstract void getViews(ArrayList<View> views);
-
-    };
-}
diff --git a/v17/leanback/src/android/support/v17/leanback/app/RowsFragment.java b/v17/leanback/src/android/support/v17/leanback/app/RowsFragment.java
index 46ad417..a008ad6 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/RowsFragment.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/RowsFragment.java
@@ -19,6 +19,8 @@
 import android.animation.TimeAnimator;
 import android.animation.TimeAnimator.TimeListener;
 import android.os.Bundle;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
 import android.support.v17.leanback.R;
 import android.support.v17.leanback.widget.BaseOnItemViewClickedListener;
 import android.support.v17.leanback.widget.BaseOnItemViewSelectedListener;
@@ -288,7 +290,7 @@
     }
 
     @Override
-    public void onViewCreated(View view, Bundle savedInstanceState) {
+    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
         if (DEBUG) Log.v(TAG, "onViewCreated");
         super.onViewCreated(view, savedInstanceState);
         // Align the top edge of child with id row_content.
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 8e99bd3..2154ff2 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/SearchFragment.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/SearchFragment.java
@@ -55,12 +55,11 @@
  * into a {@link RowsFragment}, in the same way that they are in a {@link
  * BrowseFragment}.
  *
- * <p>If you do not supply a callback via
- * {@link #setSpeechRecognitionCallback(SpeechRecognitionCallback)}, an internal speech
- * recognizer will be used for which your application will need to declare
+ * <p>A SpeechRecognizer object will be created for which your application will need to declare
  * android.permission.RECORD_AUDIO in AndroidManifest file. If app's target version is >= 23 and
  * the device version is >= 23, a permission dialog will show first time using speech recognition.
  * 0 will be used as requestCode in requestPermissions() call.
+ * {@link #setSpeechRecognitionCallback(SpeechRecognitionCallback)} is deprecated.
  * </p>
  * <p>
  * Speech recognition is automatically started when fragment is created, but
@@ -579,8 +578,11 @@
 
     /**
      * Sets this callback to have the fragment pass speech recognition requests
-     * to the activity rather than using an internal recognizer.
+     * to the activity rather than using a SpeechRecognizer object.
+     * @deprecated Launching voice recognition activity is no longer supported. App should declare
+     *             android.permission.RECORD_AUDIO in AndroidManifest file.
      */
+    @Deprecated
     public void setSpeechRecognitionCallback(SpeechRecognitionCallback callback) {
         mSpeechRecognitionCallback = callback;
         if (mSearchBar != null) {
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 e26f5ba..ed2a679 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/SearchSupportFragment.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/SearchSupportFragment.java
@@ -52,12 +52,11 @@
  * into a {@link RowsSupportFragment}, in the same way that they are in a {@link
  * BrowseSupportFragment}.
  *
- * <p>If you do not supply a callback via
- * {@link #setSpeechRecognitionCallback(SpeechRecognitionCallback)}, an internal speech
- * recognizer will be used for which your application will need to declare
+ * <p>A SpeechRecognizer object will be created for which your application will need to declare
  * android.permission.RECORD_AUDIO in AndroidManifest file. If app's target version is >= 23 and
  * the device version is >= 23, a permission dialog will show first time using speech recognition.
  * 0 will be used as requestCode in requestPermissions() call.
+ * {@link #setSpeechRecognitionCallback(SpeechRecognitionCallback)} is deprecated.
  * </p>
  * <p>
  * Speech recognition is automatically started when fragment is created, but
@@ -576,8 +575,11 @@
 
     /**
      * Sets this callback to have the fragment pass speech recognition requests
-     * to the activity rather than using an internal recognizer.
+     * to the activity rather than using a SpeechRecognizer object.
+     * @deprecated Launching voice recognition activity is no longer supported. App should declare
+     *             android.permission.RECORD_AUDIO in AndroidManifest file.
      */
+    @Deprecated
     public void setSpeechRecognitionCallback(SpeechRecognitionCallback callback) {
         mSpeechRecognitionCallback = callback;
         if (mSearchBar != null) {
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/ActionPresenterSelector.java b/v17/leanback/src/android/support/v17/leanback/widget/ActionPresenterSelector.java
index 1ced4d4..a018c2e 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/ActionPresenterSelector.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/ActionPresenterSelector.java
@@ -55,43 +55,13 @@
         }
     }
 
-    static class OneLineActionPresenter extends Presenter {
-        @Override
-        public ViewHolder onCreateViewHolder(ViewGroup parent) {
-            View v = LayoutInflater.from(parent.getContext())
-                .inflate(R.layout.lb_action_1_line, parent, false);
-            return new ActionViewHolder(v, parent.getLayoutDirection());
-        }
-
+    abstract static class ActionPresenter extends Presenter {
         @Override
         public void onBindViewHolder(Presenter.ViewHolder viewHolder, Object item) {
             Action action = (Action) item;
             ActionViewHolder vh = (ActionViewHolder) viewHolder;
             vh.mAction = action;
-            vh.mButton.setText(action.getLabel1());
-        }
-
-        @Override
-        public void onUnbindViewHolder(Presenter.ViewHolder viewHolder) {
-            ((ActionViewHolder) viewHolder).mAction = null;
-        }
-    }
-
-    static class TwoLineActionPresenter extends Presenter {
-        @Override
-        public ViewHolder onCreateViewHolder(ViewGroup parent) {
-            View v = LayoutInflater.from(parent.getContext())
-                .inflate(R.layout.lb_action_2_lines, parent, false);
-            return new ActionViewHolder(v, parent.getLayoutDirection());
-        }
-
-        @Override
-        public void onBindViewHolder(Presenter.ViewHolder viewHolder, Object item) {
-            Action action = (Action) item;
-            ActionViewHolder vh = (ActionViewHolder) viewHolder;
             Drawable icon = action.getIcon();
-            vh.mAction = action;
-
             if (icon != null) {
                 final int startPadding = vh.view.getResources()
                         .getDimensionPixelSize(R.dimen.lb_action_with_icon_padding_start);
@@ -108,6 +78,47 @@
             } else {
                 vh.mButton.setCompoundDrawablesWithIntrinsicBounds(icon, null, null, null);
             }
+        }
+
+        @Override
+        public void onUnbindViewHolder(Presenter.ViewHolder viewHolder) {
+            ActionViewHolder vh = (ActionViewHolder) viewHolder;
+            vh.mButton.setCompoundDrawablesWithIntrinsicBounds(null, null, null, null);
+            vh.view.setPadding(0, 0, 0, 0);
+            vh.mAction = null;
+        }
+    }
+
+    static class OneLineActionPresenter extends ActionPresenter {
+        @Override
+        public ViewHolder onCreateViewHolder(ViewGroup parent) {
+            View v = LayoutInflater.from(parent.getContext())
+                .inflate(R.layout.lb_action_1_line, parent, false);
+            return new ActionViewHolder(v, parent.getLayoutDirection());
+        }
+
+        @Override
+        public void onBindViewHolder(Presenter.ViewHolder viewHolder, Object item) {
+            super.onBindViewHolder(viewHolder, item);
+            ActionViewHolder vh = ((ActionViewHolder) viewHolder);
+            Action action = (Action) item;
+            vh.mButton.setText(action.getLabel1());
+        }
+    }
+
+    static class TwoLineActionPresenter extends ActionPresenter {
+        @Override
+        public ViewHolder onCreateViewHolder(ViewGroup parent) {
+            View v = LayoutInflater.from(parent.getContext())
+                .inflate(R.layout.lb_action_2_lines, parent, false);
+            return new ActionViewHolder(v, parent.getLayoutDirection());
+        }
+
+        @Override
+        public void onBindViewHolder(Presenter.ViewHolder viewHolder, Object item) {
+            super.onBindViewHolder(viewHolder, item);
+            Action action = (Action) item;
+            ActionViewHolder vh = (ActionViewHolder) viewHolder;
 
             CharSequence line1 = action.getLabel1();
             CharSequence line2 = action.getLabel2();
@@ -119,13 +130,5 @@
                 vh.mButton.setText(line1 + "\n" + line2);
             }
         }
-
-        @Override
-        public void onUnbindViewHolder(Presenter.ViewHolder viewHolder) {
-            ActionViewHolder vh = (ActionViewHolder) viewHolder;
-            vh.mButton.setCompoundDrawablesWithIntrinsicBounds(null, null, null, null);
-            vh.view.setPadding(0, 0, 0, 0);
-            vh.mAction = null;
-        }
     }
 }
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/PlaybackControlsRowPresenter.java b/v17/leanback/src/android/support/v17/leanback/widget/PlaybackControlsRowPresenter.java
index 82cfa79..000db3c 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/PlaybackControlsRowPresenter.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/PlaybackControlsRowPresenter.java
@@ -32,7 +32,7 @@
 /**
  * A PlaybackControlsRowPresenter renders a {@link PlaybackControlsRow} to display a
  * series of playback control buttons. Typically this row will be the first row in a fragment
- * such as the {@link android.support.v17.leanback.app.PlaybackOverlayFragment}.
+ * such as the {@link android.support.v17.leanback.app.PlaybackFragment}.
  *
  * <p>The detailed description is rendered using a {@link Presenter} passed in
  * {@link #PlaybackControlsRowPresenter(Presenter)}.  Typically this will be an instance of
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/SearchBar.java b/v17/leanback/src/android/support/v17/leanback/widget/SearchBar.java
index 18f608e..9849341 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/SearchBar.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/SearchBar.java
@@ -495,7 +495,12 @@
 
     /**
      * Sets the speech recognition callback.
+     *
+     * @deprecated Launching voice recognition activity is no longer supported. App should declare
+     *             android.permission.RECORD_AUDIO in AndroidManifest file. See details in
+     *             {@link android.support.v17.leanback.app.SearchSupportFragment}.
      */
+    @Deprecated
     public void setSpeechRecognitionCallback(SpeechRecognitionCallback request) {
         mSpeechRecognitionCallback = request;
         if (mSpeechRecognitionCallback != null && mSpeechRecognizer != null) {
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/SpeechRecognitionCallback.java b/v17/leanback/src/android/support/v17/leanback/widget/SpeechRecognitionCallback.java
index 02b0990..173444d 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/SpeechRecognitionCallback.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/SpeechRecognitionCallback.java
@@ -15,7 +15,12 @@
 
 /**
  * Interface for receiving notification that speech recognition should be initiated.
+ *
+ * @deprecated Launching voice recognition activity is no longer supported. App should declare
+ *             android.permission.RECORD_AUDIO in AndroidManifest file. See details in
+ *             {@link android.support.v17.leanback.app.SearchSupportFragment}.
  */
+@Deprecated
 public interface SpeechRecognitionCallback {
     /**
      * Method invoked when speech recognition should be initiated.
diff --git a/v17/leanback/tests/generatev4.py b/v17/leanback/tests/generatev4.py
index 9e4f935..d87ff6f 100755
--- a/v17/leanback/tests/generatev4.py
+++ b/v17/leanback/tests/generatev4.py
@@ -166,18 +166,3 @@
 file.close()
 outfile.close()
 
-####### generate glue support test #######
-
-print "copy PlaybackControlGlueTest to PlaybackControlSupportGlueTest"
-file = open('java/android/support/v17/leanback/app/PlaybackControlGlueTest.java', 'r')
-outfile = open('java/android/support/v17/leanback/app/PlaybackControlSupportGlueTest.java', 'w')
-outfile.write("// CHECKSTYLE:OFF Generated code\n")
-outfile.write("/* This file is auto-generated from PlaybackControlGlueTest.java.  DO NOT MODIFY. */\n\n")
-for line in file:
-    line = line.replace('PlaybackControlGlue', 'PlaybackControlSupportGlue')
-    line = line.replace('PlaybackOverlayFragment', 'PlaybackOverlaySupportFragment')
-    line = line.replace('PlaybackGlueHostOld', 'PlaybackSupportGlueHostOld')
-    outfile.write(line)
-file.close()
-outfile.close()
-
diff --git a/v17/leanback/tests/java/android/support/v17/leanback/app/PlaybackControlGlueTest.java b/v17/leanback/tests/java/android/support/v17/leanback/app/PlaybackControlGlueTest.java
deleted file mode 100644
index 70c8795..0000000
--- a/v17/leanback/tests/java/android/support/v17/leanback/app/PlaybackControlGlueTest.java
+++ /dev/null
@@ -1,649 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.v17.leanback.app;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-
-import android.content.Context;
-import android.graphics.drawable.Drawable;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.MediumTest;
-import android.support.test.runner.AndroidJUnit4;
-import android.support.v17.leanback.widget.OnItemViewClickedListener;
-import android.support.v17.leanback.widget.PlaybackControlsRow;
-import android.support.v17.leanback.widget.PlaybackRowPresenter;
-import android.support.v17.leanback.widget.Presenter;
-import android.support.v17.leanback.widget.Row;
-import android.support.v17.leanback.widget.RowPresenter;
-import android.support.v17.leanback.widget.SparseArrayObjectAdapter;
-import android.view.KeyEvent;
-import android.view.View;
-
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mockito;
-
-@RunWith(AndroidJUnit4.class)
-@MediumTest
-public class PlaybackControlGlueTest {
-
-
-    static class PlayControlGlueImpl extends PlaybackControlGlue {
-        int mSpeedId = PLAYBACK_SPEED_PAUSED;
-        // number of times onRowChanged callback is called
-        int mOnRowChangedCallCount = 0;
-
-        PlayControlGlueImpl(Context context, int[] seekSpeeds) {
-            super(context, seekSpeeds);
-        }
-
-        PlayControlGlueImpl(Context context, int[] ffSpeeds, int[] rwSpeeds) {
-            super(context, ffSpeeds, rwSpeeds);
-        }
-
-        PlayControlGlueImpl(Context context, PlaybackOverlayFragment fragment,
-                                   int[] seekSpeeds) {
-            super(context, fragment, seekSpeeds);
-        }
-
-        @Override
-        public boolean hasValidMedia() {
-            return true;
-        }
-
-        @Override
-        public boolean isMediaPlaying() {
-            return mSpeedId == PLAYBACK_SPEED_NORMAL;
-        }
-
-        @Override
-        public CharSequence getMediaTitle() {
-            return "DUMP TITLE";
-        }
-
-        @Override
-        public CharSequence getMediaSubtitle() {
-            return "DUMP SUBTITLE";
-        }
-
-        @Override
-        public int getMediaDuration() {
-            return 50000;
-        }
-
-        @Override
-        public Drawable getMediaArt() {
-            return null;
-        }
-
-        @Override
-        public long getSupportedActions() {
-            return ACTION_REWIND | ACTION_FAST_FORWARD | ACTION_PLAY_PAUSE;
-        }
-
-        @Override
-        public int getCurrentSpeedId() {
-            return mSpeedId;
-        }
-
-        @Override
-        public int getCurrentPosition() {
-            return 5000;
-        }
-
-        @Override
-        protected void startPlayback(int speed) {
-            mSpeedId = speed;
-        }
-
-        @Override
-        protected void pausePlayback() {
-            mSpeedId = PLAYBACK_SPEED_PAUSED;
-        }
-
-        @Override
-        protected void skipToNext() {
-        }
-
-        @Override
-        protected void skipToPrevious() {
-        }
-
-        @Override
-        protected void onRowChanged(PlaybackControlsRow row) {
-            mOnRowChangedCallCount++;
-        }
-
-        public void notifyMetaDataChanged() {
-            onMetadataChanged();
-            onStateChanged();
-        }
-
-        public int getOnRowChangedCallCount() {
-            return mOnRowChangedCallCount;
-        }
-    }
-
-    Context context;
-    PlaybackControlGlue glue;
-
-    @Before
-    public void setUp() {
-        context = InstrumentationRegistry.getInstrumentation().getTargetContext();
-        try {
-            InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
-                @Override
-                public void run() {
-                    glue = new PlayControlGlueImpl(context, new int[]{
-                            PlaybackControlGlue.PLAYBACK_SPEED_FAST_L0,
-                            PlaybackControlGlue.PLAYBACK_SPEED_FAST_L1,
-                            PlaybackControlGlue.PLAYBACK_SPEED_FAST_L2
-                    });
-                }
-            });
-        } catch (Throwable throwable) {
-            Assert.fail(throwable.getMessage());
-        }
-    }
-
-    @Test
-    public void testFastForwardToMaxThenReset() {
-        PlaybackControlsRow row = new PlaybackControlsRow();
-        glue.setControlsRow(row);
-        SparseArrayObjectAdapter adapter = (SparseArrayObjectAdapter)
-                row.getPrimaryActionsAdapter();
-        PlaybackControlsRow.MultiAction playPause = (PlaybackControlsRow.MultiAction) adapter
-                .lookup(PlaybackControlGlue.ACTION_PLAY_PAUSE);
-        PlaybackControlsRow.MultiAction fastForward = (PlaybackControlsRow.MultiAction) adapter
-                .lookup(PlaybackControlGlue.ACTION_FAST_FORWARD);
-        PlaybackControlsRow.MultiAction rewind = (PlaybackControlsRow.MultiAction) adapter
-                .lookup(PlaybackControlGlue.ACTION_REWIND);
-
-        assertFalse(glue.isMediaPlaying());
-        glue.onActionClicked(playPause);
-        assertTrue(glue.isMediaPlaying());
-        assertEquals(PlaybackControlGlue.PLAYBACK_SPEED_NORMAL, glue.getCurrentSpeedId());
-        assertEquals(0, fastForward.getIndex());
-        assertEquals(0, rewind.getIndex());
-
-        // click multiple times to reach PLAYBACK_SPEED_FAST_L2
-        glue.onActionClicked(fastForward);
-        assertEquals(PlaybackControlGlue.PLAYBACK_SPEED_FAST_L0, glue.getCurrentSpeedId());
-        assertEquals(1, fastForward.getIndex());
-        assertEquals(0, rewind.getIndex());
-        glue.onActionClicked(fastForward);
-        assertEquals(PlaybackControlGlue.PLAYBACK_SPEED_FAST_L1, glue.getCurrentSpeedId());
-        assertEquals(2, fastForward.getIndex());
-        assertEquals(0, rewind.getIndex());
-        glue.onActionClicked(fastForward);
-        assertEquals(PlaybackControlGlue.PLAYBACK_SPEED_FAST_L2, glue.getCurrentSpeedId());
-        assertEquals(3, fastForward.getIndex());
-        assertEquals(0, rewind.getIndex());
-        glue.onActionClicked(fastForward);
-        assertEquals(PlaybackControlGlue.PLAYBACK_SPEED_FAST_L2, glue.getCurrentSpeedId());
-        assertEquals(3, fastForward.getIndex());
-        assertEquals(0, rewind.getIndex());
-
-        // press playPause again put it back to play
-        glue.onActionClicked(playPause);
-        assertEquals(PlaybackControlGlue.PLAYBACK_SPEED_NORMAL, glue.getCurrentSpeedId());
-        assertEquals(0, fastForward.getIndex());
-        assertEquals(0, rewind.getIndex());
-    }
-
-    @Test
-    public void testFastRewindToMaxThenReset() {
-        PlaybackControlsRow row = new PlaybackControlsRow();
-        glue.setControlsRow(row);
-        SparseArrayObjectAdapter adapter = (SparseArrayObjectAdapter)
-                row.getPrimaryActionsAdapter();
-        PlaybackControlsRow.MultiAction playPause = (PlaybackControlsRow.MultiAction) adapter
-                .lookup(PlaybackControlGlue.ACTION_PLAY_PAUSE);
-        PlaybackControlsRow.MultiAction fastForward = (PlaybackControlsRow.MultiAction) adapter
-                .lookup(PlaybackControlGlue.ACTION_FAST_FORWARD);
-        PlaybackControlsRow.MultiAction rewind = (PlaybackControlsRow.MultiAction) adapter
-                .lookup(PlaybackControlGlue.ACTION_REWIND);
-
-        assertFalse(glue.isMediaPlaying());
-        glue.onActionClicked(playPause);
-        assertTrue(glue.isMediaPlaying());
-        assertEquals(PlaybackControlGlue.PLAYBACK_SPEED_NORMAL, glue.getCurrentSpeedId());
-        assertEquals(0, fastForward.getIndex());
-        assertEquals(0, rewind.getIndex());
-
-        // click multiple times to reach PLAYBACK_SPEED_FAST_L2
-        glue.onActionClicked(rewind);
-        assertEquals(-PlaybackControlGlue.PLAYBACK_SPEED_FAST_L0, glue.getCurrentSpeedId());
-        assertEquals(0, fastForward.getIndex());
-        assertEquals(1, rewind.getIndex());
-        glue.onActionClicked(rewind);
-        assertEquals(-PlaybackControlGlue.PLAYBACK_SPEED_FAST_L1, glue.getCurrentSpeedId());
-        assertEquals(0, fastForward.getIndex());
-        assertEquals(2, rewind.getIndex());
-        glue.onActionClicked(rewind);
-        assertEquals(-PlaybackControlGlue.PLAYBACK_SPEED_FAST_L2, glue.getCurrentSpeedId());
-        assertEquals(0, fastForward.getIndex());
-        assertEquals(3, rewind.getIndex());
-        glue.onActionClicked(rewind);
-        assertEquals(-PlaybackControlGlue.PLAYBACK_SPEED_FAST_L2, glue.getCurrentSpeedId());
-        assertEquals(0, fastForward.getIndex());
-        assertEquals(3, rewind.getIndex());
-
-        // press playPause again put it back to play
-        glue.onActionClicked(playPause);
-        assertEquals(PlaybackControlGlue.PLAYBACK_SPEED_NORMAL, glue.getCurrentSpeedId());
-        assertEquals(0, fastForward.getIndex());
-        assertEquals(0, rewind.getIndex());
-    }
-
-    @Test
-    public void testFastForwardAbortKeyCodes() {
-        PlaybackControlsRow row = new PlaybackControlsRow();
-        glue.setControlsRow(row);
-        SparseArrayObjectAdapter adapter = (SparseArrayObjectAdapter)
-                row.getPrimaryActionsAdapter();
-        PlaybackControlsRow.MultiAction playPause = (PlaybackControlsRow.MultiAction) adapter
-                .lookup(PlaybackControlGlue.ACTION_PLAY_PAUSE);
-        PlaybackControlsRow.MultiAction fastForward = (PlaybackControlsRow.MultiAction) adapter
-                .lookup(PlaybackControlGlue.ACTION_FAST_FORWARD);
-        PlaybackControlsRow.MultiAction rewind = (PlaybackControlsRow.MultiAction) adapter
-                .lookup(PlaybackControlGlue.ACTION_REWIND);
-
-        glue.onActionClicked(playPause);
-        assertTrue(glue.isMediaPlaying());
-        assertEquals(PlaybackControlGlue.PLAYBACK_SPEED_NORMAL, glue.getCurrentSpeedId());
-        assertEquals(0, fastForward.getIndex());
-        assertEquals(0, rewind.getIndex());
-
-        // Testing keycodes that will not abort seek
-        final int[] noAbortSeekKeyCodes = new int[] {
-                KeyEvent.KEYCODE_DPAD_CENTER,
-                KeyEvent.KEYCODE_ENTER
-        };
-        for (int i = 0; i < noAbortSeekKeyCodes.length; i++) {
-            glue.onActionClicked(fastForward);
-            assertEquals(PlaybackControlGlue.PLAYBACK_SPEED_FAST_L0, glue.getCurrentSpeedId());
-            assertEquals(1, fastForward.getIndex());
-            assertEquals(0, rewind.getIndex());
-            KeyEvent kv = new KeyEvent(KeyEvent.ACTION_DOWN, noAbortSeekKeyCodes[i]);
-            glue.onKey(null, noAbortSeekKeyCodes[i], kv);
-            assertEquals(PlaybackControlGlue.PLAYBACK_SPEED_FAST_L0, glue.getCurrentSpeedId());
-            glue.onActionClicked(playPause);
-            assertEquals(PlaybackControlGlue.PLAYBACK_SPEED_NORMAL, glue.getCurrentSpeedId());
-        }
-
-        // Testing abortSeekKeyCodes
-        final int[] abortSeekKeyCodes = new int[] {
-            KeyEvent.KEYCODE_DPAD_UP,
-            KeyEvent.KEYCODE_DPAD_DOWN,
-            KeyEvent.KEYCODE_DPAD_RIGHT,
-            KeyEvent.KEYCODE_DPAD_LEFT,
-            KeyEvent.KEYCODE_BACK,
-            KeyEvent.KEYCODE_ESCAPE
-        };
-        for (int i = 0; i < abortSeekKeyCodes.length; i++) {
-            glue.onActionClicked(fastForward);
-            assertEquals(PlaybackControlGlue.PLAYBACK_SPEED_FAST_L0, glue.getCurrentSpeedId());
-            assertEquals(1, fastForward.getIndex());
-            assertEquals(0, rewind.getIndex());
-            KeyEvent kv = new KeyEvent(KeyEvent.ACTION_DOWN, abortSeekKeyCodes[i]);
-            glue.onKey(null, abortSeekKeyCodes[i], kv);
-            assertEquals(PlaybackControlGlue.PLAYBACK_SPEED_NORMAL, glue.getCurrentSpeedId());
-            assertEquals(0, fastForward.getIndex());
-            assertEquals(0, rewind.getIndex());
-        }
-    }
-
-    @Test
-    public void testRewindAbortKeyCodes() {
-        PlaybackControlsRow row = new PlaybackControlsRow();
-        glue.setControlsRow(row);
-        SparseArrayObjectAdapter adapter = (SparseArrayObjectAdapter)
-                row.getPrimaryActionsAdapter();
-        PlaybackControlsRow.MultiAction playPause = (PlaybackControlsRow.MultiAction) adapter
-                .lookup(PlaybackControlGlue.ACTION_PLAY_PAUSE);
-        PlaybackControlsRow.MultiAction fastForward = (PlaybackControlsRow.MultiAction) adapter
-                .lookup(PlaybackControlGlue.ACTION_FAST_FORWARD);
-        PlaybackControlsRow.MultiAction rewind = (PlaybackControlsRow.MultiAction) adapter
-                .lookup(PlaybackControlGlue.ACTION_REWIND);
-
-        glue.onActionClicked(playPause);
-        assertTrue(glue.isMediaPlaying());
-        assertEquals(PlaybackControlGlue.PLAYBACK_SPEED_NORMAL, glue.getCurrentSpeedId());
-        assertEquals(0, fastForward.getIndex());
-        assertEquals(0, rewind.getIndex());
-
-        // Testing keycodes that will not abort seek
-        final int[] noAbortSeekKeyCodes = new int[] {
-                KeyEvent.KEYCODE_DPAD_CENTER,
-                KeyEvent.KEYCODE_ENTER
-        };
-        for (int i = 0; i < noAbortSeekKeyCodes.length; i++) {
-            glue.onActionClicked(rewind);
-            assertEquals(-PlaybackControlGlue.PLAYBACK_SPEED_FAST_L0, glue.getCurrentSpeedId());
-            assertEquals(0, fastForward.getIndex());
-            assertEquals(1, rewind.getIndex());
-            KeyEvent kv = new KeyEvent(KeyEvent.ACTION_DOWN, noAbortSeekKeyCodes[i]);
-            glue.onKey(null, noAbortSeekKeyCodes[i], kv);
-            assertEquals(-PlaybackControlGlue.PLAYBACK_SPEED_FAST_L0, glue.getCurrentSpeedId());
-            glue.onActionClicked(playPause);
-            assertEquals(PlaybackControlGlue.PLAYBACK_SPEED_NORMAL, glue.getCurrentSpeedId());
-        }
-
-        // Testing abortSeekKeyCodes
-        final int[] abortSeekKeyCodes = new int[] {
-                KeyEvent.KEYCODE_DPAD_UP,
-                KeyEvent.KEYCODE_DPAD_DOWN,
-                KeyEvent.KEYCODE_DPAD_RIGHT,
-                KeyEvent.KEYCODE_DPAD_LEFT,
-                KeyEvent.KEYCODE_BACK,
-                KeyEvent.KEYCODE_ESCAPE
-        };
-        for (int i = 0; i < abortSeekKeyCodes.length; i++) {
-            glue.onActionClicked(rewind);
-            assertEquals(-PlaybackControlGlue.PLAYBACK_SPEED_FAST_L0, glue.getCurrentSpeedId());
-            assertEquals(0, fastForward.getIndex());
-            assertEquals(1, rewind.getIndex());
-            KeyEvent kv = new KeyEvent(KeyEvent.ACTION_DOWN, abortSeekKeyCodes[i]);
-            glue.onKey(null, abortSeekKeyCodes[i], kv);
-            assertEquals(PlaybackControlGlue.PLAYBACK_SPEED_NORMAL, glue.getCurrentSpeedId());
-            assertEquals(0, fastForward.getIndex());
-            assertEquals(0, rewind.getIndex());
-        }
-    }
-
-    @Test
-    public void testMediaPauseButtonOnFF() {
-        PlaybackControlsRow row = new PlaybackControlsRow();
-        glue.setControlsRow(row);
-        SparseArrayObjectAdapter adapter = (SparseArrayObjectAdapter)
-                row.getPrimaryActionsAdapter();
-        PlaybackControlsRow.MultiAction playPause = (PlaybackControlsRow.MultiAction) adapter
-                .lookup(PlaybackControlGlue.ACTION_PLAY_PAUSE);
-        PlaybackControlsRow.MultiAction fastForward = (PlaybackControlsRow.MultiAction) adapter
-                .lookup(PlaybackControlGlue.ACTION_FAST_FORWARD);
-
-        glue.onActionClicked(playPause);
-        glue.onActionClicked(fastForward);
-        assertEquals(PlaybackControlGlue.PLAYBACK_SPEED_FAST_L0, glue.getCurrentSpeedId());
-        glue.onKey(null, KeyEvent.KEYCODE_MEDIA_PAUSE, new KeyEvent(KeyEvent.ACTION_DOWN,
-                KeyEvent.KEYCODE_MEDIA_PAUSE));
-        assertEquals(PlaybackControlGlue.PLAYBACK_SPEED_PAUSED, glue.getCurrentSpeedId());
-    }
-
-    @Test
-    public void testMediaPauseButtonOnPlay() {
-        PlaybackControlsRow row = new PlaybackControlsRow();
-        glue.setControlsRow(row);
-        SparseArrayObjectAdapter adapter = (SparseArrayObjectAdapter)
-                row.getPrimaryActionsAdapter();
-        PlaybackControlsRow.MultiAction playPause = (PlaybackControlsRow.MultiAction) adapter
-                .lookup(PlaybackControlGlue.ACTION_PLAY_PAUSE);
-
-        glue.onActionClicked(playPause);
-        assertEquals(PlaybackControlGlue.PLAYBACK_SPEED_NORMAL, glue.getCurrentSpeedId());
-        glue.onKey(null, KeyEvent.KEYCODE_MEDIA_PAUSE, new KeyEvent(KeyEvent.ACTION_DOWN,
-                KeyEvent.KEYCODE_MEDIA_PAUSE));
-        assertEquals(PlaybackControlGlue.PLAYBACK_SPEED_PAUSED, glue.getCurrentSpeedId());
-    }
-
-    @Test
-    public void testMediaPauseButtonOnPause() {
-        PlaybackControlsRow row = new PlaybackControlsRow();
-        glue.setControlsRow(row);
-        SparseArrayObjectAdapter adapter = (SparseArrayObjectAdapter)
-                row.getPrimaryActionsAdapter();
-        PlaybackControlsRow.MultiAction playPause = (PlaybackControlsRow.MultiAction) adapter
-                .lookup(PlaybackControlGlue.ACTION_PLAY_PAUSE);
-
-        glue.onActionClicked(playPause);
-        glue.onActionClicked(playPause);
-        assertEquals(PlaybackControlGlue.PLAYBACK_SPEED_PAUSED, glue.getCurrentSpeedId());
-        glue.onKey(null, KeyEvent.KEYCODE_MEDIA_PAUSE, new KeyEvent(KeyEvent.ACTION_DOWN,
-                KeyEvent.KEYCODE_MEDIA_PAUSE));
-        assertEquals(PlaybackControlGlue.PLAYBACK_SPEED_PAUSED, glue.getCurrentSpeedId());
-    }
-
-    @Test
-    public void testMediaPlayButtonOnFF() {
-        PlaybackControlsRow row = new PlaybackControlsRow();
-        glue.setControlsRow(row);
-        SparseArrayObjectAdapter adapter = (SparseArrayObjectAdapter)
-                row.getPrimaryActionsAdapter();
-        PlaybackControlsRow.MultiAction playPause = (PlaybackControlsRow.MultiAction) adapter
-                .lookup(PlaybackControlGlue.ACTION_PLAY_PAUSE);
-        PlaybackControlsRow.MultiAction fastForward = (PlaybackControlsRow.MultiAction) adapter
-                .lookup(PlaybackControlGlue.ACTION_FAST_FORWARD);
-
-        glue.onActionClicked(playPause);
-        glue.onActionClicked(fastForward);
-        assertEquals(PlaybackControlGlue.PLAYBACK_SPEED_FAST_L0, glue.getCurrentSpeedId());
-        glue.onKey(null, KeyEvent.KEYCODE_MEDIA_PLAY, new KeyEvent(KeyEvent.ACTION_DOWN,
-                KeyEvent.KEYCODE_MEDIA_PLAY));
-        assertEquals(PlaybackControlGlue.PLAYBACK_SPEED_NORMAL, glue.getCurrentSpeedId());
-    }
-
-    @Test
-    public void testMediaPlayButtonOnPlay() {
-        PlaybackControlsRow row = new PlaybackControlsRow();
-        glue.setControlsRow(row);
-        SparseArrayObjectAdapter adapter = (SparseArrayObjectAdapter)
-                row.getPrimaryActionsAdapter();
-        PlaybackControlsRow.MultiAction playPause = (PlaybackControlsRow.MultiAction) adapter
-                .lookup(PlaybackControlGlue.ACTION_PLAY_PAUSE);
-
-        glue.onActionClicked(playPause);
-        assertEquals(PlaybackControlGlue.PLAYBACK_SPEED_NORMAL, glue.getCurrentSpeedId());
-        glue.onKey(null, KeyEvent.KEYCODE_MEDIA_PLAY, new KeyEvent(KeyEvent.ACTION_DOWN,
-                KeyEvent.KEYCODE_MEDIA_PLAY));
-        assertEquals(PlaybackControlGlue.PLAYBACK_SPEED_NORMAL, glue.getCurrentSpeedId());
-    }
-
-    @Test
-    public void testMediaPlayButtonOnPause() {
-        PlaybackControlsRow row = new PlaybackControlsRow();
-        glue.setControlsRow(row);
-        SparseArrayObjectAdapter adapter = (SparseArrayObjectAdapter)
-                row.getPrimaryActionsAdapter();
-        PlaybackControlsRow.MultiAction playPause = (PlaybackControlsRow.MultiAction) adapter
-                .lookup(PlaybackControlGlue.ACTION_PLAY_PAUSE);
-
-        glue.onActionClicked(playPause);
-        glue.onActionClicked(playPause);
-        assertEquals(PlaybackControlGlue.PLAYBACK_SPEED_PAUSED, glue.getCurrentSpeedId());
-        glue.onKey(null, KeyEvent.KEYCODE_MEDIA_PLAY, new KeyEvent(KeyEvent.ACTION_DOWN,
-                KeyEvent.KEYCODE_MEDIA_PLAY));
-        assertEquals(PlaybackControlGlue.PLAYBACK_SPEED_NORMAL, glue.getCurrentSpeedId());
-    }
-
-    @Test
-    public void testMediaPlayPauseButtonOnFF() {
-        PlaybackControlsRow row = new PlaybackControlsRow();
-        glue.setControlsRow(row);
-        SparseArrayObjectAdapter adapter = (SparseArrayObjectAdapter)
-                row.getPrimaryActionsAdapter();
-        PlaybackControlsRow.MultiAction playPause = (PlaybackControlsRow.MultiAction) adapter
-                .lookup(PlaybackControlGlue.ACTION_PLAY_PAUSE);
-        PlaybackControlsRow.MultiAction fastForward = (PlaybackControlsRow.MultiAction) adapter
-                .lookup(PlaybackControlGlue.ACTION_FAST_FORWARD);
-
-        glue.onActionClicked(playPause);
-        glue.onActionClicked(fastForward);
-        assertEquals(PlaybackControlGlue.PLAYBACK_SPEED_FAST_L0, glue.getCurrentSpeedId());
-        glue.onKey(null, KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE, new KeyEvent(KeyEvent.ACTION_DOWN,
-                KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE));
-        assertEquals(PlaybackControlGlue.PLAYBACK_SPEED_NORMAL, glue.getCurrentSpeedId());
-    }
-
-    @Test
-    public void testMediaPlayPauseButtonOnPlay() {
-        PlaybackControlsRow row = new PlaybackControlsRow();
-        glue.setControlsRow(row);
-        SparseArrayObjectAdapter adapter = (SparseArrayObjectAdapter)
-                row.getPrimaryActionsAdapter();
-        PlaybackControlsRow.MultiAction playPause = (PlaybackControlsRow.MultiAction) adapter
-                .lookup(PlaybackControlGlue.ACTION_PLAY_PAUSE);
-
-        glue.onActionClicked(playPause);
-        assertEquals(PlaybackControlGlue.PLAYBACK_SPEED_NORMAL, glue.getCurrentSpeedId());
-        glue.onKey(null, KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE, new KeyEvent(KeyEvent.ACTION_DOWN,
-                KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE));
-        assertEquals(PlaybackControlGlue.PLAYBACK_SPEED_PAUSED, glue.getCurrentSpeedId());
-    }
-
-    @Test
-    public void testMediaPlayPauseButtonOnPause() {
-        PlaybackControlsRow row = new PlaybackControlsRow();
-        glue.setControlsRow(row);
-        SparseArrayObjectAdapter adapter = (SparseArrayObjectAdapter)
-                row.getPrimaryActionsAdapter();
-        PlaybackControlsRow.MultiAction playPause = (PlaybackControlsRow.MultiAction) adapter
-                .lookup(PlaybackControlGlue.ACTION_PLAY_PAUSE);
-
-        glue.onActionClicked(playPause);
-        glue.onActionClicked(playPause);
-        assertEquals(PlaybackControlGlue.PLAYBACK_SPEED_PAUSED, glue.getCurrentSpeedId());
-        glue.onKey(null, KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE, new KeyEvent(KeyEvent.ACTION_DOWN,
-                KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE));
-        assertEquals(PlaybackControlGlue.PLAYBACK_SPEED_NORMAL, glue.getCurrentSpeedId());
-    }
-
-    @Test
-    public void testOnItemClickedListener() {
-        PlaybackControlsRow row = new PlaybackControlsRow();
-        final PlaybackOverlayFragment[] fragmentResult = new PlaybackOverlayFragment[1];
-        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
-            @Override
-            public void run() {
-                fragmentResult[0] = new PlaybackOverlayFragment();
-            }
-        });
-        PlaybackOverlayFragment fragment = fragmentResult[0];
-        glue.setHost(new PlaybackControlGlue.PlaybackGlueHostOld(fragment));
-        glue.setControlsRow(row);
-        SparseArrayObjectAdapter adapter = (SparseArrayObjectAdapter)
-                row.getPrimaryActionsAdapter();
-        PlaybackControlsRow.MultiAction playPause = (PlaybackControlsRow.MultiAction) adapter
-                .lookup(PlaybackControlGlue.ACTION_PLAY_PAUSE);
-        OnItemViewClickedListener listener = Mockito.mock(OnItemViewClickedListener.class);
-        glue.setOnItemViewClickedListener(listener);
-
-        // create fake row ViewHolder and fade item ViewHolder
-        View rowView = new View(context);
-        View view = new View(context);
-        PlaybackRowPresenter.ViewHolder rowVh = new PlaybackRowPresenter.ViewHolder(rowView);
-        Presenter.ViewHolder vh = new Presenter.ViewHolder(view);
-
-        // Initially media is paused
-        assertEquals(PlaybackControlGlue.PLAYBACK_SPEED_PAUSED, glue.getCurrentSpeedId());
-
-        // simulate a click inside PlaybackOverlayFragment's PlaybackRow.
-        fragment.getOnItemViewClickedListener().onItemClicked(vh, playPause, rowVh, row);
-        verify(listener, times(0)).onItemClicked(vh, playPause, rowVh, row);
-        assertEquals(PlaybackControlGlue.PLAYBACK_SPEED_NORMAL, glue.getCurrentSpeedId());
-
-        // simulate a click on object other than PlaybackRow.
-        Object regularItem = new Object();
-        Row regularRow = new Row();
-        RowPresenter.ViewHolder regularRowViewHolder = new RowPresenter.ViewHolder(rowView);
-        Presenter.ViewHolder regularViewHOlder = new Presenter.ViewHolder(view);
-        fragment.getOnItemViewClickedListener().onItemClicked(regularViewHOlder, regularItem,
-                regularRowViewHolder, regularRow);
-        verify(listener, times(1)).onItemClicked(regularViewHOlder, regularItem,
-                regularRowViewHolder, regularRow);
-        assertEquals(PlaybackControlGlue.PLAYBACK_SPEED_NORMAL, glue.getCurrentSpeedId());
-    }
-
-    @Test
-    public void testOnRowChangedCallback() throws Exception {
-        final PlaybackOverlayFragment[] fragmentResult = new
-                PlaybackOverlayFragment[1];
-        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
-            @Override
-            public void run() {
-                fragmentResult[0] = new PlaybackOverlayFragment();
-            }
-        });
-        PlaybackOverlayFragment fragment = fragmentResult[0];
-        PlayControlGlueImpl playbackGlue = new PlayControlGlueImpl(context, fragment,
-                new int[]{
-                        PlaybackControlGlue.PLAYBACK_SPEED_FAST_L0,
-                        PlaybackControlGlue.PLAYBACK_SPEED_FAST_L1,
-                        PlaybackControlGlue.PLAYBACK_SPEED_FAST_L2
-                });
-
-        // before any controls row is created the count is zero
-        assertEquals(playbackGlue.getOnRowChangedCallCount(), 0);
-        playbackGlue.createControlsRowAndPresenter();
-        // after a controls row is created, onRowChanged() call back is called once
-        assertEquals(playbackGlue.getOnRowChangedCallCount(), 1);
-        assertEquals(3, playbackGlue.getControlsRow().getPrimaryActionsAdapter().size());
-        playbackGlue.notifyMetaDataChanged();
-        // onMetaDataChanged() calls updateRowMetadata which ends up calling
-        // notifyPlaybackRowChanged on the old host and finally onRowChanged on the glue.
-        assertEquals(playbackGlue.getOnRowChangedCallCount(), 2);
-        assertEquals(3, playbackGlue.getControlsRow().getPrimaryActionsAdapter().size());
-    }
-
-
-    @Test
-    public void testWithoutValidMedia() throws Exception {
-        final PlaybackOverlayFragment[] fragmentResult = new
-                PlaybackOverlayFragment[1];
-        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
-            @Override
-            public void run() {
-                fragmentResult[0] = new PlaybackOverlayFragment();
-            }
-        });
-        final boolean[] hasValidMedia = new boolean[] {false};
-        PlaybackOverlayFragment fragment = fragmentResult[0];
-        PlayControlGlueImpl playbackGlue = new PlayControlGlueImpl(context, fragment,
-                new int[]{
-                        PlaybackControlGlue.PLAYBACK_SPEED_FAST_L0,
-                        PlaybackControlGlue.PLAYBACK_SPEED_FAST_L1,
-                        PlaybackControlGlue.PLAYBACK_SPEED_FAST_L2
-                }) {
-            @Override
-            public boolean hasValidMedia() {
-                return hasValidMedia[0];
-            }
-        };
-
-        // before any controls row is created the count is zero
-        assertEquals(playbackGlue.getOnRowChangedCallCount(), 0);
-        playbackGlue.createControlsRowAndPresenter();
-        // after a controls row is created, onRowChanged() call back is called once
-        assertEquals(playbackGlue.getOnRowChangedCallCount(), 1);
-        // enven hasValidMedia() is false, we should still have three buttons.
-        assertEquals(3, playbackGlue.getControlsRow().getPrimaryActionsAdapter().size());
-
-        hasValidMedia[0] = true;
-        playbackGlue.notifyMetaDataChanged();
-        // onMetaDataChanged() calls updateRowMetadata which ends up calling
-        // notifyPlaybackRowChanged on the old host and finally onRowChanged on the glue.
-        assertEquals(playbackGlue.getOnRowChangedCallCount(), 2);
-        assertEquals(3, playbackGlue.getControlsRow().getPrimaryActionsAdapter().size());
-    }
-
-}
diff --git a/v17/leanback/tests/java/android/support/v17/leanback/app/PlaybackControlSupportGlueTest.java b/v17/leanback/tests/java/android/support/v17/leanback/app/PlaybackControlSupportGlueTest.java
deleted file mode 100644
index 37f5754..0000000
--- a/v17/leanback/tests/java/android/support/v17/leanback/app/PlaybackControlSupportGlueTest.java
+++ /dev/null
@@ -1,652 +0,0 @@
-// CHECKSTYLE:OFF Generated code
-/* This file is auto-generated from PlaybackControlGlueTest.java.  DO NOT MODIFY. */
-
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.v17.leanback.app;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-
-import android.content.Context;
-import android.graphics.drawable.Drawable;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.MediumTest;
-import android.support.test.runner.AndroidJUnit4;
-import android.support.v17.leanback.widget.OnItemViewClickedListener;
-import android.support.v17.leanback.widget.PlaybackControlsRow;
-import android.support.v17.leanback.widget.PlaybackRowPresenter;
-import android.support.v17.leanback.widget.Presenter;
-import android.support.v17.leanback.widget.Row;
-import android.support.v17.leanback.widget.RowPresenter;
-import android.support.v17.leanback.widget.SparseArrayObjectAdapter;
-import android.view.KeyEvent;
-import android.view.View;
-
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mockito;
-
-@RunWith(AndroidJUnit4.class)
-@MediumTest
-public class PlaybackControlSupportGlueTest {
-
-
-    static class PlayControlGlueImpl extends PlaybackControlSupportGlue {
-        int mSpeedId = PLAYBACK_SPEED_PAUSED;
-        // number of times onRowChanged callback is called
-        int mOnRowChangedCallCount = 0;
-
-        PlayControlGlueImpl(Context context, int[] seekSpeeds) {
-            super(context, seekSpeeds);
-        }
-
-        PlayControlGlueImpl(Context context, int[] ffSpeeds, int[] rwSpeeds) {
-            super(context, ffSpeeds, rwSpeeds);
-        }
-
-        PlayControlGlueImpl(Context context, PlaybackOverlaySupportFragment fragment,
-                                   int[] seekSpeeds) {
-            super(context, fragment, seekSpeeds);
-        }
-
-        @Override
-        public boolean hasValidMedia() {
-            return true;
-        }
-
-        @Override
-        public boolean isMediaPlaying() {
-            return mSpeedId == PLAYBACK_SPEED_NORMAL;
-        }
-
-        @Override
-        public CharSequence getMediaTitle() {
-            return "DUMP TITLE";
-        }
-
-        @Override
-        public CharSequence getMediaSubtitle() {
-            return "DUMP SUBTITLE";
-        }
-
-        @Override
-        public int getMediaDuration() {
-            return 50000;
-        }
-
-        @Override
-        public Drawable getMediaArt() {
-            return null;
-        }
-
-        @Override
-        public long getSupportedActions() {
-            return ACTION_REWIND | ACTION_FAST_FORWARD | ACTION_PLAY_PAUSE;
-        }
-
-        @Override
-        public int getCurrentSpeedId() {
-            return mSpeedId;
-        }
-
-        @Override
-        public int getCurrentPosition() {
-            return 5000;
-        }
-
-        @Override
-        protected void startPlayback(int speed) {
-            mSpeedId = speed;
-        }
-
-        @Override
-        protected void pausePlayback() {
-            mSpeedId = PLAYBACK_SPEED_PAUSED;
-        }
-
-        @Override
-        protected void skipToNext() {
-        }
-
-        @Override
-        protected void skipToPrevious() {
-        }
-
-        @Override
-        protected void onRowChanged(PlaybackControlsRow row) {
-            mOnRowChangedCallCount++;
-        }
-
-        public void notifyMetaDataChanged() {
-            onMetadataChanged();
-            onStateChanged();
-        }
-
-        public int getOnRowChangedCallCount() {
-            return mOnRowChangedCallCount;
-        }
-    }
-
-    Context context;
-    PlaybackControlSupportGlue glue;
-
-    @Before
-    public void setUp() {
-        context = InstrumentationRegistry.getInstrumentation().getTargetContext();
-        try {
-            InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
-                @Override
-                public void run() {
-                    glue = new PlayControlGlueImpl(context, new int[]{
-                            PlaybackControlSupportGlue.PLAYBACK_SPEED_FAST_L0,
-                            PlaybackControlSupportGlue.PLAYBACK_SPEED_FAST_L1,
-                            PlaybackControlSupportGlue.PLAYBACK_SPEED_FAST_L2
-                    });
-                }
-            });
-        } catch (Throwable throwable) {
-            Assert.fail(throwable.getMessage());
-        }
-    }
-
-    @Test
-    public void testFastForwardToMaxThenReset() {
-        PlaybackControlsRow row = new PlaybackControlsRow();
-        glue.setControlsRow(row);
-        SparseArrayObjectAdapter adapter = (SparseArrayObjectAdapter)
-                row.getPrimaryActionsAdapter();
-        PlaybackControlsRow.MultiAction playPause = (PlaybackControlsRow.MultiAction) adapter
-                .lookup(PlaybackControlSupportGlue.ACTION_PLAY_PAUSE);
-        PlaybackControlsRow.MultiAction fastForward = (PlaybackControlsRow.MultiAction) adapter
-                .lookup(PlaybackControlSupportGlue.ACTION_FAST_FORWARD);
-        PlaybackControlsRow.MultiAction rewind = (PlaybackControlsRow.MultiAction) adapter
-                .lookup(PlaybackControlSupportGlue.ACTION_REWIND);
-
-        assertFalse(glue.isMediaPlaying());
-        glue.onActionClicked(playPause);
-        assertTrue(glue.isMediaPlaying());
-        assertEquals(PlaybackControlSupportGlue.PLAYBACK_SPEED_NORMAL, glue.getCurrentSpeedId());
-        assertEquals(0, fastForward.getIndex());
-        assertEquals(0, rewind.getIndex());
-
-        // click multiple times to reach PLAYBACK_SPEED_FAST_L2
-        glue.onActionClicked(fastForward);
-        assertEquals(PlaybackControlSupportGlue.PLAYBACK_SPEED_FAST_L0, glue.getCurrentSpeedId());
-        assertEquals(1, fastForward.getIndex());
-        assertEquals(0, rewind.getIndex());
-        glue.onActionClicked(fastForward);
-        assertEquals(PlaybackControlSupportGlue.PLAYBACK_SPEED_FAST_L1, glue.getCurrentSpeedId());
-        assertEquals(2, fastForward.getIndex());
-        assertEquals(0, rewind.getIndex());
-        glue.onActionClicked(fastForward);
-        assertEquals(PlaybackControlSupportGlue.PLAYBACK_SPEED_FAST_L2, glue.getCurrentSpeedId());
-        assertEquals(3, fastForward.getIndex());
-        assertEquals(0, rewind.getIndex());
-        glue.onActionClicked(fastForward);
-        assertEquals(PlaybackControlSupportGlue.PLAYBACK_SPEED_FAST_L2, glue.getCurrentSpeedId());
-        assertEquals(3, fastForward.getIndex());
-        assertEquals(0, rewind.getIndex());
-
-        // press playPause again put it back to play
-        glue.onActionClicked(playPause);
-        assertEquals(PlaybackControlSupportGlue.PLAYBACK_SPEED_NORMAL, glue.getCurrentSpeedId());
-        assertEquals(0, fastForward.getIndex());
-        assertEquals(0, rewind.getIndex());
-    }
-
-    @Test
-    public void testFastRewindToMaxThenReset() {
-        PlaybackControlsRow row = new PlaybackControlsRow();
-        glue.setControlsRow(row);
-        SparseArrayObjectAdapter adapter = (SparseArrayObjectAdapter)
-                row.getPrimaryActionsAdapter();
-        PlaybackControlsRow.MultiAction playPause = (PlaybackControlsRow.MultiAction) adapter
-                .lookup(PlaybackControlSupportGlue.ACTION_PLAY_PAUSE);
-        PlaybackControlsRow.MultiAction fastForward = (PlaybackControlsRow.MultiAction) adapter
-                .lookup(PlaybackControlSupportGlue.ACTION_FAST_FORWARD);
-        PlaybackControlsRow.MultiAction rewind = (PlaybackControlsRow.MultiAction) adapter
-                .lookup(PlaybackControlSupportGlue.ACTION_REWIND);
-
-        assertFalse(glue.isMediaPlaying());
-        glue.onActionClicked(playPause);
-        assertTrue(glue.isMediaPlaying());
-        assertEquals(PlaybackControlSupportGlue.PLAYBACK_SPEED_NORMAL, glue.getCurrentSpeedId());
-        assertEquals(0, fastForward.getIndex());
-        assertEquals(0, rewind.getIndex());
-
-        // click multiple times to reach PLAYBACK_SPEED_FAST_L2
-        glue.onActionClicked(rewind);
-        assertEquals(-PlaybackControlSupportGlue.PLAYBACK_SPEED_FAST_L0, glue.getCurrentSpeedId());
-        assertEquals(0, fastForward.getIndex());
-        assertEquals(1, rewind.getIndex());
-        glue.onActionClicked(rewind);
-        assertEquals(-PlaybackControlSupportGlue.PLAYBACK_SPEED_FAST_L1, glue.getCurrentSpeedId());
-        assertEquals(0, fastForward.getIndex());
-        assertEquals(2, rewind.getIndex());
-        glue.onActionClicked(rewind);
-        assertEquals(-PlaybackControlSupportGlue.PLAYBACK_SPEED_FAST_L2, glue.getCurrentSpeedId());
-        assertEquals(0, fastForward.getIndex());
-        assertEquals(3, rewind.getIndex());
-        glue.onActionClicked(rewind);
-        assertEquals(-PlaybackControlSupportGlue.PLAYBACK_SPEED_FAST_L2, glue.getCurrentSpeedId());
-        assertEquals(0, fastForward.getIndex());
-        assertEquals(3, rewind.getIndex());
-
-        // press playPause again put it back to play
-        glue.onActionClicked(playPause);
-        assertEquals(PlaybackControlSupportGlue.PLAYBACK_SPEED_NORMAL, glue.getCurrentSpeedId());
-        assertEquals(0, fastForward.getIndex());
-        assertEquals(0, rewind.getIndex());
-    }
-
-    @Test
-    public void testFastForwardAbortKeyCodes() {
-        PlaybackControlsRow row = new PlaybackControlsRow();
-        glue.setControlsRow(row);
-        SparseArrayObjectAdapter adapter = (SparseArrayObjectAdapter)
-                row.getPrimaryActionsAdapter();
-        PlaybackControlsRow.MultiAction playPause = (PlaybackControlsRow.MultiAction) adapter
-                .lookup(PlaybackControlSupportGlue.ACTION_PLAY_PAUSE);
-        PlaybackControlsRow.MultiAction fastForward = (PlaybackControlsRow.MultiAction) adapter
-                .lookup(PlaybackControlSupportGlue.ACTION_FAST_FORWARD);
-        PlaybackControlsRow.MultiAction rewind = (PlaybackControlsRow.MultiAction) adapter
-                .lookup(PlaybackControlSupportGlue.ACTION_REWIND);
-
-        glue.onActionClicked(playPause);
-        assertTrue(glue.isMediaPlaying());
-        assertEquals(PlaybackControlSupportGlue.PLAYBACK_SPEED_NORMAL, glue.getCurrentSpeedId());
-        assertEquals(0, fastForward.getIndex());
-        assertEquals(0, rewind.getIndex());
-
-        // Testing keycodes that will not abort seek
-        final int[] noAbortSeekKeyCodes = new int[] {
-                KeyEvent.KEYCODE_DPAD_CENTER,
-                KeyEvent.KEYCODE_ENTER
-        };
-        for (int i = 0; i < noAbortSeekKeyCodes.length; i++) {
-            glue.onActionClicked(fastForward);
-            assertEquals(PlaybackControlSupportGlue.PLAYBACK_SPEED_FAST_L0, glue.getCurrentSpeedId());
-            assertEquals(1, fastForward.getIndex());
-            assertEquals(0, rewind.getIndex());
-            KeyEvent kv = new KeyEvent(KeyEvent.ACTION_DOWN, noAbortSeekKeyCodes[i]);
-            glue.onKey(null, noAbortSeekKeyCodes[i], kv);
-            assertEquals(PlaybackControlSupportGlue.PLAYBACK_SPEED_FAST_L0, glue.getCurrentSpeedId());
-            glue.onActionClicked(playPause);
-            assertEquals(PlaybackControlSupportGlue.PLAYBACK_SPEED_NORMAL, glue.getCurrentSpeedId());
-        }
-
-        // Testing abortSeekKeyCodes
-        final int[] abortSeekKeyCodes = new int[] {
-            KeyEvent.KEYCODE_DPAD_UP,
-            KeyEvent.KEYCODE_DPAD_DOWN,
-            KeyEvent.KEYCODE_DPAD_RIGHT,
-            KeyEvent.KEYCODE_DPAD_LEFT,
-            KeyEvent.KEYCODE_BACK,
-            KeyEvent.KEYCODE_ESCAPE
-        };
-        for (int i = 0; i < abortSeekKeyCodes.length; i++) {
-            glue.onActionClicked(fastForward);
-            assertEquals(PlaybackControlSupportGlue.PLAYBACK_SPEED_FAST_L0, glue.getCurrentSpeedId());
-            assertEquals(1, fastForward.getIndex());
-            assertEquals(0, rewind.getIndex());
-            KeyEvent kv = new KeyEvent(KeyEvent.ACTION_DOWN, abortSeekKeyCodes[i]);
-            glue.onKey(null, abortSeekKeyCodes[i], kv);
-            assertEquals(PlaybackControlSupportGlue.PLAYBACK_SPEED_NORMAL, glue.getCurrentSpeedId());
-            assertEquals(0, fastForward.getIndex());
-            assertEquals(0, rewind.getIndex());
-        }
-    }
-
-    @Test
-    public void testRewindAbortKeyCodes() {
-        PlaybackControlsRow row = new PlaybackControlsRow();
-        glue.setControlsRow(row);
-        SparseArrayObjectAdapter adapter = (SparseArrayObjectAdapter)
-                row.getPrimaryActionsAdapter();
-        PlaybackControlsRow.MultiAction playPause = (PlaybackControlsRow.MultiAction) adapter
-                .lookup(PlaybackControlSupportGlue.ACTION_PLAY_PAUSE);
-        PlaybackControlsRow.MultiAction fastForward = (PlaybackControlsRow.MultiAction) adapter
-                .lookup(PlaybackControlSupportGlue.ACTION_FAST_FORWARD);
-        PlaybackControlsRow.MultiAction rewind = (PlaybackControlsRow.MultiAction) adapter
-                .lookup(PlaybackControlSupportGlue.ACTION_REWIND);
-
-        glue.onActionClicked(playPause);
-        assertTrue(glue.isMediaPlaying());
-        assertEquals(PlaybackControlSupportGlue.PLAYBACK_SPEED_NORMAL, glue.getCurrentSpeedId());
-        assertEquals(0, fastForward.getIndex());
-        assertEquals(0, rewind.getIndex());
-
-        // Testing keycodes that will not abort seek
-        final int[] noAbortSeekKeyCodes = new int[] {
-                KeyEvent.KEYCODE_DPAD_CENTER,
-                KeyEvent.KEYCODE_ENTER
-        };
-        for (int i = 0; i < noAbortSeekKeyCodes.length; i++) {
-            glue.onActionClicked(rewind);
-            assertEquals(-PlaybackControlSupportGlue.PLAYBACK_SPEED_FAST_L0, glue.getCurrentSpeedId());
-            assertEquals(0, fastForward.getIndex());
-            assertEquals(1, rewind.getIndex());
-            KeyEvent kv = new KeyEvent(KeyEvent.ACTION_DOWN, noAbortSeekKeyCodes[i]);
-            glue.onKey(null, noAbortSeekKeyCodes[i], kv);
-            assertEquals(-PlaybackControlSupportGlue.PLAYBACK_SPEED_FAST_L0, glue.getCurrentSpeedId());
-            glue.onActionClicked(playPause);
-            assertEquals(PlaybackControlSupportGlue.PLAYBACK_SPEED_NORMAL, glue.getCurrentSpeedId());
-        }
-
-        // Testing abortSeekKeyCodes
-        final int[] abortSeekKeyCodes = new int[] {
-                KeyEvent.KEYCODE_DPAD_UP,
-                KeyEvent.KEYCODE_DPAD_DOWN,
-                KeyEvent.KEYCODE_DPAD_RIGHT,
-                KeyEvent.KEYCODE_DPAD_LEFT,
-                KeyEvent.KEYCODE_BACK,
-                KeyEvent.KEYCODE_ESCAPE
-        };
-        for (int i = 0; i < abortSeekKeyCodes.length; i++) {
-            glue.onActionClicked(rewind);
-            assertEquals(-PlaybackControlSupportGlue.PLAYBACK_SPEED_FAST_L0, glue.getCurrentSpeedId());
-            assertEquals(0, fastForward.getIndex());
-            assertEquals(1, rewind.getIndex());
-            KeyEvent kv = new KeyEvent(KeyEvent.ACTION_DOWN, abortSeekKeyCodes[i]);
-            glue.onKey(null, abortSeekKeyCodes[i], kv);
-            assertEquals(PlaybackControlSupportGlue.PLAYBACK_SPEED_NORMAL, glue.getCurrentSpeedId());
-            assertEquals(0, fastForward.getIndex());
-            assertEquals(0, rewind.getIndex());
-        }
-    }
-
-    @Test
-    public void testMediaPauseButtonOnFF() {
-        PlaybackControlsRow row = new PlaybackControlsRow();
-        glue.setControlsRow(row);
-        SparseArrayObjectAdapter adapter = (SparseArrayObjectAdapter)
-                row.getPrimaryActionsAdapter();
-        PlaybackControlsRow.MultiAction playPause = (PlaybackControlsRow.MultiAction) adapter
-                .lookup(PlaybackControlSupportGlue.ACTION_PLAY_PAUSE);
-        PlaybackControlsRow.MultiAction fastForward = (PlaybackControlsRow.MultiAction) adapter
-                .lookup(PlaybackControlSupportGlue.ACTION_FAST_FORWARD);
-
-        glue.onActionClicked(playPause);
-        glue.onActionClicked(fastForward);
-        assertEquals(PlaybackControlSupportGlue.PLAYBACK_SPEED_FAST_L0, glue.getCurrentSpeedId());
-        glue.onKey(null, KeyEvent.KEYCODE_MEDIA_PAUSE, new KeyEvent(KeyEvent.ACTION_DOWN,
-                KeyEvent.KEYCODE_MEDIA_PAUSE));
-        assertEquals(PlaybackControlSupportGlue.PLAYBACK_SPEED_PAUSED, glue.getCurrentSpeedId());
-    }
-
-    @Test
-    public void testMediaPauseButtonOnPlay() {
-        PlaybackControlsRow row = new PlaybackControlsRow();
-        glue.setControlsRow(row);
-        SparseArrayObjectAdapter adapter = (SparseArrayObjectAdapter)
-                row.getPrimaryActionsAdapter();
-        PlaybackControlsRow.MultiAction playPause = (PlaybackControlsRow.MultiAction) adapter
-                .lookup(PlaybackControlSupportGlue.ACTION_PLAY_PAUSE);
-
-        glue.onActionClicked(playPause);
-        assertEquals(PlaybackControlSupportGlue.PLAYBACK_SPEED_NORMAL, glue.getCurrentSpeedId());
-        glue.onKey(null, KeyEvent.KEYCODE_MEDIA_PAUSE, new KeyEvent(KeyEvent.ACTION_DOWN,
-                KeyEvent.KEYCODE_MEDIA_PAUSE));
-        assertEquals(PlaybackControlSupportGlue.PLAYBACK_SPEED_PAUSED, glue.getCurrentSpeedId());
-    }
-
-    @Test
-    public void testMediaPauseButtonOnPause() {
-        PlaybackControlsRow row = new PlaybackControlsRow();
-        glue.setControlsRow(row);
-        SparseArrayObjectAdapter adapter = (SparseArrayObjectAdapter)
-                row.getPrimaryActionsAdapter();
-        PlaybackControlsRow.MultiAction playPause = (PlaybackControlsRow.MultiAction) adapter
-                .lookup(PlaybackControlSupportGlue.ACTION_PLAY_PAUSE);
-
-        glue.onActionClicked(playPause);
-        glue.onActionClicked(playPause);
-        assertEquals(PlaybackControlSupportGlue.PLAYBACK_SPEED_PAUSED, glue.getCurrentSpeedId());
-        glue.onKey(null, KeyEvent.KEYCODE_MEDIA_PAUSE, new KeyEvent(KeyEvent.ACTION_DOWN,
-                KeyEvent.KEYCODE_MEDIA_PAUSE));
-        assertEquals(PlaybackControlSupportGlue.PLAYBACK_SPEED_PAUSED, glue.getCurrentSpeedId());
-    }
-
-    @Test
-    public void testMediaPlayButtonOnFF() {
-        PlaybackControlsRow row = new PlaybackControlsRow();
-        glue.setControlsRow(row);
-        SparseArrayObjectAdapter adapter = (SparseArrayObjectAdapter)
-                row.getPrimaryActionsAdapter();
-        PlaybackControlsRow.MultiAction playPause = (PlaybackControlsRow.MultiAction) adapter
-                .lookup(PlaybackControlSupportGlue.ACTION_PLAY_PAUSE);
-        PlaybackControlsRow.MultiAction fastForward = (PlaybackControlsRow.MultiAction) adapter
-                .lookup(PlaybackControlSupportGlue.ACTION_FAST_FORWARD);
-
-        glue.onActionClicked(playPause);
-        glue.onActionClicked(fastForward);
-        assertEquals(PlaybackControlSupportGlue.PLAYBACK_SPEED_FAST_L0, glue.getCurrentSpeedId());
-        glue.onKey(null, KeyEvent.KEYCODE_MEDIA_PLAY, new KeyEvent(KeyEvent.ACTION_DOWN,
-                KeyEvent.KEYCODE_MEDIA_PLAY));
-        assertEquals(PlaybackControlSupportGlue.PLAYBACK_SPEED_NORMAL, glue.getCurrentSpeedId());
-    }
-
-    @Test
-    public void testMediaPlayButtonOnPlay() {
-        PlaybackControlsRow row = new PlaybackControlsRow();
-        glue.setControlsRow(row);
-        SparseArrayObjectAdapter adapter = (SparseArrayObjectAdapter)
-                row.getPrimaryActionsAdapter();
-        PlaybackControlsRow.MultiAction playPause = (PlaybackControlsRow.MultiAction) adapter
-                .lookup(PlaybackControlSupportGlue.ACTION_PLAY_PAUSE);
-
-        glue.onActionClicked(playPause);
-        assertEquals(PlaybackControlSupportGlue.PLAYBACK_SPEED_NORMAL, glue.getCurrentSpeedId());
-        glue.onKey(null, KeyEvent.KEYCODE_MEDIA_PLAY, new KeyEvent(KeyEvent.ACTION_DOWN,
-                KeyEvent.KEYCODE_MEDIA_PLAY));
-        assertEquals(PlaybackControlSupportGlue.PLAYBACK_SPEED_NORMAL, glue.getCurrentSpeedId());
-    }
-
-    @Test
-    public void testMediaPlayButtonOnPause() {
-        PlaybackControlsRow row = new PlaybackControlsRow();
-        glue.setControlsRow(row);
-        SparseArrayObjectAdapter adapter = (SparseArrayObjectAdapter)
-                row.getPrimaryActionsAdapter();
-        PlaybackControlsRow.MultiAction playPause = (PlaybackControlsRow.MultiAction) adapter
-                .lookup(PlaybackControlSupportGlue.ACTION_PLAY_PAUSE);
-
-        glue.onActionClicked(playPause);
-        glue.onActionClicked(playPause);
-        assertEquals(PlaybackControlSupportGlue.PLAYBACK_SPEED_PAUSED, glue.getCurrentSpeedId());
-        glue.onKey(null, KeyEvent.KEYCODE_MEDIA_PLAY, new KeyEvent(KeyEvent.ACTION_DOWN,
-                KeyEvent.KEYCODE_MEDIA_PLAY));
-        assertEquals(PlaybackControlSupportGlue.PLAYBACK_SPEED_NORMAL, glue.getCurrentSpeedId());
-    }
-
-    @Test
-    public void testMediaPlayPauseButtonOnFF() {
-        PlaybackControlsRow row = new PlaybackControlsRow();
-        glue.setControlsRow(row);
-        SparseArrayObjectAdapter adapter = (SparseArrayObjectAdapter)
-                row.getPrimaryActionsAdapter();
-        PlaybackControlsRow.MultiAction playPause = (PlaybackControlsRow.MultiAction) adapter
-                .lookup(PlaybackControlSupportGlue.ACTION_PLAY_PAUSE);
-        PlaybackControlsRow.MultiAction fastForward = (PlaybackControlsRow.MultiAction) adapter
-                .lookup(PlaybackControlSupportGlue.ACTION_FAST_FORWARD);
-
-        glue.onActionClicked(playPause);
-        glue.onActionClicked(fastForward);
-        assertEquals(PlaybackControlSupportGlue.PLAYBACK_SPEED_FAST_L0, glue.getCurrentSpeedId());
-        glue.onKey(null, KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE, new KeyEvent(KeyEvent.ACTION_DOWN,
-                KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE));
-        assertEquals(PlaybackControlSupportGlue.PLAYBACK_SPEED_NORMAL, glue.getCurrentSpeedId());
-    }
-
-    @Test
-    public void testMediaPlayPauseButtonOnPlay() {
-        PlaybackControlsRow row = new PlaybackControlsRow();
-        glue.setControlsRow(row);
-        SparseArrayObjectAdapter adapter = (SparseArrayObjectAdapter)
-                row.getPrimaryActionsAdapter();
-        PlaybackControlsRow.MultiAction playPause = (PlaybackControlsRow.MultiAction) adapter
-                .lookup(PlaybackControlSupportGlue.ACTION_PLAY_PAUSE);
-
-        glue.onActionClicked(playPause);
-        assertEquals(PlaybackControlSupportGlue.PLAYBACK_SPEED_NORMAL, glue.getCurrentSpeedId());
-        glue.onKey(null, KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE, new KeyEvent(KeyEvent.ACTION_DOWN,
-                KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE));
-        assertEquals(PlaybackControlSupportGlue.PLAYBACK_SPEED_PAUSED, glue.getCurrentSpeedId());
-    }
-
-    @Test
-    public void testMediaPlayPauseButtonOnPause() {
-        PlaybackControlsRow row = new PlaybackControlsRow();
-        glue.setControlsRow(row);
-        SparseArrayObjectAdapter adapter = (SparseArrayObjectAdapter)
-                row.getPrimaryActionsAdapter();
-        PlaybackControlsRow.MultiAction playPause = (PlaybackControlsRow.MultiAction) adapter
-                .lookup(PlaybackControlSupportGlue.ACTION_PLAY_PAUSE);
-
-        glue.onActionClicked(playPause);
-        glue.onActionClicked(playPause);
-        assertEquals(PlaybackControlSupportGlue.PLAYBACK_SPEED_PAUSED, glue.getCurrentSpeedId());
-        glue.onKey(null, KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE, new KeyEvent(KeyEvent.ACTION_DOWN,
-                KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE));
-        assertEquals(PlaybackControlSupportGlue.PLAYBACK_SPEED_NORMAL, glue.getCurrentSpeedId());
-    }
-
-    @Test
-    public void testOnItemClickedListener() {
-        PlaybackControlsRow row = new PlaybackControlsRow();
-        final PlaybackOverlaySupportFragment[] fragmentResult = new PlaybackOverlaySupportFragment[1];
-        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
-            @Override
-            public void run() {
-                fragmentResult[0] = new PlaybackOverlaySupportFragment();
-            }
-        });
-        PlaybackOverlaySupportFragment fragment = fragmentResult[0];
-        glue.setHost(new PlaybackControlSupportGlue.PlaybackSupportGlueHostOld(fragment));
-        glue.setControlsRow(row);
-        SparseArrayObjectAdapter adapter = (SparseArrayObjectAdapter)
-                row.getPrimaryActionsAdapter();
-        PlaybackControlsRow.MultiAction playPause = (PlaybackControlsRow.MultiAction) adapter
-                .lookup(PlaybackControlSupportGlue.ACTION_PLAY_PAUSE);
-        OnItemViewClickedListener listener = Mockito.mock(OnItemViewClickedListener.class);
-        glue.setOnItemViewClickedListener(listener);
-
-        // create fake row ViewHolder and fade item ViewHolder
-        View rowView = new View(context);
-        View view = new View(context);
-        PlaybackRowPresenter.ViewHolder rowVh = new PlaybackRowPresenter.ViewHolder(rowView);
-        Presenter.ViewHolder vh = new Presenter.ViewHolder(view);
-
-        // Initially media is paused
-        assertEquals(PlaybackControlSupportGlue.PLAYBACK_SPEED_PAUSED, glue.getCurrentSpeedId());
-
-        // simulate a click inside PlaybackOverlaySupportFragment's PlaybackRow.
-        fragment.getOnItemViewClickedListener().onItemClicked(vh, playPause, rowVh, row);
-        verify(listener, times(0)).onItemClicked(vh, playPause, rowVh, row);
-        assertEquals(PlaybackControlSupportGlue.PLAYBACK_SPEED_NORMAL, glue.getCurrentSpeedId());
-
-        // simulate a click on object other than PlaybackRow.
-        Object regularItem = new Object();
-        Row regularRow = new Row();
-        RowPresenter.ViewHolder regularRowViewHolder = new RowPresenter.ViewHolder(rowView);
-        Presenter.ViewHolder regularViewHOlder = new Presenter.ViewHolder(view);
-        fragment.getOnItemViewClickedListener().onItemClicked(regularViewHOlder, regularItem,
-                regularRowViewHolder, regularRow);
-        verify(listener, times(1)).onItemClicked(regularViewHOlder, regularItem,
-                regularRowViewHolder, regularRow);
-        assertEquals(PlaybackControlSupportGlue.PLAYBACK_SPEED_NORMAL, glue.getCurrentSpeedId());
-    }
-
-    @Test
-    public void testOnRowChangedCallback() throws Exception {
-        final PlaybackOverlaySupportFragment[] fragmentResult = new
-                PlaybackOverlaySupportFragment[1];
-        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
-            @Override
-            public void run() {
-                fragmentResult[0] = new PlaybackOverlaySupportFragment();
-            }
-        });
-        PlaybackOverlaySupportFragment fragment = fragmentResult[0];
-        PlayControlGlueImpl playbackGlue = new PlayControlGlueImpl(context, fragment,
-                new int[]{
-                        PlaybackControlSupportGlue.PLAYBACK_SPEED_FAST_L0,
-                        PlaybackControlSupportGlue.PLAYBACK_SPEED_FAST_L1,
-                        PlaybackControlSupportGlue.PLAYBACK_SPEED_FAST_L2
-                });
-
-        // before any controls row is created the count is zero
-        assertEquals(playbackGlue.getOnRowChangedCallCount(), 0);
-        playbackGlue.createControlsRowAndPresenter();
-        // after a controls row is created, onRowChanged() call back is called once
-        assertEquals(playbackGlue.getOnRowChangedCallCount(), 1);
-        assertEquals(3, playbackGlue.getControlsRow().getPrimaryActionsAdapter().size());
-        playbackGlue.notifyMetaDataChanged();
-        // onMetaDataChanged() calls updateRowMetadata which ends up calling
-        // notifyPlaybackRowChanged on the old host and finally onRowChanged on the glue.
-        assertEquals(playbackGlue.getOnRowChangedCallCount(), 2);
-        assertEquals(3, playbackGlue.getControlsRow().getPrimaryActionsAdapter().size());
-    }
-
-
-    @Test
-    public void testWithoutValidMedia() throws Exception {
-        final PlaybackOverlaySupportFragment[] fragmentResult = new
-                PlaybackOverlaySupportFragment[1];
-        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
-            @Override
-            public void run() {
-                fragmentResult[0] = new PlaybackOverlaySupportFragment();
-            }
-        });
-        final boolean[] hasValidMedia = new boolean[] {false};
-        PlaybackOverlaySupportFragment fragment = fragmentResult[0];
-        PlayControlGlueImpl playbackGlue = new PlayControlGlueImpl(context, fragment,
-                new int[]{
-                        PlaybackControlSupportGlue.PLAYBACK_SPEED_FAST_L0,
-                        PlaybackControlSupportGlue.PLAYBACK_SPEED_FAST_L1,
-                        PlaybackControlSupportGlue.PLAYBACK_SPEED_FAST_L2
-                }) {
-            @Override
-            public boolean hasValidMedia() {
-                return hasValidMedia[0];
-            }
-        };
-
-        // before any controls row is created the count is zero
-        assertEquals(playbackGlue.getOnRowChangedCallCount(), 0);
-        playbackGlue.createControlsRowAndPresenter();
-        // after a controls row is created, onRowChanged() call back is called once
-        assertEquals(playbackGlue.getOnRowChangedCallCount(), 1);
-        // enven hasValidMedia() is false, we should still have three buttons.
-        assertEquals(3, playbackGlue.getControlsRow().getPrimaryActionsAdapter().size());
-
-        hasValidMedia[0] = true;
-        playbackGlue.notifyMetaDataChanged();
-        // onMetaDataChanged() calls updateRowMetadata which ends up calling
-        // notifyPlaybackRowChanged on the old host and finally onRowChanged on the glue.
-        assertEquals(playbackGlue.getOnRowChangedCallCount(), 2);
-        assertEquals(3, playbackGlue.getControlsRow().getPrimaryActionsAdapter().size());
-    }
-
-}
diff --git a/v17/leanback/tests/java/android/support/v17/leanback/app/PlaybackOverlayFragmentTest.java b/v17/leanback/tests/java/android/support/v17/leanback/app/PlaybackOverlayFragmentTest.java
deleted file mode 100644
index f21bd04..0000000
--- a/v17/leanback/tests/java/android/support/v17/leanback/app/PlaybackOverlayFragmentTest.java
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.support.v17.leanback.app;
-
-import static junit.framework.Assert.assertEquals;
-
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
-import android.support.test.filters.FlakyTest;
-import android.support.test.filters.MediumTest;
-import android.support.test.filters.Suppress;
-import android.support.test.runner.AndroidJUnit4;
-import android.support.v17.leanback.test.R;
-import android.view.View;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-@MediumTest
-@RunWith(AndroidJUnit4.class)
-public class PlaybackOverlayFragmentTest extends SingleFragmentTestBase {
-
-    @Test
-    public void workaroundVideoViewStealFocus() {
-        SingleFragmentTestActivity activity =
-                launchAndWaitActivity(PlaybackOverlayTestFragment.class,
-                new Options().activityLayoutId(R.layout.playback_controls_with_video), 0);
-        PlaybackOverlayTestFragment fragment = (PlaybackOverlayTestFragment)
-                activity.getTestFragment();
-
-        assertFalse(activity.findViewById(R.id.videoView).hasFocus());
-        assertTrue(fragment.getView().hasFocus());
-    }
-
-    @FlakyTest
-    @Suppress
-    @Test
-    public void alignmentRowToBottom() throws Throwable {
-        SingleFragmentTestActivity activity =
-                launchAndWaitActivity(PlaybackOverlayTestFragment.class,
-                new Options().activityLayoutId(R.layout.playback_controls_with_video), 0);
-        final PlaybackOverlayTestFragment fragment = (PlaybackOverlayTestFragment)
-                activity.getTestFragment();
-
-        assertTrue(fragment.getAdapter().size() > 2);
-
-        View playRow = fragment.getVerticalGridView().getChildAt(0);
-        assertTrue(playRow.hasFocus());
-        assertEquals(playRow.getResources().getDimensionPixelSize(
-                R.dimen.lb_playback_controls_padding_bottom),
-                fragment.getVerticalGridView().getHeight() - playRow.getBottom());
-
-        activityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                fragment.getVerticalGridView().setSelectedPositionSmooth(
-                        fragment.getAdapter().size() - 1);
-            }
-        });
-        waitForScrollIdle(fragment.getVerticalGridView());
-
-        View lastRow = fragment.getVerticalGridView().getChildAt(
-                fragment.getVerticalGridView().getChildCount() - 1);
-        assertEquals(fragment.getAdapter().size() - 1,
-                fragment.getVerticalGridView().getChildAdapterPosition(lastRow));
-        assertTrue(lastRow.hasFocus());
-        assertEquals(lastRow.getResources().getDimensionPixelSize(
-                R.dimen.lb_playback_controls_padding_bottom),
-                fragment.getVerticalGridView().getHeight() - lastRow.getBottom());
-    }
-
-}
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
deleted file mode 100644
index 82e37d3..0000000
--- a/v17/leanback/tests/java/android/support/v17/leanback/app/PlaybackOverlayTestFragment.java
+++ /dev/null
@@ -1,416 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.support.v17.leanback.app;
-
-import android.content.Context;
-import android.graphics.drawable.Drawable;
-import android.os.Bundle;
-import android.os.Handler;
-import android.support.v17.leanback.test.R;
-import android.support.v17.leanback.widget.Action;
-import android.support.v17.leanback.widget.ArrayObjectAdapter;
-import android.support.v17.leanback.widget.ClassPresenterSelector;
-import android.support.v17.leanback.widget.ControlButtonPresenterSelector;
-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.OnItemViewClickedListener;
-import android.support.v17.leanback.widget.OnItemViewSelectedListener;
-import android.support.v17.leanback.widget.PlaybackControlsRow;
-import android.support.v17.leanback.widget.PlaybackControlsRowPresenter;
-import android.support.v17.leanback.widget.Presenter;
-import android.support.v17.leanback.widget.PresenterSelector;
-import android.support.v17.leanback.widget.Row;
-import android.support.v17.leanback.widget.RowPresenter;
-import android.support.v17.leanback.widget.SparseArrayObjectAdapter;
-import android.util.Log;
-import android.view.KeyEvent;
-import android.view.View;
-import android.widget.Toast;
-
-public class PlaybackOverlayTestFragment extends PlaybackOverlayFragment {
-    private static final String TAG = "leanback.PlaybackControlsFragment";
-
-    /**
-     * Change this to choose a different overlay background.
-     */
-    private static final int BACKGROUND_TYPE = PlaybackOverlayFragment.BG_LIGHT;
-
-    /**
-     * Change the number of related content rows.
-     */
-    private static final int RELATED_CONTENT_ROWS = 3;
-
-    /**
-     * Change this to select hidden
-     */
-    private static final boolean SECONDARY_HIDDEN = false;
-
-    private static final int ROW_CONTROLS = 0;
-
-    private PlaybackControlHelper mGlue;
-    private PlaybackControlsRowPresenter mPlaybackControlsRowPresenter;
-
-    private OnItemViewClickedListener mOnItemViewClickedListener = new OnItemViewClickedListener() {
-        @Override
-        public void onItemClicked(Presenter.ViewHolder itemViewHolder, Object item,
-                                  RowPresenter.ViewHolder rowViewHolder, Row row) {
-            Log.i(TAG, "onItemClicked: " + item + " row " + row);
-            if (item instanceof Action) {
-                mGlue.onActionClicked((Action) item);
-            }
-        }
-    };
-
-    private OnItemViewSelectedListener mOnItemViewSelectedListener =
-            new OnItemViewSelectedListener() {
-        @Override
-        public void onItemSelected(Presenter.ViewHolder itemViewHolder, Object item,
-                                   RowPresenter.ViewHolder rowViewHolder, Row row) {
-            Log.i(TAG, "onItemSelected: " + item + " row " + row);
-        }
-    };
-
-    @Override
-    public SparseArrayObjectAdapter getAdapter() {
-        return (SparseArrayObjectAdapter) super.getAdapter();
-    }
-
-    @Override
-    public void onCreate(Bundle savedInstanceState) {
-        Log.i(TAG, "onCreate");
-        super.onCreate(savedInstanceState);
-
-        setBackgroundType(BACKGROUND_TYPE);
-        setOnItemViewSelectedListener(mOnItemViewSelectedListener);
-
-        createComponents(getActivity());
-    }
-
-    private void createComponents(Context context) {
-        mGlue = new PlaybackControlHelper(context, this) {
-            @Override
-            public int getUpdatePeriod() {
-                long totalTime = getControlsRow().getDuration();
-                if (getView() == null || getView().getWidth() == 0 || totalTime <= 0) {
-                    return 1000;
-                }
-                return 16;
-            }
-
-            @Override
-            protected void onRowChanged(PlaybackControlsRow row) {
-                if (getAdapter() == null) {
-                    return;
-                }
-                int index = getAdapter().indexOf(row);
-                if (index >= 0) {
-                    getAdapter().notifyArrayItemRangeChanged(index, 1);
-                }
-            }
-
-            @Override
-            public void onActionClicked(Action action) {
-                if (action.getId() == R.id.lb_control_picture_in_picture) {
-                    getActivity().enterPictureInPictureMode();
-                    return;
-                }
-                super.onActionClicked(action);
-            }
-        };
-
-        mGlue.setOnItemViewClickedListener(mOnItemViewClickedListener);
-
-        mPlaybackControlsRowPresenter = mGlue.createControlsRowAndPresenter();
-        mPlaybackControlsRowPresenter.setSecondaryActionsHidden(SECONDARY_HIDDEN);
-        ClassPresenterSelector selector = new ClassPresenterSelector();
-        selector.addClassPresenter(ListRow.class, new ListRowPresenter());
-        selector.addClassPresenter(PlaybackControlsRow.class, mPlaybackControlsRowPresenter);
-
-        setAdapter(new SparseArrayObjectAdapter(selector));
-
-        // Add the controls row
-        getAdapter().set(ROW_CONTROLS, mGlue.getControlsRow());
-
-        // Add related content rows
-        for (int i = 0; i < RELATED_CONTENT_ROWS; ++i) {
-            ArrayObjectAdapter listRowAdapter = new ArrayObjectAdapter(new StringPresenter());
-            listRowAdapter.add("Some related content");
-            listRowAdapter.add("Other related content");
-            HeaderItem header = new HeaderItem(i, "Row " + i);
-            getAdapter().set(ROW_CONTROLS + 1 + i, new ListRow(header, listRowAdapter));
-        }
-
-    }
-
-    @Override
-    public void onStart() {
-        super.onStart();
-        mGlue.setFadingEnabled(true);
-    }
-
-    abstract static class PlaybackControlHelper extends PlaybackControlGlue {
-        /**
-         * Change the location of the thumbs up/down controls
-         */
-        private static final boolean THUMBS_PRIMARY = true;
-
-        private static final String FAUX_TITLE = "A short song of silence";
-        private static final String FAUX_SUBTITLE = "2014";
-        private static final int FAUX_DURATION = 33 * 1000;
-
-        // These should match the playback service FF behavior
-        private static int[] sFastForwardSpeeds = { 2, 3, 4, 5 };
-
-        private boolean mIsPlaying;
-        private int mSpeed = PlaybackControlGlue.PLAYBACK_SPEED_PAUSED;
-        private long mStartTime;
-        private long mStartPosition = 0;
-
-        private PlaybackControlsRow.RepeatAction mRepeatAction;
-        private PlaybackControlsRow.ThumbsUpAction mThumbsUpAction;
-        private PlaybackControlsRow.ThumbsDownAction mThumbsDownAction;
-        private PlaybackControlsRow.PictureInPictureAction mPipAction;
-        private static Handler mHandler = new Handler();
-
-        private final Runnable mUpdateProgressRunnable = new Runnable() {
-            @Override
-            public void run() {
-                updateProgress();
-                mHandler.postDelayed(this, getUpdatePeriod());
-            }
-        };
-
-        PlaybackControlHelper(Context context, PlaybackOverlayFragment fragment) {
-            super(context, fragment, sFastForwardSpeeds);
-            mThumbsUpAction = new PlaybackControlsRow.ThumbsUpAction(context);
-            mThumbsUpAction.setIndex(PlaybackControlsRow.ThumbsUpAction.INDEX_OUTLINE);
-            mThumbsDownAction = new PlaybackControlsRow.ThumbsDownAction(context);
-            mThumbsDownAction.setIndex(PlaybackControlsRow.ThumbsDownAction.INDEX_OUTLINE);
-            mRepeatAction = new PlaybackControlsRow.RepeatAction(context);
-            mPipAction = new PlaybackControlsRow.PictureInPictureAction(context);
-        }
-
-        @Override
-        public PlaybackControlsRowPresenter createControlsRowAndPresenter() {
-            PlaybackControlsRowPresenter presenter = super.createControlsRowAndPresenter();
-
-            ArrayObjectAdapter adapter = new ArrayObjectAdapter(
-                    new ControlButtonPresenterSelector());
-            getControlsRow().setSecondaryActionsAdapter(adapter);
-            if (!THUMBS_PRIMARY) {
-                adapter.add(mThumbsDownAction);
-            }
-            if (android.os.Build.VERSION.SDK_INT > 23) {
-                adapter.add(mPipAction);
-            }
-            adapter.add(mRepeatAction);
-            if (!THUMBS_PRIMARY) {
-                adapter.add(mThumbsUpAction);
-            }
-
-            return presenter;
-        }
-
-        @Override
-        protected SparseArrayObjectAdapter createPrimaryActionsAdapter(
-                PresenterSelector presenterSelector) {
-            SparseArrayObjectAdapter adapter = new SparseArrayObjectAdapter(presenterSelector);
-            if (THUMBS_PRIMARY) {
-                adapter.set(PlaybackControlGlue.ACTION_CUSTOM_LEFT_FIRST, mThumbsUpAction);
-                adapter.set(PlaybackControlGlue.ACTION_CUSTOM_RIGHT_FIRST, mThumbsDownAction);
-            }
-            return adapter;
-        }
-
-        @Override
-        public void onActionClicked(Action action) {
-            if (shouldDispatchAction(action)) {
-                dispatchAction(action);
-                return;
-            }
-            super.onActionClicked(action);
-        }
-
-        @Override
-        public boolean onKey(View view, int keyCode, KeyEvent keyEvent) {
-            if (keyEvent.getAction() == KeyEvent.ACTION_DOWN) {
-                Action action = getControlsRow().getActionForKeyCode(keyEvent.getKeyCode());
-                if (shouldDispatchAction(action)) {
-                    dispatchAction(action);
-                    return true;
-                }
-            }
-            return super.onKey(view, keyCode, keyEvent);
-        }
-
-        private boolean shouldDispatchAction(Action action) {
-            return action == mRepeatAction || action == mThumbsUpAction
-                    || action == mThumbsDownAction;
-        }
-
-        private void dispatchAction(Action action) {
-            Toast.makeText(getContext(), action.toString(), Toast.LENGTH_SHORT).show();
-            PlaybackControlsRow.MultiAction multiAction = (PlaybackControlsRow.MultiAction) action;
-            multiAction.nextIndex();
-            notifyActionChanged(multiAction);
-        }
-
-        private void notifyActionChanged(PlaybackControlsRow.MultiAction action) {
-            int index;
-            index = getPrimaryActionsAdapter().indexOf(action);
-            if (index >= 0) {
-                getPrimaryActionsAdapter().notifyArrayItemRangeChanged(index, 1);
-            } else {
-                index = getSecondaryActionsAdapter().indexOf(action);
-                if (index >= 0) {
-                    getSecondaryActionsAdapter().notifyArrayItemRangeChanged(index, 1);
-                }
-            }
-        }
-
-        private SparseArrayObjectAdapter getPrimaryActionsAdapter() {
-            return (SparseArrayObjectAdapter) getControlsRow().getPrimaryActionsAdapter();
-        }
-
-        private ArrayObjectAdapter getSecondaryActionsAdapter() {
-            return (ArrayObjectAdapter) getControlsRow().getSecondaryActionsAdapter();
-        }
-
-        @Override
-        public boolean hasValidMedia() {
-            return true;
-        }
-
-        @Override
-        public boolean isMediaPlaying() {
-            return mIsPlaying;
-        }
-
-        @Override
-        public CharSequence getMediaTitle() {
-            return FAUX_TITLE;
-        }
-
-        @Override
-        public CharSequence getMediaSubtitle() {
-            return FAUX_SUBTITLE;
-        }
-
-        @Override
-        public int getMediaDuration() {
-            return FAUX_DURATION;
-        }
-
-        @Override
-        public Drawable getMediaArt() {
-            return null;
-        }
-
-        @Override
-        public long getSupportedActions() {
-            return PlaybackControlGlue.ACTION_PLAY_PAUSE
-                   | PlaybackControlGlue.ACTION_FAST_FORWARD
-                   | PlaybackControlGlue.ACTION_REWIND;
-        }
-
-        @Override
-        public int getCurrentSpeedId() {
-            return mSpeed;
-        }
-
-        @Override
-        public int getCurrentPosition() {
-            int speed;
-            if (mSpeed == PlaybackControlGlue.PLAYBACK_SPEED_PAUSED) {
-                speed = 0;
-            } else if (mSpeed == PlaybackControlGlue.PLAYBACK_SPEED_NORMAL) {
-                speed = 1;
-            } else if (mSpeed >= PlaybackControlGlue.PLAYBACK_SPEED_FAST_L0) {
-                int index = mSpeed - PlaybackControlGlue.PLAYBACK_SPEED_FAST_L0;
-                speed = getFastForwardSpeeds()[index];
-            } else if (mSpeed <= -PlaybackControlGlue.PLAYBACK_SPEED_FAST_L0) {
-                int index = -mSpeed - PlaybackControlGlue.PLAYBACK_SPEED_FAST_L0;
-                speed = -getRewindSpeeds()[index];
-            } else {
-                return -1;
-            }
-            long position = mStartPosition + (System.currentTimeMillis() - mStartTime) * speed;
-            if (position > getMediaDuration()) {
-                position = getMediaDuration();
-                onPlaybackComplete(true);
-            } else if (position < 0) {
-                position = 0;
-                onPlaybackComplete(false);
-            }
-            return (int) position;
-        }
-
-        void onPlaybackComplete(final boolean ended) {
-            mHandler.post(new Runnable() {
-                @Override
-                public void run() {
-                    if (mRepeatAction.getIndex() == PlaybackControlsRow.RepeatAction.INDEX_NONE) {
-                        pausePlayback();
-                    } else {
-                        startPlayback(PlaybackControlGlue.PLAYBACK_SPEED_NORMAL);
-                    }
-                    mStartPosition = 0;
-                    onStateChanged();
-                }
-            });
-        }
-
-        @Override
-        protected void startPlayback(int speed) {
-            if (speed == mSpeed) {
-                return;
-            }
-            mStartPosition = getCurrentPosition();
-            mSpeed = speed;
-            mIsPlaying = true;
-            mStartTime = System.currentTimeMillis();
-        }
-
-        @Override
-        protected void pausePlayback() {
-            if (mSpeed == PlaybackControlGlue.PLAYBACK_SPEED_PAUSED) {
-                return;
-            }
-            mStartPosition = getCurrentPosition();
-            mSpeed = PlaybackControlGlue.PLAYBACK_SPEED_PAUSED;
-            mIsPlaying = false;
-        }
-
-        @Override
-        protected void skipToNext() {
-            // Not supported
-        }
-
-        @Override
-        protected void skipToPrevious() {
-            // Not supported
-        }
-
-        @Override
-        public void enableProgressUpdating(boolean enable) {
-            mHandler.removeCallbacks(mUpdateProgressRunnable);
-            if (enable) {
-                mUpdateProgressRunnable.run();
-            }
-        }
-    }
-}
diff --git a/v7/appcompat/Android.mk b/v7/appcompat/Android.mk
index 93baa95..500a2a2 100644
--- a/v7/appcompat/Android.mk
+++ b/v7/appcompat/Android.mk
@@ -26,7 +26,7 @@
 LOCAL_USE_AAPT2 := true
 LOCAL_MODULE := android-support-v7-appcompat
 LOCAL_SDK_VERSION := $(SUPPORT_CURRENT_SDK_VERSION)
-LOCAL_SRC_FILES := $(call all-java-files-under,src)
+LOCAL_SRC_FILES := $(call all-java-files-under,src/main/java)
 LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
 LOCAL_STATIC_JAVA_LIBRARIES := \
     android-support-vectordrawable \
diff --git a/v7/appcompat/build.gradle b/v7/appcompat/build.gradle
index a0e5290..2d57ac4 100644
--- a/v7/appcompat/build.gradle
+++ b/v7/appcompat/build.gradle
@@ -22,10 +22,7 @@
     }
 
     sourceSets {
-        main.java.srcDir 'src'
         main.res.srcDirs 'res', 'res-public'
-        main.assets.srcDir 'assets'
-        main.resources.srcDir 'src'
     }
 
     aaptOptions {
diff --git a/v7/appcompat/src/android/support/v7/app/ActionBar.java b/v7/appcompat/src/main/java/android/support/v7/app/ActionBar.java
similarity index 100%
rename from v7/appcompat/src/android/support/v7/app/ActionBar.java
rename to v7/appcompat/src/main/java/android/support/v7/app/ActionBar.java
diff --git a/v7/appcompat/src/android/support/v7/app/ActionBarDrawerToggle.java b/v7/appcompat/src/main/java/android/support/v7/app/ActionBarDrawerToggle.java
similarity index 100%
rename from v7/appcompat/src/android/support/v7/app/ActionBarDrawerToggle.java
rename to v7/appcompat/src/main/java/android/support/v7/app/ActionBarDrawerToggle.java
diff --git a/v7/appcompat/src/android/support/v7/app/ActionBarDrawerToggleHoneycomb.java b/v7/appcompat/src/main/java/android/support/v7/app/ActionBarDrawerToggleHoneycomb.java
similarity index 100%
rename from v7/appcompat/src/android/support/v7/app/ActionBarDrawerToggleHoneycomb.java
rename to v7/appcompat/src/main/java/android/support/v7/app/ActionBarDrawerToggleHoneycomb.java
diff --git a/v7/appcompat/src/android/support/v7/app/AlertController.java b/v7/appcompat/src/main/java/android/support/v7/app/AlertController.java
similarity index 100%
rename from v7/appcompat/src/android/support/v7/app/AlertController.java
rename to v7/appcompat/src/main/java/android/support/v7/app/AlertController.java
diff --git a/v7/appcompat/src/android/support/v7/app/AlertDialog.java b/v7/appcompat/src/main/java/android/support/v7/app/AlertDialog.java
similarity index 100%
rename from v7/appcompat/src/android/support/v7/app/AlertDialog.java
rename to v7/appcompat/src/main/java/android/support/v7/app/AlertDialog.java
diff --git a/v7/appcompat/src/android/support/v7/app/AppCompatActivity.java b/v7/appcompat/src/main/java/android/support/v7/app/AppCompatActivity.java
similarity index 100%
rename from v7/appcompat/src/android/support/v7/app/AppCompatActivity.java
rename to v7/appcompat/src/main/java/android/support/v7/app/AppCompatActivity.java
diff --git a/v7/appcompat/src/android/support/v7/app/AppCompatCallback.java b/v7/appcompat/src/main/java/android/support/v7/app/AppCompatCallback.java
similarity index 100%
rename from v7/appcompat/src/android/support/v7/app/AppCompatCallback.java
rename to v7/appcompat/src/main/java/android/support/v7/app/AppCompatCallback.java
diff --git a/v7/appcompat/src/android/support/v7/app/AppCompatDelegate.java b/v7/appcompat/src/main/java/android/support/v7/app/AppCompatDelegate.java
similarity index 100%
rename from v7/appcompat/src/android/support/v7/app/AppCompatDelegate.java
rename to v7/appcompat/src/main/java/android/support/v7/app/AppCompatDelegate.java
diff --git a/v7/appcompat/src/android/support/v7/app/AppCompatDelegateImplBase.java b/v7/appcompat/src/main/java/android/support/v7/app/AppCompatDelegateImplBase.java
similarity index 100%
rename from v7/appcompat/src/android/support/v7/app/AppCompatDelegateImplBase.java
rename to v7/appcompat/src/main/java/android/support/v7/app/AppCompatDelegateImplBase.java
diff --git a/v7/appcompat/src/android/support/v7/app/AppCompatDelegateImplN.java b/v7/appcompat/src/main/java/android/support/v7/app/AppCompatDelegateImplN.java
similarity index 100%
rename from v7/appcompat/src/android/support/v7/app/AppCompatDelegateImplN.java
rename to v7/appcompat/src/main/java/android/support/v7/app/AppCompatDelegateImplN.java
diff --git a/v7/appcompat/src/android/support/v7/app/AppCompatDelegateImplV11.java b/v7/appcompat/src/main/java/android/support/v7/app/AppCompatDelegateImplV11.java
similarity index 100%
rename from v7/appcompat/src/android/support/v7/app/AppCompatDelegateImplV11.java
rename to v7/appcompat/src/main/java/android/support/v7/app/AppCompatDelegateImplV11.java
diff --git a/v7/appcompat/src/android/support/v7/app/AppCompatDelegateImplV14.java b/v7/appcompat/src/main/java/android/support/v7/app/AppCompatDelegateImplV14.java
similarity index 100%
rename from v7/appcompat/src/android/support/v7/app/AppCompatDelegateImplV14.java
rename to v7/appcompat/src/main/java/android/support/v7/app/AppCompatDelegateImplV14.java
diff --git a/v7/appcompat/src/android/support/v7/app/AppCompatDelegateImplV23.java b/v7/appcompat/src/main/java/android/support/v7/app/AppCompatDelegateImplV23.java
similarity index 100%
rename from v7/appcompat/src/android/support/v7/app/AppCompatDelegateImplV23.java
rename to v7/appcompat/src/main/java/android/support/v7/app/AppCompatDelegateImplV23.java
diff --git a/v7/appcompat/src/android/support/v7/app/AppCompatDelegateImplV9.java b/v7/appcompat/src/main/java/android/support/v7/app/AppCompatDelegateImplV9.java
similarity index 100%
rename from v7/appcompat/src/android/support/v7/app/AppCompatDelegateImplV9.java
rename to v7/appcompat/src/main/java/android/support/v7/app/AppCompatDelegateImplV9.java
diff --git a/v7/appcompat/src/android/support/v7/app/AppCompatDialog.java b/v7/appcompat/src/main/java/android/support/v7/app/AppCompatDialog.java
similarity index 100%
rename from v7/appcompat/src/android/support/v7/app/AppCompatDialog.java
rename to v7/appcompat/src/main/java/android/support/v7/app/AppCompatDialog.java
diff --git a/v7/appcompat/src/android/support/v7/app/AppCompatDialogFragment.java b/v7/appcompat/src/main/java/android/support/v7/app/AppCompatDialogFragment.java
similarity index 100%
rename from v7/appcompat/src/android/support/v7/app/AppCompatDialogFragment.java
rename to v7/appcompat/src/main/java/android/support/v7/app/AppCompatDialogFragment.java
diff --git a/v7/appcompat/src/android/support/v7/app/AppCompatViewInflater.java b/v7/appcompat/src/main/java/android/support/v7/app/AppCompatViewInflater.java
similarity index 100%
rename from v7/appcompat/src/android/support/v7/app/AppCompatViewInflater.java
rename to v7/appcompat/src/main/java/android/support/v7/app/AppCompatViewInflater.java
diff --git a/v7/appcompat/src/android/support/v7/app/NavItemSelectedListener.java b/v7/appcompat/src/main/java/android/support/v7/app/NavItemSelectedListener.java
similarity index 100%
rename from v7/appcompat/src/android/support/v7/app/NavItemSelectedListener.java
rename to v7/appcompat/src/main/java/android/support/v7/app/NavItemSelectedListener.java
diff --git a/v7/appcompat/src/android/support/v7/app/ResourcesFlusher.java b/v7/appcompat/src/main/java/android/support/v7/app/ResourcesFlusher.java
similarity index 100%
rename from v7/appcompat/src/android/support/v7/app/ResourcesFlusher.java
rename to v7/appcompat/src/main/java/android/support/v7/app/ResourcesFlusher.java
diff --git a/v7/appcompat/src/android/support/v7/app/ToolbarActionBar.java b/v7/appcompat/src/main/java/android/support/v7/app/ToolbarActionBar.java
similarity index 100%
rename from v7/appcompat/src/android/support/v7/app/ToolbarActionBar.java
rename to v7/appcompat/src/main/java/android/support/v7/app/ToolbarActionBar.java
diff --git a/v7/appcompat/src/android/support/v7/app/TwilightCalculator.java b/v7/appcompat/src/main/java/android/support/v7/app/TwilightCalculator.java
similarity index 100%
rename from v7/appcompat/src/android/support/v7/app/TwilightCalculator.java
rename to v7/appcompat/src/main/java/android/support/v7/app/TwilightCalculator.java
diff --git a/v7/appcompat/src/android/support/v7/app/TwilightManager.java b/v7/appcompat/src/main/java/android/support/v7/app/TwilightManager.java
similarity index 100%
rename from v7/appcompat/src/android/support/v7/app/TwilightManager.java
rename to v7/appcompat/src/main/java/android/support/v7/app/TwilightManager.java
diff --git a/v7/appcompat/src/android/support/v7/app/WindowDecorActionBar.java b/v7/appcompat/src/main/java/android/support/v7/app/WindowDecorActionBar.java
similarity index 100%
rename from v7/appcompat/src/android/support/v7/app/WindowDecorActionBar.java
rename to v7/appcompat/src/main/java/android/support/v7/app/WindowDecorActionBar.java
diff --git a/v7/appcompat/src/android/support/v7/content/res/AppCompatColorStateListInflater.java b/v7/appcompat/src/main/java/android/support/v7/content/res/AppCompatColorStateListInflater.java
similarity index 100%
rename from v7/appcompat/src/android/support/v7/content/res/AppCompatColorStateListInflater.java
rename to v7/appcompat/src/main/java/android/support/v7/content/res/AppCompatColorStateListInflater.java
diff --git a/v7/appcompat/src/android/support/v7/content/res/AppCompatResources.java b/v7/appcompat/src/main/java/android/support/v7/content/res/AppCompatResources.java
similarity index 100%
rename from v7/appcompat/src/android/support/v7/content/res/AppCompatResources.java
rename to v7/appcompat/src/main/java/android/support/v7/content/res/AppCompatResources.java
diff --git a/v7/appcompat/src/android/support/v7/content/res/GrowingArrayUtils.java b/v7/appcompat/src/main/java/android/support/v7/content/res/GrowingArrayUtils.java
similarity index 100%
rename from v7/appcompat/src/android/support/v7/content/res/GrowingArrayUtils.java
rename to v7/appcompat/src/main/java/android/support/v7/content/res/GrowingArrayUtils.java
diff --git a/v7/appcompat/src/android/support/v7/graphics/drawable/DrawableWrapper.java b/v7/appcompat/src/main/java/android/support/v7/graphics/drawable/DrawableWrapper.java
similarity index 100%
rename from v7/appcompat/src/android/support/v7/graphics/drawable/DrawableWrapper.java
rename to v7/appcompat/src/main/java/android/support/v7/graphics/drawable/DrawableWrapper.java
diff --git a/v7/appcompat/src/android/support/v7/graphics/drawable/DrawerArrowDrawable.java b/v7/appcompat/src/main/java/android/support/v7/graphics/drawable/DrawerArrowDrawable.java
similarity index 100%
rename from v7/appcompat/src/android/support/v7/graphics/drawable/DrawerArrowDrawable.java
rename to v7/appcompat/src/main/java/android/support/v7/graphics/drawable/DrawerArrowDrawable.java
diff --git a/v7/appcompat/src/android/support/v7/text/AllCapsTransformationMethod.java b/v7/appcompat/src/main/java/android/support/v7/text/AllCapsTransformationMethod.java
similarity index 100%
rename from v7/appcompat/src/android/support/v7/text/AllCapsTransformationMethod.java
rename to v7/appcompat/src/main/java/android/support/v7/text/AllCapsTransformationMethod.java
diff --git a/v7/appcompat/src/android/support/v7/view/ActionBarPolicy.java b/v7/appcompat/src/main/java/android/support/v7/view/ActionBarPolicy.java
similarity index 100%
rename from v7/appcompat/src/android/support/v7/view/ActionBarPolicy.java
rename to v7/appcompat/src/main/java/android/support/v7/view/ActionBarPolicy.java
diff --git a/v7/appcompat/src/android/support/v7/view/ActionMode.java b/v7/appcompat/src/main/java/android/support/v7/view/ActionMode.java
similarity index 100%
rename from v7/appcompat/src/android/support/v7/view/ActionMode.java
rename to v7/appcompat/src/main/java/android/support/v7/view/ActionMode.java
diff --git a/v7/appcompat/src/android/support/v7/view/CollapsibleActionView.java b/v7/appcompat/src/main/java/android/support/v7/view/CollapsibleActionView.java
similarity index 100%
rename from v7/appcompat/src/android/support/v7/view/CollapsibleActionView.java
rename to v7/appcompat/src/main/java/android/support/v7/view/CollapsibleActionView.java
diff --git a/v7/appcompat/src/android/support/v7/view/ContextThemeWrapper.java b/v7/appcompat/src/main/java/android/support/v7/view/ContextThemeWrapper.java
similarity index 100%
rename from v7/appcompat/src/android/support/v7/view/ContextThemeWrapper.java
rename to v7/appcompat/src/main/java/android/support/v7/view/ContextThemeWrapper.java
diff --git a/v7/appcompat/src/android/support/v7/view/StandaloneActionMode.java b/v7/appcompat/src/main/java/android/support/v7/view/StandaloneActionMode.java
similarity index 100%
rename from v7/appcompat/src/android/support/v7/view/StandaloneActionMode.java
rename to v7/appcompat/src/main/java/android/support/v7/view/StandaloneActionMode.java
diff --git a/v7/appcompat/src/android/support/v7/view/SupportActionModeWrapper.java b/v7/appcompat/src/main/java/android/support/v7/view/SupportActionModeWrapper.java
similarity index 100%
rename from v7/appcompat/src/android/support/v7/view/SupportActionModeWrapper.java
rename to v7/appcompat/src/main/java/android/support/v7/view/SupportActionModeWrapper.java
diff --git a/v7/appcompat/src/android/support/v7/view/SupportMenuInflater.java b/v7/appcompat/src/main/java/android/support/v7/view/SupportMenuInflater.java
similarity index 100%
rename from v7/appcompat/src/android/support/v7/view/SupportMenuInflater.java
rename to v7/appcompat/src/main/java/android/support/v7/view/SupportMenuInflater.java
diff --git a/v7/appcompat/src/android/support/v7/view/ViewPropertyAnimatorCompatSet.java b/v7/appcompat/src/main/java/android/support/v7/view/ViewPropertyAnimatorCompatSet.java
similarity index 100%
rename from v7/appcompat/src/android/support/v7/view/ViewPropertyAnimatorCompatSet.java
rename to v7/appcompat/src/main/java/android/support/v7/view/ViewPropertyAnimatorCompatSet.java
diff --git a/v7/appcompat/src/android/support/v7/view/WindowCallbackWrapper.java b/v7/appcompat/src/main/java/android/support/v7/view/WindowCallbackWrapper.java
similarity index 100%
rename from v7/appcompat/src/android/support/v7/view/WindowCallbackWrapper.java
rename to v7/appcompat/src/main/java/android/support/v7/view/WindowCallbackWrapper.java
diff --git a/v7/appcompat/src/android/support/v7/view/menu/ActionMenuItem.java b/v7/appcompat/src/main/java/android/support/v7/view/menu/ActionMenuItem.java
similarity index 100%
rename from v7/appcompat/src/android/support/v7/view/menu/ActionMenuItem.java
rename to v7/appcompat/src/main/java/android/support/v7/view/menu/ActionMenuItem.java
diff --git a/v7/appcompat/src/android/support/v7/view/menu/ActionMenuItemView.java b/v7/appcompat/src/main/java/android/support/v7/view/menu/ActionMenuItemView.java
similarity index 100%
rename from v7/appcompat/src/android/support/v7/view/menu/ActionMenuItemView.java
rename to v7/appcompat/src/main/java/android/support/v7/view/menu/ActionMenuItemView.java
diff --git a/v7/appcompat/src/android/support/v7/view/menu/BaseMenuPresenter.java b/v7/appcompat/src/main/java/android/support/v7/view/menu/BaseMenuPresenter.java
similarity index 100%
rename from v7/appcompat/src/android/support/v7/view/menu/BaseMenuPresenter.java
rename to v7/appcompat/src/main/java/android/support/v7/view/menu/BaseMenuPresenter.java
diff --git a/v7/appcompat/src/android/support/v7/view/menu/BaseMenuWrapper.java b/v7/appcompat/src/main/java/android/support/v7/view/menu/BaseMenuWrapper.java
similarity index 100%
rename from v7/appcompat/src/android/support/v7/view/menu/BaseMenuWrapper.java
rename to v7/appcompat/src/main/java/android/support/v7/view/menu/BaseMenuWrapper.java
diff --git a/v7/appcompat/src/android/support/v7/view/menu/BaseWrapper.java b/v7/appcompat/src/main/java/android/support/v7/view/menu/BaseWrapper.java
similarity index 100%
rename from v7/appcompat/src/android/support/v7/view/menu/BaseWrapper.java
rename to v7/appcompat/src/main/java/android/support/v7/view/menu/BaseWrapper.java
diff --git a/v7/appcompat/src/android/support/v7/view/menu/CascadingMenuPopup.java b/v7/appcompat/src/main/java/android/support/v7/view/menu/CascadingMenuPopup.java
similarity index 100%
rename from v7/appcompat/src/android/support/v7/view/menu/CascadingMenuPopup.java
rename to v7/appcompat/src/main/java/android/support/v7/view/menu/CascadingMenuPopup.java
diff --git a/v7/appcompat/src/android/support/v7/view/menu/ExpandedMenuView.java b/v7/appcompat/src/main/java/android/support/v7/view/menu/ExpandedMenuView.java
similarity index 100%
rename from v7/appcompat/src/android/support/v7/view/menu/ExpandedMenuView.java
rename to v7/appcompat/src/main/java/android/support/v7/view/menu/ExpandedMenuView.java
diff --git a/v7/appcompat/src/android/support/v7/view/menu/ListMenuItemView.java b/v7/appcompat/src/main/java/android/support/v7/view/menu/ListMenuItemView.java
similarity index 100%
rename from v7/appcompat/src/android/support/v7/view/menu/ListMenuItemView.java
rename to v7/appcompat/src/main/java/android/support/v7/view/menu/ListMenuItemView.java
diff --git a/v7/appcompat/src/android/support/v7/view/menu/ListMenuPresenter.java b/v7/appcompat/src/main/java/android/support/v7/view/menu/ListMenuPresenter.java
similarity index 100%
rename from v7/appcompat/src/android/support/v7/view/menu/ListMenuPresenter.java
rename to v7/appcompat/src/main/java/android/support/v7/view/menu/ListMenuPresenter.java
diff --git a/v7/appcompat/src/android/support/v7/view/menu/MenuAdapter.java b/v7/appcompat/src/main/java/android/support/v7/view/menu/MenuAdapter.java
similarity index 100%
rename from v7/appcompat/src/android/support/v7/view/menu/MenuAdapter.java
rename to v7/appcompat/src/main/java/android/support/v7/view/menu/MenuAdapter.java
diff --git a/v7/appcompat/src/android/support/v7/view/menu/MenuBuilder.java b/v7/appcompat/src/main/java/android/support/v7/view/menu/MenuBuilder.java
similarity index 100%
rename from v7/appcompat/src/android/support/v7/view/menu/MenuBuilder.java
rename to v7/appcompat/src/main/java/android/support/v7/view/menu/MenuBuilder.java
diff --git a/v7/appcompat/src/android/support/v7/view/menu/MenuDialogHelper.java b/v7/appcompat/src/main/java/android/support/v7/view/menu/MenuDialogHelper.java
similarity index 100%
rename from v7/appcompat/src/android/support/v7/view/menu/MenuDialogHelper.java
rename to v7/appcompat/src/main/java/android/support/v7/view/menu/MenuDialogHelper.java
diff --git a/v7/appcompat/src/android/support/v7/view/menu/MenuHelper.java b/v7/appcompat/src/main/java/android/support/v7/view/menu/MenuHelper.java
similarity index 100%
rename from v7/appcompat/src/android/support/v7/view/menu/MenuHelper.java
rename to v7/appcompat/src/main/java/android/support/v7/view/menu/MenuHelper.java
diff --git a/v7/appcompat/src/android/support/v7/view/menu/MenuItemImpl.java b/v7/appcompat/src/main/java/android/support/v7/view/menu/MenuItemImpl.java
similarity index 100%
rename from v7/appcompat/src/android/support/v7/view/menu/MenuItemImpl.java
rename to v7/appcompat/src/main/java/android/support/v7/view/menu/MenuItemImpl.java
diff --git a/v7/appcompat/src/android/support/v7/view/menu/MenuItemWrapperICS.java b/v7/appcompat/src/main/java/android/support/v7/view/menu/MenuItemWrapperICS.java
similarity index 100%
rename from v7/appcompat/src/android/support/v7/view/menu/MenuItemWrapperICS.java
rename to v7/appcompat/src/main/java/android/support/v7/view/menu/MenuItemWrapperICS.java
diff --git a/v7/appcompat/src/android/support/v7/view/menu/MenuItemWrapperJB.java b/v7/appcompat/src/main/java/android/support/v7/view/menu/MenuItemWrapperJB.java
similarity index 100%
rename from v7/appcompat/src/android/support/v7/view/menu/MenuItemWrapperJB.java
rename to v7/appcompat/src/main/java/android/support/v7/view/menu/MenuItemWrapperJB.java
diff --git a/v7/appcompat/src/android/support/v7/view/menu/MenuPopup.java b/v7/appcompat/src/main/java/android/support/v7/view/menu/MenuPopup.java
similarity index 100%
rename from v7/appcompat/src/android/support/v7/view/menu/MenuPopup.java
rename to v7/appcompat/src/main/java/android/support/v7/view/menu/MenuPopup.java
diff --git a/v7/appcompat/src/android/support/v7/view/menu/MenuPopupHelper.java b/v7/appcompat/src/main/java/android/support/v7/view/menu/MenuPopupHelper.java
similarity index 100%
rename from v7/appcompat/src/android/support/v7/view/menu/MenuPopupHelper.java
rename to v7/appcompat/src/main/java/android/support/v7/view/menu/MenuPopupHelper.java
diff --git a/v7/appcompat/src/android/support/v7/view/menu/MenuPresenter.java b/v7/appcompat/src/main/java/android/support/v7/view/menu/MenuPresenter.java
similarity index 100%
rename from v7/appcompat/src/android/support/v7/view/menu/MenuPresenter.java
rename to v7/appcompat/src/main/java/android/support/v7/view/menu/MenuPresenter.java
diff --git a/v7/appcompat/src/android/support/v7/view/menu/MenuView.java b/v7/appcompat/src/main/java/android/support/v7/view/menu/MenuView.java
similarity index 100%
rename from v7/appcompat/src/android/support/v7/view/menu/MenuView.java
rename to v7/appcompat/src/main/java/android/support/v7/view/menu/MenuView.java
diff --git a/v7/appcompat/src/android/support/v7/view/menu/MenuWrapperFactory.java b/v7/appcompat/src/main/java/android/support/v7/view/menu/MenuWrapperFactory.java
similarity index 100%
rename from v7/appcompat/src/android/support/v7/view/menu/MenuWrapperFactory.java
rename to v7/appcompat/src/main/java/android/support/v7/view/menu/MenuWrapperFactory.java
diff --git a/v7/appcompat/src/android/support/v7/view/menu/MenuWrapperICS.java b/v7/appcompat/src/main/java/android/support/v7/view/menu/MenuWrapperICS.java
similarity index 100%
rename from v7/appcompat/src/android/support/v7/view/menu/MenuWrapperICS.java
rename to v7/appcompat/src/main/java/android/support/v7/view/menu/MenuWrapperICS.java
diff --git a/v7/appcompat/src/android/support/v7/view/menu/ShowableListMenu.java b/v7/appcompat/src/main/java/android/support/v7/view/menu/ShowableListMenu.java
similarity index 100%
rename from v7/appcompat/src/android/support/v7/view/menu/ShowableListMenu.java
rename to v7/appcompat/src/main/java/android/support/v7/view/menu/ShowableListMenu.java
diff --git a/v7/appcompat/src/android/support/v7/view/menu/StandardMenuPopup.java b/v7/appcompat/src/main/java/android/support/v7/view/menu/StandardMenuPopup.java
similarity index 100%
rename from v7/appcompat/src/android/support/v7/view/menu/StandardMenuPopup.java
rename to v7/appcompat/src/main/java/android/support/v7/view/menu/StandardMenuPopup.java
diff --git a/v7/appcompat/src/android/support/v7/view/menu/SubMenuBuilder.java b/v7/appcompat/src/main/java/android/support/v7/view/menu/SubMenuBuilder.java
similarity index 100%
rename from v7/appcompat/src/android/support/v7/view/menu/SubMenuBuilder.java
rename to v7/appcompat/src/main/java/android/support/v7/view/menu/SubMenuBuilder.java
diff --git a/v7/appcompat/src/android/support/v7/view/menu/SubMenuWrapperICS.java b/v7/appcompat/src/main/java/android/support/v7/view/menu/SubMenuWrapperICS.java
similarity index 100%
rename from v7/appcompat/src/android/support/v7/view/menu/SubMenuWrapperICS.java
rename to v7/appcompat/src/main/java/android/support/v7/view/menu/SubMenuWrapperICS.java
diff --git a/v7/appcompat/src/android/support/v7/widget/AbsActionBarView.java b/v7/appcompat/src/main/java/android/support/v7/widget/AbsActionBarView.java
similarity index 100%
rename from v7/appcompat/src/android/support/v7/widget/AbsActionBarView.java
rename to v7/appcompat/src/main/java/android/support/v7/widget/AbsActionBarView.java
diff --git a/v7/appcompat/src/android/support/v7/widget/ActionBarBackgroundDrawable.java b/v7/appcompat/src/main/java/android/support/v7/widget/ActionBarBackgroundDrawable.java
similarity index 100%
rename from v7/appcompat/src/android/support/v7/widget/ActionBarBackgroundDrawable.java
rename to v7/appcompat/src/main/java/android/support/v7/widget/ActionBarBackgroundDrawable.java
diff --git a/v7/appcompat/src/android/support/v7/widget/ActionBarBackgroundDrawableV21.java b/v7/appcompat/src/main/java/android/support/v7/widget/ActionBarBackgroundDrawableV21.java
similarity index 100%
rename from v7/appcompat/src/android/support/v7/widget/ActionBarBackgroundDrawableV21.java
rename to v7/appcompat/src/main/java/android/support/v7/widget/ActionBarBackgroundDrawableV21.java
diff --git a/v7/appcompat/src/android/support/v7/widget/ActionBarContainer.java b/v7/appcompat/src/main/java/android/support/v7/widget/ActionBarContainer.java
similarity index 100%
rename from v7/appcompat/src/android/support/v7/widget/ActionBarContainer.java
rename to v7/appcompat/src/main/java/android/support/v7/widget/ActionBarContainer.java
diff --git a/v7/appcompat/src/android/support/v7/widget/ActionBarContextView.java b/v7/appcompat/src/main/java/android/support/v7/widget/ActionBarContextView.java
similarity index 100%
rename from v7/appcompat/src/android/support/v7/widget/ActionBarContextView.java
rename to v7/appcompat/src/main/java/android/support/v7/widget/ActionBarContextView.java
diff --git a/v7/appcompat/src/android/support/v7/widget/ActionBarOverlayLayout.java b/v7/appcompat/src/main/java/android/support/v7/widget/ActionBarOverlayLayout.java
similarity index 100%
rename from v7/appcompat/src/android/support/v7/widget/ActionBarOverlayLayout.java
rename to v7/appcompat/src/main/java/android/support/v7/widget/ActionBarOverlayLayout.java
diff --git a/v7/appcompat/src/android/support/v7/widget/ActionMenuPresenter.java b/v7/appcompat/src/main/java/android/support/v7/widget/ActionMenuPresenter.java
similarity index 100%
rename from v7/appcompat/src/android/support/v7/widget/ActionMenuPresenter.java
rename to v7/appcompat/src/main/java/android/support/v7/widget/ActionMenuPresenter.java
diff --git a/v7/appcompat/src/android/support/v7/widget/ActionMenuView.java b/v7/appcompat/src/main/java/android/support/v7/widget/ActionMenuView.java
similarity index 100%
rename from v7/appcompat/src/android/support/v7/widget/ActionMenuView.java
rename to v7/appcompat/src/main/java/android/support/v7/widget/ActionMenuView.java
diff --git a/v7/appcompat/src/android/support/v7/widget/ActivityChooserModel.java b/v7/appcompat/src/main/java/android/support/v7/widget/ActivityChooserModel.java
similarity index 100%
rename from v7/appcompat/src/android/support/v7/widget/ActivityChooserModel.java
rename to v7/appcompat/src/main/java/android/support/v7/widget/ActivityChooserModel.java
diff --git a/v7/appcompat/src/android/support/v7/widget/ActivityChooserView.java b/v7/appcompat/src/main/java/android/support/v7/widget/ActivityChooserView.java
similarity index 100%
rename from v7/appcompat/src/android/support/v7/widget/ActivityChooserView.java
rename to v7/appcompat/src/main/java/android/support/v7/widget/ActivityChooserView.java
diff --git a/v7/appcompat/src/android/support/v7/widget/AlertDialogLayout.java b/v7/appcompat/src/main/java/android/support/v7/widget/AlertDialogLayout.java
similarity index 100%
rename from v7/appcompat/src/android/support/v7/widget/AlertDialogLayout.java
rename to v7/appcompat/src/main/java/android/support/v7/widget/AlertDialogLayout.java
diff --git a/v7/appcompat/src/android/support/v7/widget/AppCompatAutoCompleteTextView.java b/v7/appcompat/src/main/java/android/support/v7/widget/AppCompatAutoCompleteTextView.java
similarity index 100%
rename from v7/appcompat/src/android/support/v7/widget/AppCompatAutoCompleteTextView.java
rename to v7/appcompat/src/main/java/android/support/v7/widget/AppCompatAutoCompleteTextView.java
diff --git a/v7/appcompat/src/android/support/v7/widget/AppCompatBackgroundHelper.java b/v7/appcompat/src/main/java/android/support/v7/widget/AppCompatBackgroundHelper.java
similarity index 100%
rename from v7/appcompat/src/android/support/v7/widget/AppCompatBackgroundHelper.java
rename to v7/appcompat/src/main/java/android/support/v7/widget/AppCompatBackgroundHelper.java
diff --git a/v7/appcompat/src/android/support/v7/widget/AppCompatButton.java b/v7/appcompat/src/main/java/android/support/v7/widget/AppCompatButton.java
similarity index 100%
rename from v7/appcompat/src/android/support/v7/widget/AppCompatButton.java
rename to v7/appcompat/src/main/java/android/support/v7/widget/AppCompatButton.java
diff --git a/v7/appcompat/src/android/support/v7/widget/AppCompatCheckBox.java b/v7/appcompat/src/main/java/android/support/v7/widget/AppCompatCheckBox.java
similarity index 100%
rename from v7/appcompat/src/android/support/v7/widget/AppCompatCheckBox.java
rename to v7/appcompat/src/main/java/android/support/v7/widget/AppCompatCheckBox.java
diff --git a/v7/appcompat/src/android/support/v7/widget/AppCompatCheckedTextView.java b/v7/appcompat/src/main/java/android/support/v7/widget/AppCompatCheckedTextView.java
similarity index 100%
rename from v7/appcompat/src/android/support/v7/widget/AppCompatCheckedTextView.java
rename to v7/appcompat/src/main/java/android/support/v7/widget/AppCompatCheckedTextView.java
diff --git a/v7/appcompat/src/android/support/v7/widget/AppCompatCompoundButtonHelper.java b/v7/appcompat/src/main/java/android/support/v7/widget/AppCompatCompoundButtonHelper.java
similarity index 100%
rename from v7/appcompat/src/android/support/v7/widget/AppCompatCompoundButtonHelper.java
rename to v7/appcompat/src/main/java/android/support/v7/widget/AppCompatCompoundButtonHelper.java
diff --git a/v7/appcompat/src/android/support/v7/widget/AppCompatDrawableManager.java b/v7/appcompat/src/main/java/android/support/v7/widget/AppCompatDrawableManager.java
similarity index 100%
rename from v7/appcompat/src/android/support/v7/widget/AppCompatDrawableManager.java
rename to v7/appcompat/src/main/java/android/support/v7/widget/AppCompatDrawableManager.java
diff --git a/v7/appcompat/src/android/support/v7/widget/AppCompatEditText.java b/v7/appcompat/src/main/java/android/support/v7/widget/AppCompatEditText.java
similarity index 100%
rename from v7/appcompat/src/android/support/v7/widget/AppCompatEditText.java
rename to v7/appcompat/src/main/java/android/support/v7/widget/AppCompatEditText.java
diff --git a/v7/appcompat/src/android/support/v7/widget/AppCompatImageButton.java b/v7/appcompat/src/main/java/android/support/v7/widget/AppCompatImageButton.java
similarity index 100%
rename from v7/appcompat/src/android/support/v7/widget/AppCompatImageButton.java
rename to v7/appcompat/src/main/java/android/support/v7/widget/AppCompatImageButton.java
diff --git a/v7/appcompat/src/android/support/v7/widget/AppCompatImageHelper.java b/v7/appcompat/src/main/java/android/support/v7/widget/AppCompatImageHelper.java
similarity index 100%
rename from v7/appcompat/src/android/support/v7/widget/AppCompatImageHelper.java
rename to v7/appcompat/src/main/java/android/support/v7/widget/AppCompatImageHelper.java
diff --git a/v7/appcompat/src/android/support/v7/widget/AppCompatImageView.java b/v7/appcompat/src/main/java/android/support/v7/widget/AppCompatImageView.java
similarity index 100%
rename from v7/appcompat/src/android/support/v7/widget/AppCompatImageView.java
rename to v7/appcompat/src/main/java/android/support/v7/widget/AppCompatImageView.java
diff --git a/v7/appcompat/src/android/support/v7/widget/AppCompatMultiAutoCompleteTextView.java b/v7/appcompat/src/main/java/android/support/v7/widget/AppCompatMultiAutoCompleteTextView.java
similarity index 100%
rename from v7/appcompat/src/android/support/v7/widget/AppCompatMultiAutoCompleteTextView.java
rename to v7/appcompat/src/main/java/android/support/v7/widget/AppCompatMultiAutoCompleteTextView.java
diff --git a/v7/appcompat/src/android/support/v7/widget/AppCompatPopupWindow.java b/v7/appcompat/src/main/java/android/support/v7/widget/AppCompatPopupWindow.java
similarity index 100%
rename from v7/appcompat/src/android/support/v7/widget/AppCompatPopupWindow.java
rename to v7/appcompat/src/main/java/android/support/v7/widget/AppCompatPopupWindow.java
diff --git a/v7/appcompat/src/android/support/v7/widget/AppCompatProgressBarHelper.java b/v7/appcompat/src/main/java/android/support/v7/widget/AppCompatProgressBarHelper.java
similarity index 100%
rename from v7/appcompat/src/android/support/v7/widget/AppCompatProgressBarHelper.java
rename to v7/appcompat/src/main/java/android/support/v7/widget/AppCompatProgressBarHelper.java
diff --git a/v7/appcompat/src/android/support/v7/widget/AppCompatRadioButton.java b/v7/appcompat/src/main/java/android/support/v7/widget/AppCompatRadioButton.java
similarity index 100%
rename from v7/appcompat/src/android/support/v7/widget/AppCompatRadioButton.java
rename to v7/appcompat/src/main/java/android/support/v7/widget/AppCompatRadioButton.java
diff --git a/v7/appcompat/src/android/support/v7/widget/AppCompatRatingBar.java b/v7/appcompat/src/main/java/android/support/v7/widget/AppCompatRatingBar.java
similarity index 100%
rename from v7/appcompat/src/android/support/v7/widget/AppCompatRatingBar.java
rename to v7/appcompat/src/main/java/android/support/v7/widget/AppCompatRatingBar.java
diff --git a/v7/appcompat/src/android/support/v7/widget/AppCompatSeekBar.java b/v7/appcompat/src/main/java/android/support/v7/widget/AppCompatSeekBar.java
similarity index 100%
rename from v7/appcompat/src/android/support/v7/widget/AppCompatSeekBar.java
rename to v7/appcompat/src/main/java/android/support/v7/widget/AppCompatSeekBar.java
diff --git a/v7/appcompat/src/android/support/v7/widget/AppCompatSeekBarHelper.java b/v7/appcompat/src/main/java/android/support/v7/widget/AppCompatSeekBarHelper.java
similarity index 100%
rename from v7/appcompat/src/android/support/v7/widget/AppCompatSeekBarHelper.java
rename to v7/appcompat/src/main/java/android/support/v7/widget/AppCompatSeekBarHelper.java
diff --git a/v7/appcompat/src/android/support/v7/widget/AppCompatSpinner.java b/v7/appcompat/src/main/java/android/support/v7/widget/AppCompatSpinner.java
similarity index 100%
rename from v7/appcompat/src/android/support/v7/widget/AppCompatSpinner.java
rename to v7/appcompat/src/main/java/android/support/v7/widget/AppCompatSpinner.java
diff --git a/v7/appcompat/src/android/support/v7/widget/AppCompatTextHelper.java b/v7/appcompat/src/main/java/android/support/v7/widget/AppCompatTextHelper.java
similarity index 99%
rename from v7/appcompat/src/android/support/v7/widget/AppCompatTextHelper.java
rename to v7/appcompat/src/main/java/android/support/v7/widget/AppCompatTextHelper.java
index 75fa38f..51510aa 100644
--- a/v7/appcompat/src/android/support/v7/widget/AppCompatTextHelper.java
+++ b/v7/appcompat/src/main/java/android/support/v7/widget/AppCompatTextHelper.java
@@ -214,7 +214,7 @@
                     : R.styleable.TextAppearance_fontFamily;
             if (!context.isRestricted()) {
                 try {
-                    mFontTypeface = a.getFont(fontFamilyId, mStyle, mView);
+                    mFontTypeface = a.getFont(fontFamilyId, mStyle);
                 } catch (UnsupportedOperationException | Resources.NotFoundException e) {
                     // Expected if it is not a font resource.
                 }
diff --git a/v7/appcompat/src/android/support/v7/widget/AppCompatTextHelperV17.java b/v7/appcompat/src/main/java/android/support/v7/widget/AppCompatTextHelperV17.java
similarity index 100%
rename from v7/appcompat/src/android/support/v7/widget/AppCompatTextHelperV17.java
rename to v7/appcompat/src/main/java/android/support/v7/widget/AppCompatTextHelperV17.java
diff --git a/v7/appcompat/src/android/support/v7/widget/AppCompatTextView.java b/v7/appcompat/src/main/java/android/support/v7/widget/AppCompatTextView.java
similarity index 100%
rename from v7/appcompat/src/android/support/v7/widget/AppCompatTextView.java
rename to v7/appcompat/src/main/java/android/support/v7/widget/AppCompatTextView.java
diff --git a/v7/appcompat/src/android/support/v7/widget/AppCompatTextViewAutoSizeHelper.java b/v7/appcompat/src/main/java/android/support/v7/widget/AppCompatTextViewAutoSizeHelper.java
similarity index 100%
rename from v7/appcompat/src/android/support/v7/widget/AppCompatTextViewAutoSizeHelper.java
rename to v7/appcompat/src/main/java/android/support/v7/widget/AppCompatTextViewAutoSizeHelper.java
diff --git a/v7/appcompat/src/android/support/v7/widget/ButtonBarLayout.java b/v7/appcompat/src/main/java/android/support/v7/widget/ButtonBarLayout.java
similarity index 100%
rename from v7/appcompat/src/android/support/v7/widget/ButtonBarLayout.java
rename to v7/appcompat/src/main/java/android/support/v7/widget/ButtonBarLayout.java
diff --git a/v7/appcompat/src/android/support/v7/widget/ContentFrameLayout.java b/v7/appcompat/src/main/java/android/support/v7/widget/ContentFrameLayout.java
similarity index 100%
rename from v7/appcompat/src/android/support/v7/widget/ContentFrameLayout.java
rename to v7/appcompat/src/main/java/android/support/v7/widget/ContentFrameLayout.java
diff --git a/v7/appcompat/src/android/support/v7/widget/DecorContentParent.java b/v7/appcompat/src/main/java/android/support/v7/widget/DecorContentParent.java
similarity index 100%
rename from v7/appcompat/src/android/support/v7/widget/DecorContentParent.java
rename to v7/appcompat/src/main/java/android/support/v7/widget/DecorContentParent.java
diff --git a/v7/appcompat/src/android/support/v7/widget/DecorToolbar.java b/v7/appcompat/src/main/java/android/support/v7/widget/DecorToolbar.java
similarity index 100%
rename from v7/appcompat/src/android/support/v7/widget/DecorToolbar.java
rename to v7/appcompat/src/main/java/android/support/v7/widget/DecorToolbar.java
diff --git a/v7/appcompat/src/android/support/v7/widget/DialogTitle.java b/v7/appcompat/src/main/java/android/support/v7/widget/DialogTitle.java
similarity index 100%
rename from v7/appcompat/src/android/support/v7/widget/DialogTitle.java
rename to v7/appcompat/src/main/java/android/support/v7/widget/DialogTitle.java
diff --git a/v7/appcompat/src/android/support/v7/widget/DrawableUtils.java b/v7/appcompat/src/main/java/android/support/v7/widget/DrawableUtils.java
similarity index 100%
rename from v7/appcompat/src/android/support/v7/widget/DrawableUtils.java
rename to v7/appcompat/src/main/java/android/support/v7/widget/DrawableUtils.java
diff --git a/v7/appcompat/src/android/support/v7/widget/DropDownListView.java b/v7/appcompat/src/main/java/android/support/v7/widget/DropDownListView.java
similarity index 100%
rename from v7/appcompat/src/android/support/v7/widget/DropDownListView.java
rename to v7/appcompat/src/main/java/android/support/v7/widget/DropDownListView.java
diff --git a/v7/appcompat/src/android/support/v7/widget/FitWindowsFrameLayout.java b/v7/appcompat/src/main/java/android/support/v7/widget/FitWindowsFrameLayout.java
similarity index 100%
rename from v7/appcompat/src/android/support/v7/widget/FitWindowsFrameLayout.java
rename to v7/appcompat/src/main/java/android/support/v7/widget/FitWindowsFrameLayout.java
diff --git a/v7/appcompat/src/android/support/v7/widget/FitWindowsLinearLayout.java b/v7/appcompat/src/main/java/android/support/v7/widget/FitWindowsLinearLayout.java
similarity index 100%
rename from v7/appcompat/src/android/support/v7/widget/FitWindowsLinearLayout.java
rename to v7/appcompat/src/main/java/android/support/v7/widget/FitWindowsLinearLayout.java
diff --git a/v7/appcompat/src/android/support/v7/widget/FitWindowsViewGroup.java b/v7/appcompat/src/main/java/android/support/v7/widget/FitWindowsViewGroup.java
similarity index 100%
rename from v7/appcompat/src/android/support/v7/widget/FitWindowsViewGroup.java
rename to v7/appcompat/src/main/java/android/support/v7/widget/FitWindowsViewGroup.java
diff --git a/v7/appcompat/src/android/support/v7/widget/ForwardingListener.java b/v7/appcompat/src/main/java/android/support/v7/widget/ForwardingListener.java
similarity index 100%
rename from v7/appcompat/src/android/support/v7/widget/ForwardingListener.java
rename to v7/appcompat/src/main/java/android/support/v7/widget/ForwardingListener.java
diff --git a/v7/appcompat/src/android/support/v7/widget/LinearLayoutCompat.java b/v7/appcompat/src/main/java/android/support/v7/widget/LinearLayoutCompat.java
similarity index 100%
rename from v7/appcompat/src/android/support/v7/widget/LinearLayoutCompat.java
rename to v7/appcompat/src/main/java/android/support/v7/widget/LinearLayoutCompat.java
diff --git a/v7/appcompat/src/android/support/v7/widget/ListPopupWindow.java b/v7/appcompat/src/main/java/android/support/v7/widget/ListPopupWindow.java
similarity index 100%
rename from v7/appcompat/src/android/support/v7/widget/ListPopupWindow.java
rename to v7/appcompat/src/main/java/android/support/v7/widget/ListPopupWindow.java
diff --git a/v7/appcompat/src/android/support/v7/widget/ListViewCompat.java b/v7/appcompat/src/main/java/android/support/v7/widget/ListViewCompat.java
similarity index 100%
rename from v7/appcompat/src/android/support/v7/widget/ListViewCompat.java
rename to v7/appcompat/src/main/java/android/support/v7/widget/ListViewCompat.java
diff --git a/v7/appcompat/src/android/support/v7/widget/MenuItemHoverListener.java b/v7/appcompat/src/main/java/android/support/v7/widget/MenuItemHoverListener.java
similarity index 100%
rename from v7/appcompat/src/android/support/v7/widget/MenuItemHoverListener.java
rename to v7/appcompat/src/main/java/android/support/v7/widget/MenuItemHoverListener.java
diff --git a/v7/appcompat/src/android/support/v7/widget/MenuPopupWindow.java b/v7/appcompat/src/main/java/android/support/v7/widget/MenuPopupWindow.java
similarity index 100%
rename from v7/appcompat/src/android/support/v7/widget/MenuPopupWindow.java
rename to v7/appcompat/src/main/java/android/support/v7/widget/MenuPopupWindow.java
diff --git a/v7/appcompat/src/android/support/v7/widget/PopupMenu.java b/v7/appcompat/src/main/java/android/support/v7/widget/PopupMenu.java
similarity index 100%
rename from v7/appcompat/src/android/support/v7/widget/PopupMenu.java
rename to v7/appcompat/src/main/java/android/support/v7/widget/PopupMenu.java
diff --git a/v7/appcompat/src/android/support/v7/widget/ResourcesWrapper.java b/v7/appcompat/src/main/java/android/support/v7/widget/ResourcesWrapper.java
similarity index 100%
rename from v7/appcompat/src/android/support/v7/widget/ResourcesWrapper.java
rename to v7/appcompat/src/main/java/android/support/v7/widget/ResourcesWrapper.java
diff --git a/v7/appcompat/src/android/support/v7/widget/RtlSpacingHelper.java b/v7/appcompat/src/main/java/android/support/v7/widget/RtlSpacingHelper.java
similarity index 100%
rename from v7/appcompat/src/android/support/v7/widget/RtlSpacingHelper.java
rename to v7/appcompat/src/main/java/android/support/v7/widget/RtlSpacingHelper.java
diff --git a/v7/appcompat/src/android/support/v7/widget/ScrollingTabContainerView.java b/v7/appcompat/src/main/java/android/support/v7/widget/ScrollingTabContainerView.java
similarity index 100%
rename from v7/appcompat/src/android/support/v7/widget/ScrollingTabContainerView.java
rename to v7/appcompat/src/main/java/android/support/v7/widget/ScrollingTabContainerView.java
diff --git a/v7/appcompat/src/android/support/v7/widget/SearchView.java b/v7/appcompat/src/main/java/android/support/v7/widget/SearchView.java
similarity index 100%
rename from v7/appcompat/src/android/support/v7/widget/SearchView.java
rename to v7/appcompat/src/main/java/android/support/v7/widget/SearchView.java
diff --git a/v7/appcompat/src/android/support/v7/widget/ShareActionProvider.java b/v7/appcompat/src/main/java/android/support/v7/widget/ShareActionProvider.java
similarity index 100%
rename from v7/appcompat/src/android/support/v7/widget/ShareActionProvider.java
rename to v7/appcompat/src/main/java/android/support/v7/widget/ShareActionProvider.java
diff --git a/v7/appcompat/src/android/support/v7/widget/SuggestionsAdapter.java b/v7/appcompat/src/main/java/android/support/v7/widget/SuggestionsAdapter.java
similarity index 100%
rename from v7/appcompat/src/android/support/v7/widget/SuggestionsAdapter.java
rename to v7/appcompat/src/main/java/android/support/v7/widget/SuggestionsAdapter.java
diff --git a/v7/appcompat/src/android/support/v7/widget/SwitchCompat.java b/v7/appcompat/src/main/java/android/support/v7/widget/SwitchCompat.java
similarity index 100%
rename from v7/appcompat/src/android/support/v7/widget/SwitchCompat.java
rename to v7/appcompat/src/main/java/android/support/v7/widget/SwitchCompat.java
diff --git a/v7/appcompat/src/android/support/v7/widget/ThemeUtils.java b/v7/appcompat/src/main/java/android/support/v7/widget/ThemeUtils.java
similarity index 100%
rename from v7/appcompat/src/android/support/v7/widget/ThemeUtils.java
rename to v7/appcompat/src/main/java/android/support/v7/widget/ThemeUtils.java
diff --git a/v7/appcompat/src/android/support/v7/widget/ThemedSpinnerAdapter.java b/v7/appcompat/src/main/java/android/support/v7/widget/ThemedSpinnerAdapter.java
similarity index 100%
rename from v7/appcompat/src/android/support/v7/widget/ThemedSpinnerAdapter.java
rename to v7/appcompat/src/main/java/android/support/v7/widget/ThemedSpinnerAdapter.java
diff --git a/v7/appcompat/src/android/support/v7/widget/TintContextWrapper.java b/v7/appcompat/src/main/java/android/support/v7/widget/TintContextWrapper.java
similarity index 100%
rename from v7/appcompat/src/android/support/v7/widget/TintContextWrapper.java
rename to v7/appcompat/src/main/java/android/support/v7/widget/TintContextWrapper.java
diff --git a/v7/appcompat/src/android/support/v7/widget/TintInfo.java b/v7/appcompat/src/main/java/android/support/v7/widget/TintInfo.java
similarity index 100%
rename from v7/appcompat/src/android/support/v7/widget/TintInfo.java
rename to v7/appcompat/src/main/java/android/support/v7/widget/TintInfo.java
diff --git a/v7/appcompat/src/android/support/v7/widget/TintResources.java b/v7/appcompat/src/main/java/android/support/v7/widget/TintResources.java
similarity index 100%
rename from v7/appcompat/src/android/support/v7/widget/TintResources.java
rename to v7/appcompat/src/main/java/android/support/v7/widget/TintResources.java
diff --git a/v7/appcompat/src/android/support/v7/widget/TintTypedArray.java b/v7/appcompat/src/main/java/android/support/v7/widget/TintTypedArray.java
similarity index 95%
rename from v7/appcompat/src/android/support/v7/widget/TintTypedArray.java
rename to v7/appcompat/src/main/java/android/support/v7/widget/TintTypedArray.java
index 2213dd3..2270955 100644
--- a/v7/appcompat/src/android/support/v7/widget/TintTypedArray.java
+++ b/v7/appcompat/src/main/java/android/support/v7/widget/TintTypedArray.java
@@ -25,7 +25,6 @@
 import android.graphics.Typeface;
 import android.graphics.drawable.Drawable;
 import android.os.Build;
-import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
 import android.support.annotation.RequiresApi;
 import android.support.annotation.RestrictTo;
@@ -34,7 +33,6 @@
 import android.support.v7.content.res.AppCompatResources;
 import android.util.AttributeSet;
 import android.util.TypedValue;
-import android.widget.TextView;
 
 /**
  * A class that wraps a {@link android.content.res.TypedArray} and provides the same public API
@@ -98,9 +96,9 @@
      *
      * @param index Index of attribute to retrieve.
      * @param style A style value used for selecting best match font from the list of family. Note
-     * that this value will be ignored if the platform supports font family(API 24 or later).
-     * @param targetView A text view to be applied this font. If async loading is specified in XML,
-     * this view will be refreshed with result typeface.
+     * that this value will be ignored if the platform supports font family (API 24 or later).
+     * @param fontCallback A callback to receive async fetching of this font. If async loading is
+     *                     specified in XML, this callback will be triggered.
      *
      * @return Typeface for the attribute, or {@code null} if not defined.
      * @throws RuntimeException if the TypedArray has already been recycled.
@@ -108,7 +106,7 @@
      *         not a font resource.
      */
     @Nullable
-    public Typeface getFont(@StyleableRes int index, int style, @NonNull TextView targetView) {
+    public Typeface getFont(@StyleableRes int index, int style) {
         final int resourceId = mWrapped.getResourceId(index, 0);
         if (resourceId == 0) {
             return null;
@@ -116,7 +114,7 @@
         if (mTypedValue == null) {
             mTypedValue = new TypedValue();
         }
-        return ResourcesCompat.getFont(mContext, resourceId, mTypedValue, style, targetView);
+        return ResourcesCompat.getFont(mContext, resourceId, mTypedValue, style);
     }
 
     public int length() {
diff --git a/v7/appcompat/src/android/support/v7/widget/Toolbar.java b/v7/appcompat/src/main/java/android/support/v7/widget/Toolbar.java
similarity index 100%
rename from v7/appcompat/src/android/support/v7/widget/Toolbar.java
rename to v7/appcompat/src/main/java/android/support/v7/widget/Toolbar.java
diff --git a/v7/appcompat/src/android/support/v7/widget/ToolbarWidgetWrapper.java b/v7/appcompat/src/main/java/android/support/v7/widget/ToolbarWidgetWrapper.java
similarity index 100%
rename from v7/appcompat/src/android/support/v7/widget/ToolbarWidgetWrapper.java
rename to v7/appcompat/src/main/java/android/support/v7/widget/ToolbarWidgetWrapper.java
diff --git a/v7/appcompat/src/android/support/v7/widget/TooltipCompat.java b/v7/appcompat/src/main/java/android/support/v7/widget/TooltipCompat.java
similarity index 100%
rename from v7/appcompat/src/android/support/v7/widget/TooltipCompat.java
rename to v7/appcompat/src/main/java/android/support/v7/widget/TooltipCompat.java
diff --git a/v7/appcompat/src/android/support/v7/widget/TooltipCompatHandler.java b/v7/appcompat/src/main/java/android/support/v7/widget/TooltipCompatHandler.java
similarity index 100%
rename from v7/appcompat/src/android/support/v7/widget/TooltipCompatHandler.java
rename to v7/appcompat/src/main/java/android/support/v7/widget/TooltipCompatHandler.java
diff --git a/v7/appcompat/src/android/support/v7/widget/TooltipPopup.java b/v7/appcompat/src/main/java/android/support/v7/widget/TooltipPopup.java
similarity index 100%
rename from v7/appcompat/src/android/support/v7/widget/TooltipPopup.java
rename to v7/appcompat/src/main/java/android/support/v7/widget/TooltipPopup.java
diff --git a/v7/appcompat/src/android/support/v7/widget/VectorEnabledTintResources.java b/v7/appcompat/src/main/java/android/support/v7/widget/VectorEnabledTintResources.java
similarity index 100%
rename from v7/appcompat/src/android/support/v7/widget/VectorEnabledTintResources.java
rename to v7/appcompat/src/main/java/android/support/v7/widget/VectorEnabledTintResources.java
diff --git a/v7/appcompat/src/android/support/v7/widget/ViewStubCompat.java b/v7/appcompat/src/main/java/android/support/v7/widget/ViewStubCompat.java
similarity index 100%
rename from v7/appcompat/src/android/support/v7/widget/ViewStubCompat.java
rename to v7/appcompat/src/main/java/android/support/v7/widget/ViewStubCompat.java
diff --git a/v7/appcompat/src/android/support/v7/widget/ViewUtils.java b/v7/appcompat/src/main/java/android/support/v7/widget/ViewUtils.java
similarity index 100%
rename from v7/appcompat/src/android/support/v7/widget/ViewUtils.java
rename to v7/appcompat/src/main/java/android/support/v7/widget/ViewUtils.java
diff --git a/v7/cardview/Android.mk b/v7/cardview/Android.mk
index 56fa996..19d377c 100644
--- a/v7/cardview/Android.mk
+++ b/v7/cardview/Android.mk
@@ -25,7 +25,7 @@
 LOCAL_MODULE := android-support-v7-cardview
 LOCAL_SDK_VERSION := $(SUPPORT_CURRENT_SDK_VERSION)
 LOCAL_SRC_FILES := \
-    $(call all-java-files-under,src)
+    $(call all-java-files-under,src/main/java)
 LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
 LOCAL_SHARED_ANDROID_LIBRARIES := \
     android-support-annotations
diff --git a/v7/cardview/build.gradle b/v7/cardview/build.gradle
index 5d9494e..76c3bf3 100644
--- a/v7/cardview/build.gradle
+++ b/v7/cardview/build.gradle
@@ -10,9 +10,6 @@
     }
 
     sourceSets {
-        main.java.srcDirs = [
-                'src'
-        ]
         main.res.srcDir 'res'
     }
 }
diff --git a/v7/cardview/src/android/support/v7/widget/CardView.java b/v7/cardview/src/main/java/android/support/v7/widget/CardView.java
similarity index 98%
rename from v7/cardview/src/android/support/v7/widget/CardView.java
rename to v7/cardview/src/main/java/android/support/v7/widget/CardView.java
index 3df45d9..58a04f0 100644
--- a/v7/cardview/src/android/support/v7/widget/CardView.java
+++ b/v7/cardview/src/main/java/android/support/v7/widget/CardView.java
@@ -24,6 +24,7 @@
 import android.graphics.drawable.Drawable;
 import android.os.Build;
 import android.support.annotation.ColorInt;
+import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
 import android.support.v7.cardview.R;
 import android.util.AttributeSet;
@@ -106,17 +107,17 @@
 
     final Rect mShadowBounds = new Rect();
 
-    public CardView(Context context) {
+    public CardView(@NonNull Context context) {
         super(context);
         initialize(context, null, 0);
     }
 
-    public CardView(Context context, AttributeSet attrs) {
+    public CardView(@NonNull Context context, @Nullable AttributeSet attrs) {
         super(context, attrs);
         initialize(context, attrs, 0);
     }
 
-    public CardView(Context context, AttributeSet attrs, int defStyleAttr) {
+    public CardView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
         super(context, attrs, defStyleAttr);
         initialize(context, attrs, defStyleAttr);
     }
@@ -300,6 +301,7 @@
      *
      * @return The background color state list of the CardView.
      */
+    @NonNull
     public ColorStateList getCardBackgroundColor() {
         return IMPL.getBackgroundColor(mCardViewDelegate);
     }
diff --git a/v7/cardview/src/android/support/v7/widget/CardViewApi17Impl.java b/v7/cardview/src/main/java/android/support/v7/widget/CardViewApi17Impl.java
similarity index 100%
rename from v7/cardview/src/android/support/v7/widget/CardViewApi17Impl.java
rename to v7/cardview/src/main/java/android/support/v7/widget/CardViewApi17Impl.java
diff --git a/v7/cardview/src/android/support/v7/widget/CardViewApi21Impl.java b/v7/cardview/src/main/java/android/support/v7/widget/CardViewApi21Impl.java
similarity index 100%
rename from v7/cardview/src/android/support/v7/widget/CardViewApi21Impl.java
rename to v7/cardview/src/main/java/android/support/v7/widget/CardViewApi21Impl.java
diff --git a/v7/cardview/src/android/support/v7/widget/CardViewBaseImpl.java b/v7/cardview/src/main/java/android/support/v7/widget/CardViewBaseImpl.java
similarity index 100%
rename from v7/cardview/src/android/support/v7/widget/CardViewBaseImpl.java
rename to v7/cardview/src/main/java/android/support/v7/widget/CardViewBaseImpl.java
diff --git a/v7/cardview/src/android/support/v7/widget/CardViewDelegate.java b/v7/cardview/src/main/java/android/support/v7/widget/CardViewDelegate.java
similarity index 100%
rename from v7/cardview/src/android/support/v7/widget/CardViewDelegate.java
rename to v7/cardview/src/main/java/android/support/v7/widget/CardViewDelegate.java
diff --git a/v7/cardview/src/android/support/v7/widget/CardViewImpl.java b/v7/cardview/src/main/java/android/support/v7/widget/CardViewImpl.java
similarity index 100%
rename from v7/cardview/src/android/support/v7/widget/CardViewImpl.java
rename to v7/cardview/src/main/java/android/support/v7/widget/CardViewImpl.java
diff --git a/v7/cardview/src/android/support/v7/widget/RoundRectDrawable.java b/v7/cardview/src/main/java/android/support/v7/widget/RoundRectDrawable.java
similarity index 100%
rename from v7/cardview/src/android/support/v7/widget/RoundRectDrawable.java
rename to v7/cardview/src/main/java/android/support/v7/widget/RoundRectDrawable.java
diff --git a/v7/cardview/src/android/support/v7/widget/RoundRectDrawableWithShadow.java b/v7/cardview/src/main/java/android/support/v7/widget/RoundRectDrawableWithShadow.java
similarity index 100%
rename from v7/cardview/src/android/support/v7/widget/RoundRectDrawableWithShadow.java
rename to v7/cardview/src/main/java/android/support/v7/widget/RoundRectDrawableWithShadow.java
diff --git a/v7/gridlayout/Android.mk b/v7/gridlayout/Android.mk
index 6eac23b4..5091081 100644
--- a/v7/gridlayout/Android.mk
+++ b/v7/gridlayout/Android.mk
@@ -27,7 +27,7 @@
 LOCAL_USE_AAPT2 := true
 LOCAL_MODULE := android-support-v7-gridlayout
 LOCAL_SDK_VERSION := $(SUPPORT_CURRENT_SDK_VERSION)
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
+LOCAL_SRC_FILES := $(call all-java-files-under, src/main/java)
 LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
 LOCAL_SHARED_ANDROID_LIBRARIES := \
     android-support-compat \
diff --git a/v7/gridlayout/build.gradle b/v7/gridlayout/build.gradle
index e0df821..d4d467d 100644
--- a/v7/gridlayout/build.gradle
+++ b/v7/gridlayout/build.gradle
@@ -14,7 +14,6 @@
     }
 
     sourceSets {
-        main.java.srcDir 'src'
         main.res.srcDir 'res'
     }
 }
diff --git a/v7/gridlayout/src/android/support/v7/widget/GridLayout.java b/v7/gridlayout/src/main/java/android/support/v7/widget/GridLayout.java
similarity index 100%
rename from v7/gridlayout/src/android/support/v7/widget/GridLayout.java
rename to v7/gridlayout/src/main/java/android/support/v7/widget/GridLayout.java
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 b7fb054..e716fb5 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
@@ -80,7 +80,7 @@
         /**
          * Called when the {@link Palette} has been generated.
          */
-        void onGenerated(Palette palette);
+        void onGenerated(@NonNull Palette palette);
     }
 
     static final int DEFAULT_RESIZE_BITMAP_AREA = 112 * 112;
@@ -95,7 +95,8 @@
     /**
      * Start generating a {@link Palette} with the returned {@link Builder} instance.
      */
-    public static Builder from(Bitmap bitmap) {
+    @NonNull
+    public static Builder from(@NonNull Bitmap bitmap) {
         return new Builder(bitmap);
     }
 
@@ -104,7 +105,8 @@
      * This is useful for testing, or if you want to resurrect a {@link Palette} instance from a
      * list of swatches. Will return null if the {@code swatches} is null.
      */
-    public static Palette from(List<Swatch> swatches) {
+    @NonNull
+    public static Palette from(@NonNull List<Swatch> swatches) {
         return new Builder(swatches).generate();
     }
 
@@ -484,6 +486,7 @@
          *     hsv[1] is Saturation [0...1]
          *     hsv[2] is Lightness [0...1]
          */
+        @NonNull
         public float[] getHsl() {
             if (mHsl == null) {
                 mHsl = new float[3];
@@ -610,7 +613,7 @@
         /**
          * Construct a new {@link Builder} using a source {@link Bitmap}
          */
-        public Builder(Bitmap bitmap) {
+        public Builder(@NonNull Bitmap bitmap) {
             if (bitmap == null || bitmap.isRecycled()) {
                 throw new IllegalArgumentException("Bitmap is not valid");
             }
@@ -631,7 +634,7 @@
          * Construct a new {@link Builder} using a list of {@link Swatch} instances.
          * Typically only used for testing.
          */
-        public Builder(List<Swatch> swatches) {
+        public Builder(@NonNull List<Swatch> swatches) {
             if (swatches == null || swatches.isEmpty()) {
                 throw new IllegalArgumentException("List of Swatches is not valid");
             }
@@ -850,7 +853,8 @@
          * generated.
          */
         @NonNull
-        public AsyncTask<Bitmap, Void, Palette> generate(final PaletteAsyncListener listener) {
+        public AsyncTask<Bitmap, Void, Palette> generate(
+                @NonNull final PaletteAsyncListener listener) {
             if (listener == null) {
                 throw new IllegalArgumentException("listener can not be null");
             }
@@ -943,7 +947,7 @@
          *
          * @see Builder#addFilter(Filter)
          */
-        boolean isAllowed(int rgb, float[] hsl);
+        boolean isAllowed(@ColorInt int rgb, @NonNull float[] hsl);
     }
 
     /**
diff --git a/v7/palette/src/main/java/android/support/v7/graphics/Target.java b/v7/palette/src/main/java/android/support/v7/graphics/Target.java
index 640970b..0eff90b 100644
--- a/v7/palette/src/main/java/android/support/v7/graphics/Target.java
+++ b/v7/palette/src/main/java/android/support/v7/graphics/Target.java
@@ -17,6 +17,7 @@
 package android.support.v7.graphics;
 
 import android.support.annotation.FloatRange;
+import android.support.annotation.NonNull;
 
 /**
  * A class which allows custom selection of colors in a {@link Palette}'s generation. Instances
@@ -122,7 +123,7 @@
         setDefaultWeights();
     }
 
-    Target(Target from) {
+    Target(@NonNull Target from) {
         System.arraycopy(from.mSaturationTargets, 0, mSaturationTargets, 0,
                 mSaturationTargets.length);
         System.arraycopy(from.mLightnessTargets, 0, mLightnessTargets, 0,
@@ -295,13 +296,14 @@
         /**
          * Create a new builder based on an existing {@link Target}.
          */
-        public Builder(Target target) {
+        public Builder(@NonNull Target target) {
             mTarget = new Target(target);
         }
 
         /**
          * Set the minimum saturation value for this target.
          */
+        @NonNull
         public Builder setMinimumSaturation(@FloatRange(from = 0, to = 1) float value) {
             mTarget.mSaturationTargets[INDEX_MIN] = value;
             return this;
@@ -310,6 +312,7 @@
         /**
          * Set the target/ideal saturation value for this target.
          */
+        @NonNull
         public Builder setTargetSaturation(@FloatRange(from = 0, to = 1) float value) {
             mTarget.mSaturationTargets[INDEX_TARGET] = value;
             return this;
@@ -318,6 +321,7 @@
         /**
          * Set the maximum saturation value for this target.
          */
+        @NonNull
         public Builder setMaximumSaturation(@FloatRange(from = 0, to = 1) float value) {
             mTarget.mSaturationTargets[INDEX_MAX] = value;
             return this;
@@ -326,6 +330,7 @@
         /**
          * Set the minimum lightness value for this target.
          */
+        @NonNull
         public Builder setMinimumLightness(@FloatRange(from = 0, to = 1) float value) {
             mTarget.mLightnessTargets[INDEX_MIN] = value;
             return this;
@@ -334,6 +339,7 @@
         /**
          * Set the target/ideal lightness value for this target.
          */
+        @NonNull
         public Builder setTargetLightness(@FloatRange(from = 0, to = 1) float value) {
             mTarget.mLightnessTargets[INDEX_TARGET] = value;
             return this;
@@ -342,6 +348,7 @@
         /**
          * Set the maximum lightness value for this target.
          */
+        @NonNull
         public Builder setMaximumLightness(@FloatRange(from = 0, to = 1) float value) {
             mTarget.mLightnessTargets[INDEX_MAX] = value;
             return this;
@@ -358,6 +365,7 @@
          *
          * @see #setTargetSaturation(float)
          */
+        @NonNull
         public Builder setSaturationWeight(@FloatRange(from = 0) float weight) {
             mTarget.mWeights[INDEX_WEIGHT_SAT] = weight;
             return this;
@@ -374,6 +382,7 @@
          *
          * @see #setTargetLightness(float)
          */
+        @NonNull
         public Builder setLightnessWeight(@FloatRange(from = 0) float weight) {
             mTarget.mWeights[INDEX_WEIGHT_LUMA] = weight;
             return this;
@@ -389,6 +398,7 @@
          * <p>A weight of 0 means that it has no weight, and thus has no
          * bearing on the selection.</p>
          */
+        @NonNull
         public Builder setPopulationWeight(@FloatRange(from = 0) float weight) {
             mTarget.mWeights[INDEX_WEIGHT_POP] = weight;
             return this;
@@ -401,6 +411,7 @@
          * @param exclusive true if any the color is exclusive to this target, or false is the
          *                  color can be selected for other targets.
          */
+        @NonNull
         public Builder setExclusive(boolean exclusive) {
             mTarget.mIsExclusive = exclusive;
             return this;
@@ -409,6 +420,7 @@
         /**
          * Builds and returns the resulting {@link Target}.
          */
+        @NonNull
         public Target build() {
             return mTarget;
         }
diff --git a/v7/recyclerview/Android.mk b/v7/recyclerview/Android.mk
index e434ab2..dcebe88 100644
--- a/v7/recyclerview/Android.mk
+++ b/v7/recyclerview/Android.mk
@@ -27,7 +27,7 @@
 LOCAL_USE_AAPT2 := true
 LOCAL_MODULE := android-support-v7-recyclerview
 LOCAL_SDK_VERSION := $(SUPPORT_CURRENT_SDK_VERSION)
-LOCAL_SRC_FILES := $(call all-java-files-under,src)
+LOCAL_SRC_FILES := $(call all-java-files-under,src/main/java)
 LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
 LOCAL_SHARED_ANDROID_LIBRARIES := \
     android-support-compat \
diff --git a/v7/recyclerview/build.gradle b/v7/recyclerview/build.gradle
index e035b82..ad1150f 100644
--- a/v7/recyclerview/build.gradle
+++ b/v7/recyclerview/build.gradle
@@ -23,10 +23,7 @@
     }
 
     sourceSets {
-        main.java.srcDir 'src'
         main.res.srcDirs 'res', 'res-public'
-
-        test.java.srcDir 'jvm-tests/src'
     }
 
     testOptions {
diff --git a/v7/recyclerview/src/android/support/v7/util/AsyncListUtil.java b/v7/recyclerview/src/main/java/android/support/v7/util/AsyncListUtil.java
similarity index 100%
rename from v7/recyclerview/src/android/support/v7/util/AsyncListUtil.java
rename to v7/recyclerview/src/main/java/android/support/v7/util/AsyncListUtil.java
diff --git a/v7/recyclerview/src/android/support/v7/util/BatchingListUpdateCallback.java b/v7/recyclerview/src/main/java/android/support/v7/util/BatchingListUpdateCallback.java
similarity index 100%
rename from v7/recyclerview/src/android/support/v7/util/BatchingListUpdateCallback.java
rename to v7/recyclerview/src/main/java/android/support/v7/util/BatchingListUpdateCallback.java
diff --git a/v7/recyclerview/src/android/support/v7/util/DiffUtil.java b/v7/recyclerview/src/main/java/android/support/v7/util/DiffUtil.java
similarity index 100%
rename from v7/recyclerview/src/android/support/v7/util/DiffUtil.java
rename to v7/recyclerview/src/main/java/android/support/v7/util/DiffUtil.java
diff --git a/v7/recyclerview/src/android/support/v7/util/ListUpdateCallback.java b/v7/recyclerview/src/main/java/android/support/v7/util/ListUpdateCallback.java
similarity index 100%
rename from v7/recyclerview/src/android/support/v7/util/ListUpdateCallback.java
rename to v7/recyclerview/src/main/java/android/support/v7/util/ListUpdateCallback.java
diff --git a/v7/recyclerview/src/android/support/v7/util/MessageThreadUtil.java b/v7/recyclerview/src/main/java/android/support/v7/util/MessageThreadUtil.java
similarity index 100%
rename from v7/recyclerview/src/android/support/v7/util/MessageThreadUtil.java
rename to v7/recyclerview/src/main/java/android/support/v7/util/MessageThreadUtil.java
diff --git a/v7/recyclerview/src/android/support/v7/util/SortedList.java b/v7/recyclerview/src/main/java/android/support/v7/util/SortedList.java
similarity index 100%
rename from v7/recyclerview/src/android/support/v7/util/SortedList.java
rename to v7/recyclerview/src/main/java/android/support/v7/util/SortedList.java
diff --git a/v7/recyclerview/src/android/support/v7/util/ThreadUtil.java b/v7/recyclerview/src/main/java/android/support/v7/util/ThreadUtil.java
similarity index 100%
rename from v7/recyclerview/src/android/support/v7/util/ThreadUtil.java
rename to v7/recyclerview/src/main/java/android/support/v7/util/ThreadUtil.java
diff --git a/v7/recyclerview/src/android/support/v7/util/TileList.java b/v7/recyclerview/src/main/java/android/support/v7/util/TileList.java
similarity index 100%
rename from v7/recyclerview/src/android/support/v7/util/TileList.java
rename to v7/recyclerview/src/main/java/android/support/v7/util/TileList.java
diff --git a/v7/recyclerview/src/android/support/v7/widget/AdapterHelper.java b/v7/recyclerview/src/main/java/android/support/v7/widget/AdapterHelper.java
similarity index 100%
rename from v7/recyclerview/src/android/support/v7/widget/AdapterHelper.java
rename to v7/recyclerview/src/main/java/android/support/v7/widget/AdapterHelper.java
diff --git a/v7/recyclerview/src/android/support/v7/widget/ChildHelper.java b/v7/recyclerview/src/main/java/android/support/v7/widget/ChildHelper.java
similarity index 100%
rename from v7/recyclerview/src/android/support/v7/widget/ChildHelper.java
rename to v7/recyclerview/src/main/java/android/support/v7/widget/ChildHelper.java
diff --git a/v7/recyclerview/src/android/support/v7/widget/DefaultItemAnimator.java b/v7/recyclerview/src/main/java/android/support/v7/widget/DefaultItemAnimator.java
similarity index 100%
rename from v7/recyclerview/src/android/support/v7/widget/DefaultItemAnimator.java
rename to v7/recyclerview/src/main/java/android/support/v7/widget/DefaultItemAnimator.java
diff --git a/v7/recyclerview/src/android/support/v7/widget/DividerItemDecoration.java b/v7/recyclerview/src/main/java/android/support/v7/widget/DividerItemDecoration.java
similarity index 100%
rename from v7/recyclerview/src/android/support/v7/widget/DividerItemDecoration.java
rename to v7/recyclerview/src/main/java/android/support/v7/widget/DividerItemDecoration.java
diff --git a/v7/recyclerview/src/android/support/v7/widget/FastScroller.java b/v7/recyclerview/src/main/java/android/support/v7/widget/FastScroller.java
similarity index 100%
rename from v7/recyclerview/src/android/support/v7/widget/FastScroller.java
rename to v7/recyclerview/src/main/java/android/support/v7/widget/FastScroller.java
diff --git a/v7/recyclerview/src/android/support/v7/widget/GapWorker.java b/v7/recyclerview/src/main/java/android/support/v7/widget/GapWorker.java
similarity index 100%
rename from v7/recyclerview/src/android/support/v7/widget/GapWorker.java
rename to v7/recyclerview/src/main/java/android/support/v7/widget/GapWorker.java
diff --git a/v7/recyclerview/src/android/support/v7/widget/GridLayoutManager.java b/v7/recyclerview/src/main/java/android/support/v7/widget/GridLayoutManager.java
similarity index 100%
rename from v7/recyclerview/src/android/support/v7/widget/GridLayoutManager.java
rename to v7/recyclerview/src/main/java/android/support/v7/widget/GridLayoutManager.java
diff --git a/v7/recyclerview/src/android/support/v7/widget/LayoutState.java b/v7/recyclerview/src/main/java/android/support/v7/widget/LayoutState.java
similarity index 100%
rename from v7/recyclerview/src/android/support/v7/widget/LayoutState.java
rename to v7/recyclerview/src/main/java/android/support/v7/widget/LayoutState.java
diff --git a/v7/recyclerview/src/android/support/v7/widget/LinearLayoutManager.java b/v7/recyclerview/src/main/java/android/support/v7/widget/LinearLayoutManager.java
similarity index 100%
rename from v7/recyclerview/src/android/support/v7/widget/LinearLayoutManager.java
rename to v7/recyclerview/src/main/java/android/support/v7/widget/LinearLayoutManager.java
diff --git a/v7/recyclerview/src/android/support/v7/widget/LinearSmoothScroller.java b/v7/recyclerview/src/main/java/android/support/v7/widget/LinearSmoothScroller.java
similarity index 100%
rename from v7/recyclerview/src/android/support/v7/widget/LinearSmoothScroller.java
rename to v7/recyclerview/src/main/java/android/support/v7/widget/LinearSmoothScroller.java
diff --git a/v7/recyclerview/src/android/support/v7/widget/LinearSnapHelper.java b/v7/recyclerview/src/main/java/android/support/v7/widget/LinearSnapHelper.java
similarity index 100%
rename from v7/recyclerview/src/android/support/v7/widget/LinearSnapHelper.java
rename to v7/recyclerview/src/main/java/android/support/v7/widget/LinearSnapHelper.java
diff --git a/v7/recyclerview/src/android/support/v7/widget/OpReorderer.java b/v7/recyclerview/src/main/java/android/support/v7/widget/OpReorderer.java
similarity index 100%
rename from v7/recyclerview/src/android/support/v7/widget/OpReorderer.java
rename to v7/recyclerview/src/main/java/android/support/v7/widget/OpReorderer.java
diff --git a/v7/recyclerview/src/android/support/v7/widget/OrientationHelper.java b/v7/recyclerview/src/main/java/android/support/v7/widget/OrientationHelper.java
similarity index 100%
rename from v7/recyclerview/src/android/support/v7/widget/OrientationHelper.java
rename to v7/recyclerview/src/main/java/android/support/v7/widget/OrientationHelper.java
diff --git a/v7/recyclerview/src/android/support/v7/widget/PagerSnapHelper.java b/v7/recyclerview/src/main/java/android/support/v7/widget/PagerSnapHelper.java
similarity index 100%
rename from v7/recyclerview/src/android/support/v7/widget/PagerSnapHelper.java
rename to v7/recyclerview/src/main/java/android/support/v7/widget/PagerSnapHelper.java
diff --git a/v7/recyclerview/src/android/support/v7/widget/PositionMap.java b/v7/recyclerview/src/main/java/android/support/v7/widget/PositionMap.java
similarity index 100%
rename from v7/recyclerview/src/android/support/v7/widget/PositionMap.java
rename to v7/recyclerview/src/main/java/android/support/v7/widget/PositionMap.java
diff --git a/v7/recyclerview/src/android/support/v7/widget/RecyclerView.java b/v7/recyclerview/src/main/java/android/support/v7/widget/RecyclerView.java
similarity index 100%
rename from v7/recyclerview/src/android/support/v7/widget/RecyclerView.java
rename to v7/recyclerview/src/main/java/android/support/v7/widget/RecyclerView.java
diff --git a/v7/recyclerview/src/android/support/v7/widget/RecyclerViewAccessibilityDelegate.java b/v7/recyclerview/src/main/java/android/support/v7/widget/RecyclerViewAccessibilityDelegate.java
similarity index 100%
rename from v7/recyclerview/src/android/support/v7/widget/RecyclerViewAccessibilityDelegate.java
rename to v7/recyclerview/src/main/java/android/support/v7/widget/RecyclerViewAccessibilityDelegate.java
diff --git a/v7/recyclerview/src/android/support/v7/widget/ScrollbarHelper.java b/v7/recyclerview/src/main/java/android/support/v7/widget/ScrollbarHelper.java
similarity index 100%
rename from v7/recyclerview/src/android/support/v7/widget/ScrollbarHelper.java
rename to v7/recyclerview/src/main/java/android/support/v7/widget/ScrollbarHelper.java
diff --git a/v7/recyclerview/src/android/support/v7/widget/SimpleItemAnimator.java b/v7/recyclerview/src/main/java/android/support/v7/widget/SimpleItemAnimator.java
similarity index 100%
rename from v7/recyclerview/src/android/support/v7/widget/SimpleItemAnimator.java
rename to v7/recyclerview/src/main/java/android/support/v7/widget/SimpleItemAnimator.java
diff --git a/v7/recyclerview/src/android/support/v7/widget/SnapHelper.java b/v7/recyclerview/src/main/java/android/support/v7/widget/SnapHelper.java
similarity index 100%
rename from v7/recyclerview/src/android/support/v7/widget/SnapHelper.java
rename to v7/recyclerview/src/main/java/android/support/v7/widget/SnapHelper.java
diff --git a/v7/recyclerview/src/android/support/v7/widget/StaggeredGridLayoutManager.java b/v7/recyclerview/src/main/java/android/support/v7/widget/StaggeredGridLayoutManager.java
similarity index 100%
rename from v7/recyclerview/src/android/support/v7/widget/StaggeredGridLayoutManager.java
rename to v7/recyclerview/src/main/java/android/support/v7/widget/StaggeredGridLayoutManager.java
diff --git a/v7/recyclerview/src/android/support/v7/widget/ViewBoundsCheck.java b/v7/recyclerview/src/main/java/android/support/v7/widget/ViewBoundsCheck.java
similarity index 100%
rename from v7/recyclerview/src/android/support/v7/widget/ViewBoundsCheck.java
rename to v7/recyclerview/src/main/java/android/support/v7/widget/ViewBoundsCheck.java
diff --git a/v7/recyclerview/src/android/support/v7/widget/ViewInfoStore.java b/v7/recyclerview/src/main/java/android/support/v7/widget/ViewInfoStore.java
similarity index 100%
rename from v7/recyclerview/src/android/support/v7/widget/ViewInfoStore.java
rename to v7/recyclerview/src/main/java/android/support/v7/widget/ViewInfoStore.java
diff --git a/v7/recyclerview/src/android/support/v7/widget/helper/ItemTouchHelper.java b/v7/recyclerview/src/main/java/android/support/v7/widget/helper/ItemTouchHelper.java
similarity index 100%
rename from v7/recyclerview/src/android/support/v7/widget/helper/ItemTouchHelper.java
rename to v7/recyclerview/src/main/java/android/support/v7/widget/helper/ItemTouchHelper.java
diff --git a/v7/recyclerview/src/android/support/v7/widget/helper/ItemTouchUIUtil.java b/v7/recyclerview/src/main/java/android/support/v7/widget/helper/ItemTouchUIUtil.java
similarity index 100%
rename from v7/recyclerview/src/android/support/v7/widget/helper/ItemTouchUIUtil.java
rename to v7/recyclerview/src/main/java/android/support/v7/widget/helper/ItemTouchUIUtil.java
diff --git a/v7/recyclerview/src/android/support/v7/widget/helper/ItemTouchUIUtilImpl.java b/v7/recyclerview/src/main/java/android/support/v7/widget/helper/ItemTouchUIUtilImpl.java
similarity index 100%
rename from v7/recyclerview/src/android/support/v7/widget/helper/ItemTouchUIUtilImpl.java
rename to v7/recyclerview/src/main/java/android/support/v7/widget/helper/ItemTouchUIUtilImpl.java
diff --git a/v7/recyclerview/src/android/support/v7/widget/util/SortedListAdapterCallback.java b/v7/recyclerview/src/main/java/android/support/v7/widget/util/SortedListAdapterCallback.java
similarity index 100%
rename from v7/recyclerview/src/android/support/v7/widget/util/SortedListAdapterCallback.java
rename to v7/recyclerview/src/main/java/android/support/v7/widget/util/SortedListAdapterCallback.java
diff --git a/v7/recyclerview/jvm-tests/NO_DOCS b/v7/recyclerview/src/test/NO_DOCS
similarity index 100%
rename from v7/recyclerview/jvm-tests/NO_DOCS
rename to v7/recyclerview/src/test/NO_DOCS
diff --git a/v7/recyclerview/jvm-tests/src/android/support/v7/util/BatchingListUpdateCallbackTest.java b/v7/recyclerview/src/test/java/android/support/v7/util/BatchingListUpdateCallbackTest.java
similarity index 100%
rename from v7/recyclerview/jvm-tests/src/android/support/v7/util/BatchingListUpdateCallbackTest.java
rename to v7/recyclerview/src/test/java/android/support/v7/util/BatchingListUpdateCallbackTest.java
diff --git a/v7/recyclerview/jvm-tests/src/android/support/v7/util/DiffUtilTest.java b/v7/recyclerview/src/test/java/android/support/v7/util/DiffUtilTest.java
similarity index 100%
rename from v7/recyclerview/jvm-tests/src/android/support/v7/util/DiffUtilTest.java
rename to v7/recyclerview/src/test/java/android/support/v7/util/DiffUtilTest.java
diff --git a/v7/recyclerview/jvm-tests/src/android/support/v7/util/SortedListBatchedCallbackTest.java b/v7/recyclerview/src/test/java/android/support/v7/util/SortedListBatchedCallbackTest.java
similarity index 100%
rename from v7/recyclerview/jvm-tests/src/android/support/v7/util/SortedListBatchedCallbackTest.java
rename to v7/recyclerview/src/test/java/android/support/v7/util/SortedListBatchedCallbackTest.java
diff --git a/v7/recyclerview/jvm-tests/src/android/support/v7/util/SortedListTest.java b/v7/recyclerview/src/test/java/android/support/v7/util/SortedListTest.java
similarity index 100%
rename from v7/recyclerview/jvm-tests/src/android/support/v7/util/SortedListTest.java
rename to v7/recyclerview/src/test/java/android/support/v7/util/SortedListTest.java
diff --git a/v7/recyclerview/jvm-tests/src/android/support/v7/widget/AdapterHelperTest.java b/v7/recyclerview/src/test/java/android/support/v7/widget/AdapterHelperTest.java
similarity index 100%
rename from v7/recyclerview/jvm-tests/src/android/support/v7/widget/AdapterHelperTest.java
rename to v7/recyclerview/src/test/java/android/support/v7/widget/AdapterHelperTest.java
diff --git a/v7/recyclerview/jvm-tests/src/android/support/v7/widget/OpReorderTest.java b/v7/recyclerview/src/test/java/android/support/v7/widget/OpReorderTest.java
similarity index 100%
rename from v7/recyclerview/jvm-tests/src/android/support/v7/widget/OpReorderTest.java
rename to v7/recyclerview/src/test/java/android/support/v7/widget/OpReorderTest.java
diff --git a/v7/recyclerview/jvm-tests/src/android/support/v7/widget/ViewInfoStoreTest.java b/v7/recyclerview/src/test/java/android/support/v7/widget/ViewInfoStoreTest.java
similarity index 100%
rename from v7/recyclerview/jvm-tests/src/android/support/v7/widget/ViewInfoStoreTest.java
rename to v7/recyclerview/src/test/java/android/support/v7/widget/ViewInfoStoreTest.java
diff --git a/wear/Android.mk b/wear/Android.mk
index eec890b..fde4aa1 100644
--- a/wear/Android.mk
+++ b/wear/Android.mk
@@ -14,6 +14,12 @@
 
 LOCAL_PATH := $(call my-dir)
 
+# Here is a prebuilt library containing all the wearable stubs necessary for ambient mode
+include $(CLEAR_VARS)
+LOCAL_PREBUILT_STATIC_JAVA_LIBRARIES := \
+        prebuilt-com.google.android.wearable-stubs:wear_stubs/com.google.android.wearable-stubs.jar
+include $(BUILD_MULTI_PREBUILT)
+
 # Here is the final static library that apps can link against.
 # Applications that use this library must specify
 #
@@ -22,7 +28,8 @@
 #       android-support-core-ui \
 #       android-support-v7-recyclerview
 #
-# in their makefiles to include the resources and their dependencies in their package.
+# in their makefiles to include the resources and their dependencies in their package
+
 include $(CLEAR_VARS)
 LOCAL_USE_AAPT2 := true
 LOCAL_MODULE := android-support-wear
@@ -35,7 +42,10 @@
         android-support-percent \
         android-support-v7-recyclerview \
         android-support-v4
+LOCAL_STATIC_JAVA_LIBRARIES := \
+        prebuilt-com.google.android.wearable-stubs
 LOCAL_JAR_EXCLUDE_FILES := none
 LOCAL_JAVA_LANGUAGE_VERSION := 1.7
 LOCAL_AAPT_FLAGS := --add-javadoc-annotation doconly
 include $(BUILD_STATIC_JAVA_LIBRARY)
+
diff --git a/wear/api/current.txt b/wear/api/current.txt
index afffeed..e397eb3 100644
--- a/wear/api/current.txt
+++ b/wear/api/current.txt
@@ -1,3 +1,31 @@
+package android.support.wear.ambient {
+
+  public final class AmbientMode extends android.app.Fragment {
+    ctor public AmbientMode();
+    method public static <T extends android.app.Activity & android.support.wear.ambient.AmbientMode.AmbientCallbackProvider> android.support.wear.ambient.AmbientMode.AmbientController attachAmbientSupport(T);
+    field public static final java.lang.String EXTRA_BURN_IN_PROTECTION = "com.google.android.wearable.compat.extra.BURN_IN_PROTECTION";
+    field public static final java.lang.String EXTRA_LOWBIT_AMBIENT = "com.google.android.wearable.compat.extra.LOWBIT_AMBIENT";
+    field public static final java.lang.String FRAGMENT_TAG = "android.support.wearable.ambient.AmbientMode";
+  }
+
+  public static abstract class AmbientMode.AmbientCallback {
+    ctor public AmbientMode.AmbientCallback();
+    method public void onEnterAmbient(android.os.Bundle);
+    method public void onExitAmbient();
+    method public void onUpdateAmbient();
+  }
+
+  public static abstract interface AmbientMode.AmbientCallbackProvider {
+    method public abstract android.support.wear.ambient.AmbientMode.AmbientCallback getAmbientCallback();
+  }
+
+  public final class AmbientMode.AmbientController {
+    method public boolean isAmbient();
+    method public void setAutoResumeEnabled(boolean);
+  }
+
+}
+
 package android.support.wear.utils {
 
   public class MetadataConstants {
diff --git a/wear/build.gradle b/wear/build.gradle
index f471bc0..23a397a 100644
--- a/wear/build.gradle
+++ b/wear/build.gradle
@@ -3,6 +3,7 @@
 dependencies {
     api project(':support-annotations')
     api project(':support-core-ui')
+    api project(':support-fragment')
     api project(':percent')
     api project(':recyclerview-v7')
 
@@ -10,6 +11,8 @@
     androidTestImplementation libs.espresso_core,    { exclude module: 'support-annotations' }
     androidTestImplementation libs.mockito_core,     { exclude group: 'net.bytebuddy' } // DexMaker has it"s own MockMaker
     androidTestImplementation libs.dexmaker_mockito, { exclude group: 'net.bytebuddy' } // DexMaker has it"s own MockMaker
+
+    provided fileTree(dir: 'wear_stubs', include: ['com.google.android.wearable-stubs.jar'])
 }
 
 android {
@@ -20,6 +23,9 @@
     sourceSets {
         main.java.srcDir 'src'
         main.res.srcDirs 'res', 'res-public'
+        main.resources {
+            includes = ["wear_stubs/LICENSE"]
+        }
     }
 
     buildTypes.all {
@@ -32,4 +38,9 @@
     publish true
     inceptionYear '2016'
     description 'Android Wear Support UI'
+
+    license {
+        name 'The Apache Software License, Version 2.0'
+        url 'http://www.apache.org/licenses/LICENSE-2.0.txt'
+    }
 }
diff --git a/wear/src/android/support/wear/ambient/AmbientDelegate.java b/wear/src/android/support/wear/ambient/AmbientDelegate.java
new file mode 100644
index 0000000..4901290
--- /dev/null
+++ b/wear/src/android/support/wear/ambient/AmbientDelegate.java
@@ -0,0 +1,207 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.support.wear.ambient;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.util.Log;
+
+import com.google.android.wearable.compat.WearableActivityController;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.lang.ref.WeakReference;
+import java.lang.reflect.Method;
+
+/**
+ * Provides compatibility for ambient mode.
+ */
+final class AmbientDelegate {
+
+    private static final String TAG = "AmbientDelegate";
+
+    private WearableActivityController mWearableController;
+
+    private static boolean sInitAutoResumeEnabledMethod;
+    private static boolean sHasAutoResumeEnabledMethod;
+    private final WearableControllerProvider mWearableControllerProvider;
+    private final AmbientCallback mCallback;
+    private final WeakReference<Activity> mActivity;
+
+    /**
+     * AmbientCallback must be implemented by all users of the delegate.
+     */
+    interface AmbientCallback {
+        /**
+         * Called when an activity is entering ambient mode. This event is sent while an activity is
+         * running (after onResume, before onPause). All drawing should complete by the conclusion
+         * of this method. Note that {@code invalidate()} calls will be executed before resuming
+         * lower-power mode.
+         * <p>
+         * <p><em>Derived classes must call through to the super class's implementation of this
+         * method. If they do not, an exception will be thrown.</em>
+         *
+         * @param ambientDetails bundle containing information about the display being used.
+         *                      It includes information about low-bit color and burn-in protection.
+         */
+        void onEnterAmbient(Bundle ambientDetails);
+
+        /**
+         * Called when the system is updating the display for ambient mode. Activities may use this
+         * opportunity to update or invalidate views.
+         */
+        void onUpdateAmbient();
+
+        /**
+         * Called when an activity should exit ambient mode. This event is sent while an activity is
+         * running (after onResume, before onPause).
+         * <p>
+         * <p><em>Derived classes must call through to the super class's implementation of this
+         * method. If they do not, an exception will be thrown.</em>
+         */
+        void onExitAmbient();
+    }
+
+    AmbientDelegate(@Nullable Activity activity,
+                           @NonNull WearableControllerProvider wearableControllerProvider,
+                           @NonNull AmbientCallback callback) {
+        mActivity = new WeakReference<>(activity);
+        mCallback = callback;
+        mWearableControllerProvider = wearableControllerProvider;
+    }
+
+    /**
+     * Receives and handles the onCreate call from the associated {@link AmbientMode}
+     */
+    void onCreate() {
+        Activity activity = mActivity.get();
+        if (activity != null) {
+            mWearableController =
+                    mWearableControllerProvider.getWearableController(activity, mCallback);
+        }
+        if (mWearableController != null) {
+            mWearableController.onCreate();
+        }
+    }
+
+    /**
+     * Receives and handles the onResume call from the associated {@link AmbientMode}
+     */
+    void onResume() {
+        if (mWearableController != null) {
+            mWearableController.onResume();
+        }
+    }
+
+    /**
+     * Receives and handles the onPause call from the associated {@link AmbientMode}
+     */
+    void onPause() {
+        if (mWearableController != null) {
+            mWearableController.onPause();
+        }
+    }
+
+    /**
+     * Receives and handles the onStop call from the associated {@link AmbientMode}
+     */
+    void onStop() {
+        if (mWearableController != null) {
+            mWearableController.onStop();
+        }
+    }
+
+    /**
+     * Receives and handles the onDestroy call from the associated {@link AmbientMode}
+     */
+    void onDestroy() {
+        if (mWearableController != null) {
+            mWearableController.onDestroy();
+        }
+    }
+
+    /**
+     * Sets that this activity should remain displayed when the system enters ambient mode. The
+     * default is false. In this case, the activity is stopped when the system enters ambient mode.
+     */
+    void setAmbientEnabled() {
+        if (mWearableController != null) {
+            mWearableController.setAmbientEnabled();
+        }
+    }
+
+    /**
+     * Sets whether this activity's task should be moved to the front when the system exits ambient
+     * mode. If true, the activity's task may be moved to the front if it was the last activity to
+     * be running when ambient started, depending on how much time the system spent in ambient mode.
+     */
+    void setAutoResumeEnabled(boolean enabled) {
+        if (mWearableController != null) {
+            if (hasSetAutoResumeEnabledMethod()) {
+                mWearableController.setAutoResumeEnabled(enabled);
+            }
+        }
+    }
+
+    /**
+     * @return {@code true} if the activity is currently in ambient.
+     */
+    boolean isAmbient() {
+        if (mWearableController != null) {
+            return mWearableController.isAmbient();
+        }
+        return false;
+    }
+
+    /**
+     * Dump the current state of the wearableController responsible for implementing the Ambient
+     * mode.
+     */
+    void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
+        if (mWearableController != null) {
+            mWearableController.dump(prefix, fd, writer, args);
+        }
+    }
+
+    private boolean hasSetAutoResumeEnabledMethod() {
+        if (!sInitAutoResumeEnabledMethod) {
+            sInitAutoResumeEnabledMethod = true;
+            try {
+                Method method =
+                        WearableActivityController.class
+                                .getDeclaredMethod("setAutoResumeEnabled", boolean.class);
+                // Proguard is sneaky -- it will actually rewrite strings it finds in addition to
+                // function names. Therefore add a "." prefix to the method name check to ensure the
+                // function was not renamed by proguard.
+                if (!(".setAutoResumeEnabled".equals("." + method.getName()))) {
+                    throw new NoSuchMethodException();
+                }
+                sHasAutoResumeEnabledMethod = true;
+            } catch (NoSuchMethodException e) {
+                Log.w(
+                        "WearableActivity",
+                        "Could not find a required method for auto-resume "
+                                + "support, likely due to proguard optimization. Please add "
+                                + "com.google.android.wearable:wearable jar to the list of library "
+                                + "jars for your project");
+                sHasAutoResumeEnabledMethod = false;
+            }
+        }
+        return sHasAutoResumeEnabledMethod;
+    }
+}
diff --git a/wear/src/android/support/wear/ambient/AmbientMode.java b/wear/src/android/support/wear/ambient/AmbientMode.java
new file mode 100644
index 0000000..7fbbbb3
--- /dev/null
+++ b/wear/src/android/support/wear/ambient/AmbientMode.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.wear.ambient;
+
+import android.app.Activity;
+import android.app.Fragment;
+import android.app.FragmentManager;
+import android.content.Context;
+import android.os.Bundle;
+import android.support.annotation.CallSuper;
+import android.support.annotation.VisibleForTesting;
+import android.util.Log;
+
+import com.google.android.wearable.compat.WearableActivityController;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+
+/**
+ * Use this as a headless Fragment to add ambient support to an Activity on Wearable devices.
+ * <p>
+ * The application that uses this should add the {@link android.Manifest.permission#WAKE_LOCK}
+ * permission to its manifest.
+ * <p>
+ * The primary entry  point for this code is the {@link #attachAmbientSupport(Activity)} method.
+ * It should be called with an {@link Activity} as an argument and that {@link Activity} will then
+ * be able to receive ambient lifecycle events through an {@link AmbientCallback}. The
+ * {@link Activity} will also receive a {@link AmbientController} object from the attachment which
+ * can be used to query the current status of the ambient mode, or toggle simple settings.
+ * An example of how to attach {@link AmbientMode} to your {@link Activity} and use
+ * the {@link AmbientController} can be found below:
+ * <p>
+ * <pre class="prettyprint">{@code
+ *     AmbientMode.AmbientController controller = AmbientMode.attachAmbientSupport(this);
+ *     controller.setAutoResumeEnabled(true);
+ * }</pre>
+ */
+public final class AmbientMode extends Fragment {
+
+    /**
+     * Property in bundle passed to {@code AmbientCallback#onEnterAmbient(Bundle)} to indicate
+     * whether burn-in protection is required. When this property is set to true, views must be
+     * shifted around periodically in ambient mode. To ensure that content isn't shifted off
+     * the screen, avoid placing content within 10 pixels of the edge of the screen. Activities
+     * should also avoid solid white areas to prevent pixel burn-in. Both of these requirements
+     * only apply in ambient mode, and only when this property is set to true.
+     */
+    public static final String EXTRA_BURN_IN_PROTECTION =
+            WearableActivityController.EXTRA_BURN_IN_PROTECTION;
+
+    /**
+     * Property in bundle passed to {@code AmbientCallback#onEnterAmbient(Bundle)} to indicate
+     * whether the device has low-bit ambient mode. When this property is set to true, the screen
+     * supports fewer bits for each color in ambient mode. In this case, activities should disable
+     * anti-aliasing in ambient mode.
+     */
+    public static final String EXTRA_LOWBIT_AMBIENT =
+            WearableActivityController.EXTRA_LOWBIT_AMBIENT;
+
+    /**
+     * Fragment tag used by default when adding {@link AmbientMode} to add ambient support to an
+     * {@link Activity}.
+     */
+    public static final String FRAGMENT_TAG = "android.support.wearable.ambient.AmbientMode";
+
+    /**
+     * Interface for any {@link Activity} that wishes to implement Ambient Mode. Use the
+     * {@link #getAmbientCallback()} method to return and {@link AmbientCallback} which can be used
+     * to bind the {@link AmbientMode} to the instantiation of this interface.
+     * <p>
+     * <pre class="prettyprint">{@code
+     * return new AmbientMode.AmbientCallback() {
+     *     public void onEnterAmbient(Bundle ambientDetails) {...}
+     *     public void onExitAmbient(Bundle ambientDetails) {...}
+     *  }
+     * }</pre>
+     */
+    public interface AmbientCallbackProvider {
+        /**
+         * @return the {@link AmbientCallback} to be used by this class to communicate with the
+         * entity interested in ambient events.
+         */
+        AmbientCallback getAmbientCallback();
+    }
+
+    /**
+     * Callback to receive ambient mode state changes. It must be used by all users of AmbientMode.
+     */
+    public abstract static class AmbientCallback {
+        /**
+         * Called when an activity is entering ambient mode. This event is sent while an activity is
+         * running (after onResume, before onPause). All drawing should complete by the conclusion
+         * of this method. Note that {@code invalidate()} calls will be executed before resuming
+         * lower-power mode.
+         * <p>
+         * <p><em>Derived classes must call through to the super class's implementation of this
+         * method. If they do not, an exception will be thrown.</em>
+         *
+         * @param ambientDetails bundle containing information about the display being used.
+         *                      It includes information about low-bit color and burn-in protection.
+         */
+        public void onEnterAmbient(Bundle ambientDetails) {}
+
+        /**
+         * Called when the system is updating the display for ambient mode. Activities may use this
+         * opportunity to update or invalidate views.
+         */
+        public void onUpdateAmbient() {};
+
+        /**
+         * Called when an activity should exit ambient mode. This event is sent while an activity is
+         * running (after onResume, before onPause).
+         * <p>
+         * <p><em>Derived classes must call through to the super class's implementation of this
+         * method. If they do not, an exception will be thrown.</em>
+         */
+        public void onExitAmbient() {};
+    }
+
+    private final AmbientDelegate.AmbientCallback mCallback =
+            new AmbientDelegate.AmbientCallback() {
+                @Override
+                public void onEnterAmbient(Bundle ambientDetails) {
+                    mSuppliedCallback.onEnterAmbient(ambientDetails);
+                }
+
+                @Override
+                public void onExitAmbient() {
+                    mSuppliedCallback.onExitAmbient();
+                }
+
+                @Override
+                public void onUpdateAmbient() {
+                    mSuppliedCallback.onUpdateAmbient();
+                }
+            };
+    private AmbientDelegate mDelegate;
+    private AmbientCallback mSuppliedCallback;
+    private AmbientController mController;
+
+    /**
+     * Constructor
+     */
+    public AmbientMode() {
+        mController = new AmbientController();
+    }
+
+    @Override
+    @CallSuper
+    public void onAttach(Context context) {
+        super.onAttach(context);
+        mDelegate = new AmbientDelegate(getActivity(), new WearableControllerProvider(), mCallback);
+
+        if (context instanceof AmbientCallbackProvider) {
+            mSuppliedCallback = ((AmbientCallbackProvider) context).getAmbientCallback();
+        } else {
+            throw new IllegalArgumentException(
+                    "fragment should attach to an activity that implements AmbientCallback");
+        }
+    }
+
+    @Override
+    @CallSuper
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        mDelegate.onCreate();
+        mDelegate.setAmbientEnabled();
+    }
+
+    @Override
+    @CallSuper
+    public void onResume() {
+        super.onResume();
+        mDelegate.onResume();
+    }
+
+    @Override
+    @CallSuper
+    public void onPause() {
+        mDelegate.onPause();
+        super.onPause();
+    }
+
+    @Override
+    @CallSuper
+    public void onStop() {
+        mDelegate.onStop();
+        super.onStop();
+    }
+
+    @Override
+    @CallSuper
+    public void onDestroy() {
+        mDelegate.onDestroy();
+        super.onDestroy();
+    }
+
+    @Override
+    @CallSuper
+    public void onDetach() {
+        mDelegate = null;
+        super.onDetach();
+    }
+
+    /**
+     * Attach ambient support to the given activity.
+     *
+     * @param activity the activity to attach ambient support to. This activity has to also
+     *                implement {@link AmbientCallbackProvider}
+     * @return the associated {@link AmbientController} which can be used to query the state of
+     * ambient mode and toggle simple settings related to it.
+     */
+    public static <T extends Activity & AmbientCallbackProvider> AmbientController
+            attachAmbientSupport(T activity) {
+        FragmentManager fragmentManager = activity.getFragmentManager();
+        AmbientMode ambientFragment = (AmbientMode) fragmentManager.findFragmentByTag(FRAGMENT_TAG);
+        if (ambientFragment == null) {
+            AmbientMode fragment = new AmbientMode();
+            fragmentManager
+                    .beginTransaction()
+                    .add(fragment, FRAGMENT_TAG)
+                    .commit();
+            ambientFragment = fragment;
+        }
+        return ambientFragment.mController;
+    }
+
+    @Override
+    public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
+        if (mDelegate != null) {
+            mDelegate.dump(prefix, fd, writer, args);
+        }
+    }
+
+    @VisibleForTesting
+    void setAmbientDelegate(AmbientDelegate delegate) {
+        mDelegate = delegate;
+    }
+
+    /**
+     * A class for interacting with the ambient mode on a wearable device. This class can be used to
+     * query the current state of ambient mode and to enable or disable certain settings.
+     * An instance of this class is returned to the user when they attach their {@link Activity}
+     * to {@link AmbientMode}.
+     */
+    public final class AmbientController {
+        private static final String TAG = "AmbientController";
+
+        // Do not initialize outside of this class.
+        AmbientController() {}
+
+        /**
+         * Sets whether this activity's task should be moved to the front when the system exits
+         * ambient mode. If true, the activity's task may be moved to the front if it was the last
+         * activity to be running when ambient started, depending on how much time the system spent
+         * in ambient mode.
+         */
+        public void setAutoResumeEnabled(boolean enabled) {
+            if (mDelegate != null) {
+                mDelegate.setAutoResumeEnabled(enabled);
+            } else {
+                Log.w(TAG, "The fragment is not yet fully initialized, this call is a no-op");
+            }
+        }
+
+        /**
+         * @return {@code true} if the activity is currently in ambient.
+         */
+        public boolean isAmbient() {
+            return mDelegate == null ? false : mDelegate.isAmbient();
+        }
+    }
+}
diff --git a/wear/src/android/support/wear/ambient/SharedLibraryVersion.java b/wear/src/android/support/wear/ambient/SharedLibraryVersion.java
new file mode 100644
index 0000000..cd90a3b
--- /dev/null
+++ b/wear/src/android/support/wear/ambient/SharedLibraryVersion.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.support.wear.ambient;
+
+import android.os.Build;
+import android.support.annotation.RestrictTo;
+import android.support.annotation.VisibleForTesting;
+
+import com.google.android.wearable.WearableSharedLib;
+
+/**
+ * Internal class which can be used to determine the version of the wearable shared library that is
+ * available on the current device.
+ *
+ * @hide
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+final class SharedLibraryVersion {
+
+    private SharedLibraryVersion() {
+    }
+
+    /**
+     * Returns the version of the wearable shared library available on the current device.
+     * <p>
+     * <p>Version 1 was introduced on 2016-09-26, so any previous shared library will return 0. In
+     * those cases, it may be necessary to check {@code Build.VERSION.SDK_INT}.
+     *
+     * @throws IllegalStateException if the Wearable Shared Library is not present, which means that
+     * the {@code <uses-library>} tag is missing.
+     */
+    public static int version() {
+        verifySharedLibraryPresent();
+        return VersionHolder.VERSION;
+    }
+
+    /**
+     * Throws {@link IllegalStateException} if the Wearable Shared Library is not present and API
+     * level is at least LMP MR1.
+     * <p>
+     * <p>This validates that the developer hasn't forgotten to include a {@code <uses-library>} tag
+     * in their manifest. The method should be used in combination with API level checks for
+     * features added before {@link #version() version} 1.
+     */
+    public static void verifySharedLibraryPresent() {
+        if (!PresenceHolder.PRESENT) {
+            throw new IllegalStateException("Could not find wearable shared library classes. "
+                    + "Please add <uses-library android:name=\"com.google.android.wearable\" "
+                    + "android:required=\"false\" /> to the application manifest");
+        }
+    }
+
+    // Lazy initialization holder class (see Effective Java item 71)
+    @VisibleForTesting
+    static final class VersionHolder {
+        static final int VERSION = getSharedLibVersion(Build.VERSION.SDK_INT);
+
+        @VisibleForTesting
+        static int getSharedLibVersion(int sdkInt) {
+            if (sdkInt < Build.VERSION_CODES.N_MR1) {
+                // WearableSharedLib was introduced in N MR1 (Wear FDP 4)
+                return 0;
+            }
+            return WearableSharedLib.version();
+        }
+    }
+
+    // Lazy initialization holder class (see Effective Java item 71)
+    @VisibleForTesting
+    static final class PresenceHolder {
+        static final boolean PRESENT = isSharedLibPresent(Build.VERSION.SDK_INT);
+
+        @VisibleForTesting
+        static boolean isSharedLibPresent(int sdkInt) {
+            try {
+                // A class which has been available on the shared library from the first version.
+                Class.forName("com.google.android.wearable.compat.WearableActivityController");
+            } catch (ClassNotFoundException e) {
+                return false;
+            }
+            return true;
+        }
+    }
+}
diff --git a/wear/src/android/support/wear/ambient/WearableControllerProvider.java b/wear/src/android/support/wear/ambient/WearableControllerProvider.java
new file mode 100644
index 0000000..1682dc0
--- /dev/null
+++ b/wear/src/android/support/wear/ambient/WearableControllerProvider.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.support.wear.ambient;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.support.annotation.RestrictTo;
+
+import com.google.android.wearable.compat.WearableActivityController;
+
+import java.lang.reflect.Method;
+
+/**
+ * Provides a {@link WearableActivityController} for ambient mode control.
+ *
+ * @hide
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+public class WearableControllerProvider {
+
+    private static final String TAG = "WearableControllerProvider";
+
+    private static volatile boolean sAmbientCallbacksVerifiedPresent;
+
+    /**
+     * Retrieves a {@link WearableActivityController} to use for ambient mode.
+     *
+     * @param activity The {@link Activity} to be associated with the Controller.
+     * @param callback The {@link AmbientDelegate.AmbientCallback} for the Controller.
+     * @return the platform-appropriate version of the {@link WearableActivityController}.
+     */
+    public WearableActivityController getWearableController(Activity activity,
+            final AmbientDelegate.AmbientCallback callback) {
+        SharedLibraryVersion.verifySharedLibraryPresent();
+
+        // The AmbientCallback is an abstract class instead of an interface.
+        WearableActivityController.AmbientCallback callbackBridge =
+                new WearableActivityController.AmbientCallback() {
+                    @Override
+                    public void onEnterAmbient(Bundle ambientDetails) {
+                        callback.onEnterAmbient(ambientDetails);
+                    }
+
+                    @Override
+                    public void onUpdateAmbient() {
+                        callback.onUpdateAmbient();
+                    }
+
+                    @Override
+                    public void onExitAmbient() {
+                        callback.onExitAmbient();
+                    }
+                };
+
+        verifyAmbientCallbacksPresent();
+
+        return new WearableActivityController(TAG, activity, callbackBridge);
+    }
+
+    private static void verifyAmbientCallbacksPresent() {
+        if (sAmbientCallbacksVerifiedPresent) {
+            return;
+        }
+        try {
+            Method method =
+                    WearableActivityController.AmbientCallback.class.getDeclaredMethod(
+                            "onEnterAmbient", Bundle.class);
+            // Proguard is sneaky -- it will actually rewrite strings it finds in addition to
+            // function names. Therefore add a "." prefix to the method name check to ensure the
+            // function was not renamed by proguard.
+            if (!(".onEnterAmbient".equals("." + method.getName()))) {
+                throw new NoSuchMethodException();
+            }
+        } catch (NoSuchMethodException e) {
+            throw new IllegalStateException(
+                    "Could not find a required method for "
+                            + "ambient support, likely due to proguard optimization. Please add "
+                            + "com.google.android.wearable:wearable jar to the list of library jars"
+                            + " for your project");
+        }
+        sAmbientCallbacksVerifiedPresent = true;
+    }
+}
diff --git a/wear/tests/AndroidManifest.xml b/wear/tests/AndroidManifest.xml
index 834e067..ce78477 100644
--- a/wear/tests/AndroidManifest.xml
+++ b/wear/tests/AndroidManifest.xml
@@ -48,6 +48,13 @@
                 <category android:name="android.intent.category.LAUNCHER"/>
             </intent-filter>
         </activity>
+
+        <activity android:name="android.support.wear.ambient.AmbientModeTestActivity">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN"/>
+                <category android:name="android.intent.category.LAUNCHER"/>
+            </intent-filter>
+        </activity>
         <!-- Test app is iOS compatible. -->
         <meta-data
             android:name="com.google.android.wearable.standalone"
diff --git a/wear/tests/src/android/support/wear/ambient/AmbientDelegateTest.java b/wear/tests/src/android/support/wear/ambient/AmbientDelegateTest.java
new file mode 100644
index 0000000..32f9bb6
--- /dev/null
+++ b/wear/tests/src/android/support/wear/ambient/AmbientDelegateTest.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.support.wear.ambient;
+
+import static junit.framework.Assert.assertFalse;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyZeroInteractions;
+import static org.mockito.Mockito.when;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.v4.app.FragmentActivity;
+
+import com.google.android.wearable.compat.WearableActivityController;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+
+/**
+ * Tests for {@link AmbientDelegate}.
+ */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class AmbientDelegateTest {
+
+    @Mock
+    AmbientDelegate.AmbientCallback mMockAmbientCallback;
+    @Mock
+    WearableControllerProvider mMockWearableControllerProvider;
+    @Mock
+    WearableActivityController mMockWearableController;
+    @Mock
+    FragmentActivity mMockActivity;
+
+    private AmbientDelegate mAmbientDelegateUnderTest;
+
+    @Before
+    public void setUp() {
+        mMockAmbientCallback = mock(AmbientDelegate.AmbientCallback.class);
+        mMockWearableControllerProvider = mock(WearableControllerProvider.class);
+        mMockWearableController = mock(WearableActivityController.class);
+        mMockActivity = mock(FragmentActivity.class);
+        when(mMockWearableControllerProvider
+                .getWearableController(mMockActivity, mMockAmbientCallback))
+                .thenReturn(mMockWearableController);
+    }
+
+    @Test
+    public void testNullActivity() {
+        mAmbientDelegateUnderTest = new AmbientDelegate(null,
+                mMockWearableControllerProvider, mMockAmbientCallback);
+        verifyZeroInteractions(mMockWearableControllerProvider);
+
+        assertFalse(mAmbientDelegateUnderTest.isAmbient());
+
+    }
+
+    @Test
+    public void testActivityPresent() {
+        mAmbientDelegateUnderTest = new AmbientDelegate(mMockActivity,
+                mMockWearableControllerProvider, mMockAmbientCallback);
+
+        mAmbientDelegateUnderTest.onCreate();
+        verify(mMockWearableController).onCreate();
+
+        mAmbientDelegateUnderTest.onResume();
+        verify(mMockWearableController).onResume();
+
+        mAmbientDelegateUnderTest.onPause();
+        verify(mMockWearableController).onPause();
+
+        mAmbientDelegateUnderTest.onStop();
+        verify(mMockWearableController).onStop();
+
+        mAmbientDelegateUnderTest.onDestroy();
+        verify(mMockWearableController).onDestroy();
+    }
+}
diff --git a/wear/tests/src/android/support/wear/ambient/AmbientModeTest.java b/wear/tests/src/android/support/wear/ambient/AmbientModeTest.java
new file mode 100644
index 0000000..155622d
--- /dev/null
+++ b/wear/tests/src/android/support/wear/ambient/AmbientModeTest.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.wear.ambient;
+
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
+
+import android.support.test.filters.MediumTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.wear.widget.util.WakeLockRule;
+
+import com.google.android.wearable.compat.WearableActivityController;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class AmbientModeTest {
+    @Rule
+    public final WakeLockRule mWakeLock = new WakeLockRule();
+
+    @Rule
+    public final ActivityTestRule<AmbientModeTestActivity> mActivityRule = new ActivityTestRule<>(
+            AmbientModeTestActivity.class);
+
+    @Test
+    public void testEnterAmbientCallback() throws Throwable {
+        AmbientModeTestActivity activity = mActivityRule.getActivity();
+
+        WearableActivityController.getLastInstance().enterAmbient();
+        assertTrue(activity.mEnterAmbientCalled);
+        assertFalse(activity.mUpdateAmbientCalled);
+        assertFalse(activity.mExitAmbientCalled);
+    }
+
+    @Test
+    public void testUpdateAmbientCallback() throws Throwable {
+        AmbientModeTestActivity activity = mActivityRule.getActivity();
+
+        WearableActivityController.getLastInstance().updateAmbient();
+        assertFalse(activity.mEnterAmbientCalled);
+        assertTrue(activity.mUpdateAmbientCalled);
+        assertFalse(activity.mExitAmbientCalled);
+    }
+
+    @Test
+    public void testExitAmbientCallback() throws Throwable {
+        AmbientModeTestActivity activity = mActivityRule.getActivity();
+
+        WearableActivityController.getLastInstance().exitAmbient();
+        assertFalse(activity.mEnterAmbientCalled);
+        assertFalse(activity.mUpdateAmbientCalled);
+        assertTrue(activity.mExitAmbientCalled);
+    }
+
+    @Test
+    public void testIsAmbientEnabled() {
+        assertTrue(WearableActivityController.getLastInstance().isAmbientEnabled());
+    }
+
+    @Test
+    public void testControllerSetAutoResumeEnabled() {
+        AmbientModeTestActivity activity = mActivityRule.getActivity();
+
+        activity.getAmbientController().setAutoResumeEnabled(true);
+        assertTrue(WearableActivityController.getLastInstance().isAutoResumeEnabled());
+
+        activity.getAmbientController().setAutoResumeEnabled(false);
+        assertFalse(WearableActivityController.getLastInstance().isAutoResumeEnabled());
+    }
+
+    @Test
+    public void testCallsControllerIsAmbient() {
+        AmbientModeTestActivity activity = mActivityRule.getActivity();
+
+        WearableActivityController.getLastInstance().setAmbient(true);
+        assertTrue(activity.getAmbientController().isAmbient());
+
+        WearableActivityController.getLastInstance().setAmbient(false);
+        assertFalse(activity.getAmbientController().isAmbient());
+    }
+}
diff --git a/wear/tests/src/android/support/wear/ambient/AmbientModeTestActivity.java b/wear/tests/src/android/support/wear/ambient/AmbientModeTestActivity.java
new file mode 100644
index 0000000..26155d8
--- /dev/null
+++ b/wear/tests/src/android/support/wear/ambient/AmbientModeTestActivity.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.support.wear.ambient;
+
+import android.os.Bundle;
+import android.support.v4.app.FragmentActivity;
+
+public class AmbientModeTestActivity extends FragmentActivity
+        implements AmbientMode.AmbientCallbackProvider {
+    AmbientMode.AmbientController mAmbientController;
+
+    boolean mEnterAmbientCalled;
+    boolean mUpdateAmbientCalled;
+    boolean mExitAmbientCalled;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        mAmbientController = AmbientMode.attachAmbientSupport(this);
+    }
+
+    @Override
+    public AmbientMode.AmbientCallback getAmbientCallback() {
+        return new MyAmbientCallback();
+    }
+
+    private class MyAmbientCallback extends AmbientMode.AmbientCallback {
+
+        @Override
+        public void onEnterAmbient(Bundle ambientDetails) {
+            mEnterAmbientCalled = true;
+        }
+
+        @Override
+        public void onUpdateAmbient() {
+            mUpdateAmbientCalled = true;
+        }
+
+        @Override
+        public void onExitAmbient() {
+            mExitAmbientCalled = true;
+        }
+    }
+
+    public AmbientMode.AmbientController getAmbientController() {
+        return mAmbientController;
+    }
+
+}
diff --git a/wear/tests/src/com/google/android/wearable/compat/WearableActivityController.java b/wear/tests/src/com/google/android/wearable/compat/WearableActivityController.java
new file mode 100644
index 0000000..7823f23
--- /dev/null
+++ b/wear/tests/src/com/google/android/wearable/compat/WearableActivityController.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.wearable.compat;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+/**
+ * Mock version of {@link WearableActivityController}. During instrumentation testing, the tests
+ * would end up using this instead of the version implemented on device.
+ */
+public class WearableActivityController {
+
+    private static WearableActivityController sLastInstance;
+
+    public static WearableActivityController getLastInstance() {
+        return sLastInstance;
+    }
+
+    private AmbientCallback mCallback;
+    private boolean mAmbientEnabled = false;
+    private boolean mAutoResumeEnabled = false;
+    private boolean mAmbient = false;
+
+    public WearableActivityController(String tag, Activity activity, AmbientCallback callback) {
+        sLastInstance = this;
+        mCallback = callback;
+    }
+
+    // Methods required by the stub but not currently used in tests.
+    public void onCreate() {}
+    public void onResume() {}
+    public void onPause() {}
+    public void onStop() {}
+    public void onDestroy() {}
+
+    public void enterAmbient() {
+        mCallback.onEnterAmbient(null);
+    }
+
+    public void exitAmbient() {
+        mCallback.onExitAmbient();
+    }
+
+    public void updateAmbient() {
+        mCallback.onUpdateAmbient();
+    }
+
+    public void setAmbientEnabled() {
+        mAmbientEnabled = true;
+    }
+
+    public boolean isAmbientEnabled() {
+        return mAmbientEnabled;
+    }
+
+    public void setAutoResumeEnabled(boolean enabled) {
+        mAutoResumeEnabled = enabled;
+    }
+
+    public boolean isAutoResumeEnabled() {
+        return mAutoResumeEnabled;
+    }
+
+    public final boolean isAmbient() {
+        return mAmbient;
+    }
+
+    public void setAmbient(boolean ambient) {
+        mAmbient = ambient;
+    }
+
+    /** Stub version of {@link WearableActivityController.AmbientCallback}. */
+    public static class AmbientCallback {
+        public void onEnterAmbient(Bundle ambientDetails) {}
+
+        public void onExitAmbient() {}
+
+        public void onUpdateAmbient() {}
+    }
+}
diff --git a/wear/wear_stubs/LICENSE b/wear/wear_stubs/LICENSE
new file mode 100644
index 0000000..261eeb9
--- /dev/null
+++ b/wear/wear_stubs/LICENSE
@@ -0,0 +1,201 @@
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
diff --git a/wear/wear_stubs/README.android b/wear/wear_stubs/README.android
new file mode 100644
index 0000000..5fdff39
--- /dev/null
+++ b/wear/wear_stubs/README.android
@@ -0,0 +1,10 @@
+# Wearable support system stubs from http://ab/4131273
+This library contains system stubs generated for the
+com.google.android.wearable.jar shared library. Classes in the 1st/3rd party
+accessible wearable support library are able to access these apis.
+
+See `vendor/google_clockwork/libs/wearable` in Android Git.
+
+Imports to this directory must always be done from the Android Build server.
+To test with local changes made in Android Git see the instructions at
+http://go/clockwork-dev/device-builds.
diff --git a/wear/wear_stubs/api/1.txt b/wear/wear_stubs/api/1.txt
new file mode 100644
index 0000000..af53c8e
--- /dev/null
+++ b/wear/wear_stubs/api/1.txt
@@ -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 com.google.android.wearable {
+
+  public final class WearableSharedLib {
+    method public static int version();
+  }
+
+}
+
+package com.google.android.wearable.compat {
+
+  public class WearableActivityController {
+    ctor public WearableActivityController(java.lang.String, android.app.Activity, com.google.android.wearable.compat.WearableActivityController.AmbientCallback);
+    method public void dump(java.lang.String, java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
+    method public final boolean isAmbient();
+    method public void onCreate();
+    method public void onDestroy();
+    method public void onPause();
+    method public void onResume();
+    method public void onStop();
+    method public final void setAmbientEnabled();
+    method public final void setAutoResumeEnabled(boolean);
+    field public static final java.lang.String EXTRA_BURN_IN_PROTECTION = "com.google.android.wearable.compat.extra.BURN_IN_PROTECTION";
+    field public static final java.lang.String EXTRA_LOWBIT_AMBIENT = "com.google.android.wearable.compat.extra.LOWBIT_AMBIENT";
+  }
+
+  public static abstract class WearableActivityController.AmbientCallback {
+    ctor public WearableActivityController.AmbientCallback();
+    method public void onEnterAmbient(android.os.Bundle);
+    method public void onExitAmbient();
+    method public void onUpdateAmbient();
+  }
+
+}
+
+package com.google.android.wearable.input {
+
+  public class RotaryEncoderHelper {
+    method public static float getRotaryAxisValue(android.view.MotionEvent);
+    method public static float getScaledScrollFactor(android.content.Context);
+    method public static boolean isFromRotaryEncoder(android.view.MotionEvent);
+  }
+
+  public final class WearableInputDevice {
+    method public static final int[] getAvailableButtonKeyCodes(android.content.Context);
+    method public static final android.os.Bundle getButtonInfo(android.content.Context, int);
+    field public static final java.lang.String X_KEY = "x_key";
+    field public static final java.lang.String Y_KEY = "y_key";
+  }
+
+}
+
diff --git a/wear/wear_stubs/api/2.txt b/wear/wear_stubs/api/2.txt
new file mode 100644
index 0000000..2850f24
--- /dev/null
+++ b/wear/wear_stubs/api/2.txt
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.android.wearable {
+
+  public final class WearableSharedLib {
+    method public static int version();
+  }
+
+}
+
+package com.google.android.wearable.compat {
+
+  public class WearableActivityController {
+    ctor public WearableActivityController(java.lang.String, android.app.Activity, com.google.android.wearable.compat.WearableActivityController.AmbientCallback);
+    method public void dump(java.lang.String, java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
+    method public final boolean isAmbient();
+    method public void onCreate();
+    method public void onDestroy();
+    method public void onPause();
+    method public void onResume();
+    method public void onStop();
+    method public final void setAmbientEnabled();
+    method public final void setAutoResumeEnabled(boolean);
+    field public static final java.lang.String EXTRA_BURN_IN_PROTECTION = "com.google.android.wearable.compat.extra.BURN_IN_PROTECTION";
+    field public static final java.lang.String EXTRA_LOWBIT_AMBIENT = "com.google.android.wearable.compat.extra.LOWBIT_AMBIENT";
+  }
+
+  public static abstract class WearableActivityController.AmbientCallback {
+    ctor public WearableActivityController.AmbientCallback();
+    method public void onEnterAmbient(android.os.Bundle);
+    method public void onExitAmbient();
+    method public void onUpdateAmbient();
+  }
+
+}
+
+package com.google.android.wearable.display {
+
+  public final class WearableDisplayHelper {
+    method public static final android.graphics.RectF getObstruction();
+  }
+
+}
+
+package com.google.android.wearable.input {
+
+  public class RotaryEncoderHelper {
+    method public static float getRotaryAxisValue(android.view.MotionEvent);
+    method public static float getScaledScrollFactor(android.content.Context);
+    method public static boolean isFromRotaryEncoder(android.view.MotionEvent);
+  }
+
+  public final class WearableInputDevice {
+    method public static final int[] getAvailableButtonKeyCodes(android.content.Context);
+    method public static final android.os.Bundle getButtonInfo(android.content.Context, int);
+    field public static final java.lang.String X_KEY = "x_key";
+    field public static final java.lang.String Y_KEY = "y_key";
+  }
+
+}
+
diff --git a/wear/wear_stubs/api/current.txt b/wear/wear_stubs/api/current.txt
new file mode 100644
index 0000000..2850f24
--- /dev/null
+++ b/wear/wear_stubs/api/current.txt
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.android.wearable {
+
+  public final class WearableSharedLib {
+    method public static int version();
+  }
+
+}
+
+package com.google.android.wearable.compat {
+
+  public class WearableActivityController {
+    ctor public WearableActivityController(java.lang.String, android.app.Activity, com.google.android.wearable.compat.WearableActivityController.AmbientCallback);
+    method public void dump(java.lang.String, java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
+    method public final boolean isAmbient();
+    method public void onCreate();
+    method public void onDestroy();
+    method public void onPause();
+    method public void onResume();
+    method public void onStop();
+    method public final void setAmbientEnabled();
+    method public final void setAutoResumeEnabled(boolean);
+    field public static final java.lang.String EXTRA_BURN_IN_PROTECTION = "com.google.android.wearable.compat.extra.BURN_IN_PROTECTION";
+    field public static final java.lang.String EXTRA_LOWBIT_AMBIENT = "com.google.android.wearable.compat.extra.LOWBIT_AMBIENT";
+  }
+
+  public static abstract class WearableActivityController.AmbientCallback {
+    ctor public WearableActivityController.AmbientCallback();
+    method public void onEnterAmbient(android.os.Bundle);
+    method public void onExitAmbient();
+    method public void onUpdateAmbient();
+  }
+
+}
+
+package com.google.android.wearable.display {
+
+  public final class WearableDisplayHelper {
+    method public static final android.graphics.RectF getObstruction();
+  }
+
+}
+
+package com.google.android.wearable.input {
+
+  public class RotaryEncoderHelper {
+    method public static float getRotaryAxisValue(android.view.MotionEvent);
+    method public static float getScaledScrollFactor(android.content.Context);
+    method public static boolean isFromRotaryEncoder(android.view.MotionEvent);
+  }
+
+  public final class WearableInputDevice {
+    method public static final int[] getAvailableButtonKeyCodes(android.content.Context);
+    method public static final android.os.Bundle getButtonInfo(android.content.Context, int);
+    field public static final java.lang.String X_KEY = "x_key";
+    field public static final java.lang.String Y_KEY = "y_key";
+  }
+
+}
+
diff --git a/wear/wear_stubs/com.google.android.wearable-stubs.jar b/wear/wear_stubs/com.google.android.wearable-stubs.jar
new file mode 100644
index 0000000..7465f7c
--- /dev/null
+++ b/wear/wear_stubs/com.google.android.wearable-stubs.jar
Binary files differ