Merge "Paging API refinements, and package name rework" into oc-mr1-dev
diff --git a/app-toolkit/common/api/0.0.0.txt b/app-toolkit/common/api/0.0.0.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/app-toolkit/common/api/0.0.0.txt
diff --git a/app-toolkit/common/api/1.0.0.txt b/app-toolkit/common/api/1.0.0.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/app-toolkit/common/api/1.0.0.txt
diff --git a/app-toolkit/common/build.gradle b/app-toolkit/common/build.gradle
index ff8375a..4f51a49 100644
--- a/app-toolkit/common/build.gradle
+++ b/app-toolkit/common/build.gradle
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+import android.support.LibraryVersions
 import android.support.SupportLibraryExtension;
 
 apply plugin: android.support.SupportJavaLibraryPlugin
@@ -27,6 +28,7 @@
 
 createAndroidCheckstyle(project)
 
+version = LibraryVersions.ARCH_CORE.toString()
 supportLibrary {
     name 'Android Arch-Common'
     publish true
diff --git a/app-toolkit/core-testing/build.gradle b/app-toolkit/core-testing/build.gradle
index 2e6cde6..8b86b8b 100644
--- a/app-toolkit/core-testing/build.gradle
+++ b/app-toolkit/core-testing/build.gradle
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+import android.support.LibraryVersions
 import android.support.SupportLibraryExtension
 
 apply plugin: android.support.FlatfootAndroidLibraryPlugin
@@ -64,6 +65,7 @@
     }
 }
 
+version = LibraryVersions.ARCH_CORE_TESTING.toString()
 supportLibrary {
     name 'Android Core-Testing'
     publish true
diff --git a/app-toolkit/init.gradle b/app-toolkit/init.gradle
index e476129..aeb9718 100644
--- a/app-toolkit/init.gradle
+++ b/app-toolkit/init.gradle
@@ -84,7 +84,7 @@
 def zipFlatfootDocsTask = rootProject.tasks.create(name : "createFlatfootDocsArchive", type : Zip) {
     from rootProject.docsDir
     destinationDir distDir
-    baseName = String.format("flatfoot-docs-%s", LibraryVersions.FLATFOOT.toString())
+    baseName = "flatfoot-docs"
 }
 
 buildServerAnchorTask.dependsOn zipFlatfootDocsTask
@@ -110,16 +110,17 @@
         return
     }
 
-    def mavenGroup = project.getPath().split(":")[1]
+    def projectPath = project.getPath().split(":")
+    def mavenGroup = projectPath[1]
     def finalGroup = rootProject.flatfootProjectGroups[mavenGroup]
 
     if (finalGroup == null) {
         return
     }
-    project.group = finalGroup
-    if (!project.version) {
-        project.version = LibraryVersions.FLATFOOT.toString()
+    if (projectPath.size() == 2) {// root project.
+        return
     }
+    project.group = finalGroup
 
     if (project.getPath().contains("integration-tests")) {
         // disable upload tasks
@@ -128,6 +129,21 @@
                 task.enabled = false
             }
         }
+    } else {
+        def checkApi = project.tasks.create("checkVersion") {
+            doFirst {
+                if (project.version == null
+                        || project.version == LibraryVersions.SUPPORT_LIBRARY.toString()) {
+                    throw new GradleException("bad version for $project with $project.version")
+                }
+            }
+        }
+
+        project.tasks.whenTaskAdded { task ->
+            if (task instanceof Upload) {
+                task.dependsOn checkApi
+            }
+        }
     }
 
     project.plugins.whenPluginAdded { plugin ->
diff --git a/app-toolkit/runtime/build.gradle b/app-toolkit/runtime/build.gradle
index efb7b50..434d42b 100644
--- a/app-toolkit/runtime/build.gradle
+++ b/app-toolkit/runtime/build.gradle
@@ -15,6 +15,7 @@
  */
 
 import android.support.SupportLibraryExtension
+import android.support.LibraryVersions
 
 apply plugin: android.support.FlatfootAndroidLibraryPlugin
 
@@ -55,6 +56,7 @@
     }
 }
 
+version = LibraryVersions.ARCH_RUNTIME.toString()
 supportLibrary {
     name 'Android Arch-Runtime'
     publish true
diff --git a/buildSrc/src/main/java/android/support/LibraryVersions.java b/buildSrc/src/main/java/android/support/LibraryVersions.java
index 6795488..32c9313 100644
--- a/buildSrc/src/main/java/android/support/LibraryVersions.java
+++ b/buildSrc/src/main/java/android/support/LibraryVersions.java
@@ -26,12 +26,47 @@
     public static final Version SUPPORT_LIBRARY = new Version("27.0.0-SNAPSHOT");
 
     /**
-     * Version code of the flatfoot libraries.
+     * Version code for flatfoot 1.0 projects (room, lifecycles)
      */
-    public static final Version FLATFOOT = new Version("1.0.0-alpha9");
+    private static final Version FLATFOOT_1_0_BATCH = new Version("1.0.0-alpha10");
 
     /**
-     * Version code of the lifecycles library.
+     * Version code for Room
      */
-    public static final Version LIFECYCLES = new Version("1.0.0-SNAPSHOT");
+    public static final Version ROOM = FLATFOOT_1_0_BATCH;
+
+    /**
+     * Version code for Lifecycle extensions (live data, view model etc)
+     */
+    public static final Version LIFECYCLES_EXT = FLATFOOT_1_0_BATCH;
+
+    /**
+     * Version code for RecyclerView & Room paging
+     */
+    public static final Version PAGING = new Version("1.0.0-alpha1");
+
+    /**
+     * Version code for Lifecycle libs that are required by the support library
+     */
+    public static final Version LIFECYCLES_CORE = new Version("1.0.0");
+
+    /**
+     * Version code for Lifecycle runtime libs that are required by the support library
+     */
+    public static final Version LIFECYCLES_RUNTIME = new Version("1.0.0");
+
+    /**
+     * Version code for shared code of flatfoot
+     */
+    public static final Version ARCH_CORE = new Version("1.0.0");
+
+    /**
+     * Version code for shared code of flatfoot runtime
+     */
+    public static final Version ARCH_RUNTIME = FLATFOOT_1_0_BATCH;
+
+    /**
+     * Version code for shared testing code of flatfoot
+     */
+    public static final Version ARCH_CORE_TESTING = FLATFOOT_1_0_BATCH;
 }
diff --git a/compat/api/current.txt b/compat/api/current.txt
index 2d83433..8dea70f 100644
--- a/compat/api/current.txt
+++ b/compat/api/current.txt
@@ -1578,6 +1578,7 @@
     method public static float getElevation(android.view.View);
     method public static boolean getFitsSystemWindows(android.view.View);
     method public static int getImportantForAccessibility(android.view.View);
+    method public static int getImportantForAutofill(android.view.View);
     method public static int getLabelFor(android.view.View);
     method public static deprecated int getLayerType(android.view.View);
     method public static int getLayoutDirection(android.view.View);
@@ -1618,6 +1619,7 @@
     method public static boolean isAttachedToWindow(android.view.View);
     method public static boolean isFocusedByDefault(android.view.View);
     method public static boolean isImportantForAccessibility(android.view.View);
+    method public static boolean isImportantForAutofill(android.view.View);
     method public static boolean isInLayout(android.view.View);
     method public static boolean isKeyboardNavigationCluster(android.view.View);
     method public static boolean isLaidOut(android.view.View);
@@ -1645,6 +1647,7 @@
     method public static void setAccessibilityLiveRegion(android.view.View, int);
     method public static deprecated void setActivated(android.view.View, boolean);
     method public static deprecated void setAlpha(android.view.View, float);
+    method public static void setAutofillHints(android.view.View, java.lang.String...);
     method public static void setBackground(android.view.View, android.graphics.drawable.Drawable);
     method public static void setBackgroundTintList(android.view.View, android.content.res.ColorStateList);
     method public static void setBackgroundTintMode(android.view.View, android.graphics.PorterDuff.Mode);
@@ -1655,6 +1658,7 @@
     method public static void setFocusedByDefault(android.view.View, boolean);
     method public static void setHasTransientState(android.view.View, boolean);
     method public static void setImportantForAccessibility(android.view.View, int);
+    method public static void setImportantForAutofill(android.view.View, int);
     method public static void setKeyboardNavigationCluster(android.view.View, boolean);
     method public static void setLabelFor(android.view.View, int);
     method public static void setLayerPaint(android.view.View, android.graphics.Paint);
diff --git a/compat/java/android/support/v4/view/ViewCompat.java b/compat/java/android/support/v4/view/ViewCompat.java
index 9a66cec..e7443d7 100644
--- a/compat/java/android/support/v4/view/ViewCompat.java
+++ b/compat/java/android/support/v4/view/ViewCompat.java
@@ -19,6 +19,7 @@
 import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
 
 import android.animation.ValueAnimator;
+import android.annotation.TargetApi;
 import android.content.ClipData;
 import android.content.Context;
 import android.content.res.ColorStateList;
@@ -115,6 +116,17 @@
     @Deprecated
     public static final int OVER_SCROLL_NEVER = 2;
 
+    @TargetApi(Build.VERSION_CODES.O)
+    @IntDef({
+            View.IMPORTANT_FOR_AUTOFILL_AUTO,
+            View.IMPORTANT_FOR_AUTOFILL_YES,
+            View.IMPORTANT_FOR_AUTOFILL_NO,
+            View.IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS,
+            View.IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    private @interface AutofillImportance {}
+
     @IntDef({
             IMPORTANT_FOR_ACCESSIBILITY_AUTO,
             IMPORTANT_FOR_ACCESSIBILITY_YES,
@@ -439,6 +451,10 @@
         static Field sAccessibilityDelegateField;
         static boolean sAccessibilityDelegateCheckFailed = false;
 
+        public void setAutofillHints(@NonNull View v, @Nullable String... autofillHints) {
+            // no-op
+        }
+
         public void setAccessibilityDelegate(View v,
                 @Nullable AccessibilityDelegateCompat delegate) {
             v.setAccessibilityDelegate(delegate == null ? null : delegate.getBridge());
@@ -991,6 +1007,19 @@
         public boolean hasExplicitFocusable(@NonNull View view) {
             return view.hasFocusable();
         }
+
+        @TargetApi(Build.VERSION_CODES.O)
+        public @AutofillImportance int getImportantForAutofill(@NonNull View v) {
+            return View.IMPORTANT_FOR_AUTOFILL_AUTO;
+        }
+
+        public void setImportantForAutofill(@NonNull View v, @AutofillImportance int mode) {
+            // no-op
+        }
+
+        public boolean isImportantForAutofill(@NonNull View v) {
+            return true;
+        }
     }
 
     @RequiresApi(15)
@@ -1523,6 +1552,27 @@
 
     @RequiresApi(26)
     static class ViewCompatApi26Impl extends ViewCompatApi24Impl {
+
+        @Override
+        public void setAutofillHints(@NonNull View v, @Nullable String... autofillHints) {
+            v.setAutofillHints(autofillHints);
+        }
+
+        @Override
+        public @AutofillImportance int getImportantForAutofill(@NonNull View v) {
+            return v.getImportantForAutofill();
+        }
+
+        @Override
+        public void setImportantForAutofill(@NonNull View v, @AutofillImportance int mode) {
+            v.setImportantForAutofill(mode);
+        }
+
+        @Override
+        public boolean isImportantForAutofill(@NonNull View v) {
+            return v.isImportantForAutofill();
+        }
+
         @Override
         public void setTooltipText(View view, CharSequence tooltipText) {
             view.setTooltipText(tooltipText);
@@ -1799,6 +1849,165 @@
     }
 
     /**
+     * Sets the hints that help an {@link android.service.autofill.AutofillService} determine how
+     * to autofill the view with the user's data.
+     *
+     * <p>Typically, there is only one way to autofill a view, but there could be more than one.
+     * For example, if the application accepts either an username or email address to identify
+     * an user.
+     *
+     * <p>These hints are not validated by the Android System, but passed "as is" to the service.
+     * Hence, they can have any value, but it's recommended to use the {@code AUTOFILL_HINT_}
+     * constants such as:
+     * {@link View#AUTOFILL_HINT_USERNAME}, {@link View#AUTOFILL_HINT_PASSWORD},
+     * {@link View#AUTOFILL_HINT_EMAIL_ADDRESS},
+     * {@link View#AUTOFILL_HINT_NAME},
+     * {@link View#AUTOFILL_HINT_PHONE},
+     * {@link View#AUTOFILL_HINT_POSTAL_ADDRESS}, {@link View#AUTOFILL_HINT_POSTAL_CODE},
+     * {@link View#AUTOFILL_HINT_CREDIT_CARD_NUMBER},
+     * {@link View#AUTOFILL_HINT_CREDIT_CARD_SECURITY_CODE},
+     * {@link View#AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DATE},
+     * {@link View#AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DAY},
+     * {@link View#AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_MONTH} or
+     * {@link View#AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_YEAR}.
+     *
+     * <p>This method is only supported on API >= 26.
+     * On API 25 and below, it is a no-op</p>
+     *
+     * @param autofillHints The autofill hints to set. If the array is emtpy, {@code null} is set.
+     * @attr ref android.R.styleable#View_autofillHints
+     */
+    public static void setAutofillHints(@NonNull View v, @Nullable String... autofillHints) {
+        IMPL.setAutofillHints(v, autofillHints);
+    }
+
+    /**
+     * Gets the mode for determining whether this view is important for autofill.
+     *
+     * <p>See {@link #setImportantForAutofill(View, int)} and {@link #isImportantForAutofill(View)}
+     * for more info about this mode.
+     *
+     * <p>This method is only supported on API >= 26.
+     * On API 25 and below, it will always return {@link View#IMPORTANT_FOR_AUTOFILL_AUTO}.</p>
+     *
+     * @return {@link View#IMPORTANT_FOR_AUTOFILL_AUTO} by default, or value passed to
+     * {@link #setImportantForAutofill(View, int)}.
+     *
+     * @attr ref android.R.styleable#View_importantForAutofill
+     */
+    public static @AutofillImportance int getImportantForAutofill(@NonNull View v) {
+        return IMPL.getImportantForAutofill(v);
+    }
+
+    /**
+     * Sets the mode for determining whether this view is considered important for autofill.
+     *
+     * <p>The platform determines the importance for autofill automatically but you
+     * can use this method to customize the behavior. For example:
+     *
+     * <ol>
+     *   <li>When the view contents is irrelevant for autofill (for example, a text field used in a
+     *       "Captcha" challenge), it should be {@link View#IMPORTANT_FOR_AUTOFILL_NO}.
+     *   <li>When both the view and its children are irrelevant for autofill (for example, the root
+     *       view of an activity containing a spreadhseet editor), it should be
+     *       {@link View#IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS}.
+     *   <li>When the view content is relevant for autofill but its children aren't (for example,
+     *       a credit card expiration date represented by a custom view that overrides the proper
+     *       autofill methods and has 2 children representing the month and year), it should
+     *       be {@link View#IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS}.
+     * </ol>
+     *
+     * <p><b>NOTE:</strong> setting the mode as does {@link View#IMPORTANT_FOR_AUTOFILL_NO} or
+     * {@link View#IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS} does not guarantee the view (and
+     * its children) will be always be considered not important; for example, when the user
+     * explicitly makes an autofill request, all views are considered important. See
+     * {@link #isImportantForAutofill(View)} for more details about how the View's importance for
+     * autofill is used.
+     *
+     * <p>This method is only supported on API >= 26.
+     * On API 25 and below, it is a no-op</p>
+     *
+     *
+     * @param mode {@link View#IMPORTANT_FOR_AUTOFILL_AUTO},
+     * {@link View#IMPORTANT_FOR_AUTOFILL_YES},
+     * {@link View#IMPORTANT_FOR_AUTOFILL_NO},
+     * {@link View#IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS},
+     * or {@link View#IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS}.
+     *
+     * @attr ref android.R.styleable#View_importantForAutofill
+     */
+    public static void setImportantForAutofill(@NonNull View v, @AutofillImportance int mode) {
+        IMPL.setImportantForAutofill(v, mode);
+    }
+
+    /**
+     * Hints the Android System whether the {@link android.app.assist.AssistStructure.ViewNode}
+     * associated with this view is considered important for autofill purposes.
+     *
+     * <p>Generally speaking, a view is important for autofill if:
+     * <ol>
+     * <li>The view can be autofilled by an {@link android.service.autofill.AutofillService}.
+     * <li>The view contents can help an {@link android.service.autofill.AutofillService}
+     *     determine how other views can be autofilled.
+     * <ol>
+     *
+     * <p>For example, view containers should typically return {@code false} for performance reasons
+     * (since the important info is provided by their children), but if its properties have relevant
+     * information (for example, a resource id called {@code credentials}, it should return
+     * {@code true}. On the other hand, views representing labels or editable fields should
+     * typically return {@code true}, but in some cases they could return {@code false}
+     * (for example, if they're part of a "Captcha" mechanism).
+     *
+     * <p>The value returned by this method depends on the value returned by
+     * {@link #getImportantForAutofill(View)}:
+     *
+     * <ol>
+     *   <li>if it returns {@link View#IMPORTANT_FOR_AUTOFILL_YES} or
+     *       {@link View#IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS},
+     *       then it returns {@code true}
+     *   <li>if it returns {@link View#IMPORTANT_FOR_AUTOFILL_NO} or
+     *       {@link View#IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS},
+     *       then it returns {@code false}
+     *   <li>if it returns {@link View#IMPORTANT_FOR_AUTOFILL_AUTO},
+     *   then it uses some simple heuristics that can return {@code true}
+     *   in some cases (like a container with a resource id), but {@code false} in most.
+     *   <li>otherwise, it returns {@code false}.
+     * </ol>
+     *
+     * <p>When a view is considered important for autofill:
+     * <ul>
+     *   <li>The view might automatically trigger an autofill request when focused on.
+     *   <li>The contents of the view are included in the {@link android.view.ViewStructure}
+     *   used in an autofill request.
+     * </ul>
+     *
+     * <p>On the other hand, when a view is considered not important for autofill:
+     * <ul>
+     *   <li>The view never automatically triggers autofill requests, but it can trigger a manual
+     *       request through {@link android.view.autofill.AutofillManager#requestAutofill(View)}.
+     *   <li>The contents of the view are not included in the {@link android.view.ViewStructure}
+     *   used in an autofill request, unless the request has the
+     *       {@link View#AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS} flag.
+     * </ul>
+     *
+     * <p>This method is only supported on API >= 26.
+     * On API 25 and below, it will always return {@code true}.</p>
+     *
+     * @return whether the view is considered important for autofill.
+     *
+     * @see #setImportantForAutofill(View, int)
+     * @see View#IMPORTANT_FOR_AUTOFILL_AUTO
+     * @see View#IMPORTANT_FOR_AUTOFILL_YES
+     * @see View#IMPORTANT_FOR_AUTOFILL_NO
+     * @see View#IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS
+     * @see View#IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS
+     * @see android.view.autofill.AutofillManager#requestAutofill(View)
+     */
+    public static boolean isImportantForAutofill(@NonNull View v) {
+        return IMPL.isImportantForAutofill(v);
+    }
+
+    /**
      * Checks whether provided View has an accessibility delegate attached to it.
      *
      * @param v The View instance to check
diff --git a/lifecycle/common/api/1.0.0.txt b/lifecycle/common/api/1.0.0.txt
new file mode 100644
index 0000000..151db2b
--- /dev/null
+++ b/lifecycle/common/api/1.0.0.txt
@@ -0,0 +1,44 @@
+package android.arch.lifecycle {
+
+  public abstract class Lifecycle {
+    ctor public Lifecycle();
+    method public abstract void addObserver(android.arch.lifecycle.LifecycleObserver);
+    method public abstract android.arch.lifecycle.Lifecycle.State getCurrentState();
+    method public abstract void removeObserver(android.arch.lifecycle.LifecycleObserver);
+  }
+
+  public static final class Lifecycle.Event extends java.lang.Enum {
+    method public static android.arch.lifecycle.Lifecycle.Event valueOf(java.lang.String);
+    method public static final android.arch.lifecycle.Lifecycle.Event[] values();
+    enum_constant public static final android.arch.lifecycle.Lifecycle.Event ON_ANY;
+    enum_constant public static final android.arch.lifecycle.Lifecycle.Event ON_CREATE;
+    enum_constant public static final android.arch.lifecycle.Lifecycle.Event ON_DESTROY;
+    enum_constant public static final android.arch.lifecycle.Lifecycle.Event ON_PAUSE;
+    enum_constant public static final android.arch.lifecycle.Lifecycle.Event ON_RESUME;
+    enum_constant public static final android.arch.lifecycle.Lifecycle.Event ON_START;
+    enum_constant public static final android.arch.lifecycle.Lifecycle.Event ON_STOP;
+  }
+
+  public static final class Lifecycle.State extends java.lang.Enum {
+    method public boolean isAtLeast(android.arch.lifecycle.Lifecycle.State);
+    method public static android.arch.lifecycle.Lifecycle.State valueOf(java.lang.String);
+    method public static final android.arch.lifecycle.Lifecycle.State[] values();
+    enum_constant public static final android.arch.lifecycle.Lifecycle.State CREATED;
+    enum_constant public static final android.arch.lifecycle.Lifecycle.State DESTROYED;
+    enum_constant public static final android.arch.lifecycle.Lifecycle.State INITIALIZED;
+    enum_constant public static final android.arch.lifecycle.Lifecycle.State RESUMED;
+    enum_constant public static final android.arch.lifecycle.Lifecycle.State STARTED;
+  }
+
+  public abstract interface LifecycleObserver {
+  }
+
+  public abstract interface LifecycleOwner {
+    method public abstract android.arch.lifecycle.Lifecycle getLifecycle();
+  }
+
+  public abstract class OnLifecycleEvent implements java.lang.annotation.Annotation {
+  }
+
+}
+
diff --git a/lifecycle/common/build.gradle b/lifecycle/common/build.gradle
index f9b8513..57cfd00 100644
--- a/lifecycle/common/build.gradle
+++ b/lifecycle/common/build.gradle
@@ -26,8 +26,8 @@
 }
 
 createAndroidCheckstyle(project)
-version = LibraryVersions.LIFECYCLES.toString()
 
+version = LibraryVersions.LIFECYCLES_CORE.toString()
 supportLibrary {
     name 'Android Lifecycle-Common'
     publish true
diff --git a/lifecycle/compiler/build.gradle b/lifecycle/compiler/build.gradle
index 5d3dfdf..b1477f5 100644
--- a/lifecycle/compiler/build.gradle
+++ b/lifecycle/compiler/build.gradle
@@ -1,3 +1,5 @@
+import android.support.LibraryVersions
+
 apply plugin: 'kotlin'
 apply plugin: 'maven'
 apply plugin: 'checkstyle'
@@ -23,4 +25,5 @@
     testCompile files(org.gradle.internal.jvm.Jvm.current().getToolsJar())
 }
 
+version = LibraryVersions.LIFECYCLES_EXT.toString()
 createKotlinCheckstyle(project)
diff --git a/lifecycle/extensions/build.gradle b/lifecycle/extensions/build.gradle
index b3530ea..71c90ef 100644
--- a/lifecycle/extensions/build.gradle
+++ b/lifecycle/extensions/build.gradle
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+import android.support.LibraryVersions
 import android.support.SupportLibraryExtension
 
 apply plugin: android.support.FlatfootAndroidLibraryPlugin
@@ -55,6 +56,7 @@
 
 createAndroidCheckstyle(project)
 
+version = LibraryVersions.LIFECYCLES_EXT.toString()
 supportLibrary {
     name 'Android Lifecycle Extensions'
     publish true
diff --git a/lifecycle/reactivestreams/build.gradle b/lifecycle/reactivestreams/build.gradle
index 2f05cab..f973e0e 100644
--- a/lifecycle/reactivestreams/build.gradle
+++ b/lifecycle/reactivestreams/build.gradle
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+import android.support.LibraryVersions
 import android.support.SupportLibraryExtension
 
 apply plugin: android.support.FlatfootAndroidLibraryPlugin
@@ -55,6 +56,7 @@
 
 createAndroidCheckstyle(project)
 
+version = LibraryVersions.LIFECYCLES_EXT.toString()
 supportLibrary {
     name 'Android Lifecycle Reactivestreams'
     publish true
diff --git a/lifecycle/runtime/api/1.0.0.txt b/lifecycle/runtime/api/1.0.0.txt
new file mode 100644
index 0000000..93a55fc
--- /dev/null
+++ b/lifecycle/runtime/api/1.0.0.txt
@@ -0,0 +1,18 @@
+package android.arch.lifecycle {
+
+  public class LifecycleRegistry extends android.arch.lifecycle.Lifecycle {
+    ctor public LifecycleRegistry(android.arch.lifecycle.LifecycleOwner);
+    method public void addObserver(android.arch.lifecycle.LifecycleObserver);
+    method public android.arch.lifecycle.Lifecycle.State getCurrentState();
+    method public int getObserverCount();
+    method public void handleLifecycleEvent(android.arch.lifecycle.Lifecycle.Event);
+    method public void markState(android.arch.lifecycle.Lifecycle.State);
+    method public void removeObserver(android.arch.lifecycle.LifecycleObserver);
+  }
+
+  public abstract interface LifecycleRegistryOwner implements android.arch.lifecycle.LifecycleOwner {
+    method public abstract android.arch.lifecycle.LifecycleRegistry getLifecycle();
+  }
+
+}
+
diff --git a/lifecycle/runtime/build.gradle b/lifecycle/runtime/build.gradle
index 3280425..7678e95 100644
--- a/lifecycle/runtime/build.gradle
+++ b/lifecycle/runtime/build.gradle
@@ -35,8 +35,8 @@
 }
 
 createAndroidCheckstyle(project)
-version = LibraryVersions.LIFECYCLES.toString()
 
+version = LibraryVersions.LIFECYCLES_RUNTIME.toString()
 supportLibrary {
     name 'Android Lifecycle Runtime'
     publish true
diff --git a/paging/common/build.gradle b/paging/common/build.gradle
index d627c90..a1945dd 100644
--- a/paging/common/build.gradle
+++ b/paging/common/build.gradle
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+import android.support.LibraryVersions
 import android.support.SupportLibraryExtension;
 
 apply plugin: android.support.SupportJavaLibraryPlugin
@@ -37,6 +38,7 @@
 createAndroidCheckstyle(project)
 createKotlinCheckstyle(project)
 
+version = LibraryVersions.PAGING.toString()
 supportLibrary {
     name 'Android Paging-Common'
     publish false
diff --git a/paging/runtime/build.gradle b/paging/runtime/build.gradle
index 84d558d..8dad089 100644
--- a/paging/runtime/build.gradle
+++ b/paging/runtime/build.gradle
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+import android.support.LibraryVersions
 import android.support.SupportLibraryExtension
 
 apply plugin: android.support.FlatfootAndroidLibraryPlugin
@@ -66,6 +67,7 @@
     }
 }
 
+version = LibraryVersions.PAGING.toString()
 supportLibrary {
     name 'Android Lifecycle Extensions'
     publish false
diff --git a/room/common/build.gradle b/room/common/build.gradle
index 7c2bd1b..4336583 100644
--- a/room/common/build.gradle
+++ b/room/common/build.gradle
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+import android.support.LibraryVersions
 import android.support.SupportLibraryExtension;
 
 apply plugin: android.support.SupportJavaLibraryPlugin
@@ -26,6 +27,7 @@
 
 createAndroidCheckstyle(project)
 
+version = LibraryVersions.ROOM.toString()
 supportLibrary {
     name 'Android Room-Common'
     publish true
diff --git a/room/compiler/build.gradle b/room/compiler/build.gradle
index bce93f4..8934f88 100644
--- a/room/compiler/build.gradle
+++ b/room/compiler/build.gradle
@@ -1,3 +1,5 @@
+import android.support.LibraryVersions
+
 /*
  * Copyright (C) 2016 The Android Open Source Project
  *
@@ -24,6 +26,7 @@
     main.java.srcDirs += antlrOut
 }
 project.ext.noDocs = true
+version = LibraryVersions.ROOM.toString()
 
 // Temporary hack to stop AS to adding two guavas into test's classpath
 configurations.all {
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 1e0963b..7b9e0b9 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
@@ -29,7 +29,7 @@
 
 object ProcessorErrors {
     private fun String.trim(): String {
-        return this.trimIndent().replace(System.lineSeparator(), " ")
+        return this.trimIndent().replace("\n", " ")
     }
     val MISSING_QUERY_ANNOTATION = "Query methods must be annotated with ${Query::class.java}"
     val MISSING_INSERT_ANNOTATION = "Insertion methods must be annotated with ${Insert::class.java}"
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 60adf2b..69f16f3 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
@@ -33,7 +33,7 @@
         return """
             CREATE $uniqueSQL INDEX `$name`
             ON `$tableName` (${fields.map { it.columnName }.joinToString(", ") { "`$it`"}})
-            """.trimIndent().replace(System.lineSeparator(), " ")
+            """.trimIndent().replace("\n", " ")
     }
 
     val columnNames by lazy { fields.map {it.columnName} }
diff --git a/room/db-impl/build.gradle b/room/db-impl/build.gradle
index 56df267..a5da1f1 100644
--- a/room/db-impl/build.gradle
+++ b/room/db-impl/build.gradle
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+import android.support.LibraryVersions
 import android.support.SupportLibraryExtension
 
 apply plugin: android.support.FlatfootAndroidLibraryPlugin
@@ -55,6 +56,7 @@
     }
 }
 
+version = LibraryVersions.ROOM.toString()
 supportLibrary {
     name 'Android DB-Impl'
     publish true
diff --git a/room/db/build.gradle b/room/db/build.gradle
index 5fe3a1d..4757a79 100644
--- a/room/db/build.gradle
+++ b/room/db/build.gradle
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+import android.support.LibraryVersions
 import android.support.SupportLibraryExtension
 
 apply plugin: android.support.FlatfootAndroidLibraryPlugin
@@ -54,6 +55,7 @@
     }
 }
 
+version = LibraryVersions.ROOM.toString()
 supportLibrary {
     name 'Android DB'
     publish true
diff --git a/room/migration/build.gradle b/room/migration/build.gradle
index 1aebefb..45785ef 100644
--- a/room/migration/build.gradle
+++ b/room/migration/build.gradle
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+import android.support.LibraryVersions
 import android.support.SupportLibraryExtension;
 
 apply plugin: android.support.SupportJavaLibraryPlugin
@@ -31,6 +32,7 @@
     testCompile libs.mockito_core
 }
 
+version = LibraryVersions.ROOM.toString()
 supportLibrary {
     name 'Android Room Migration'
     publish true
diff --git a/room/runtime/build.gradle b/room/runtime/build.gradle
index fa00e78..18fa660 100644
--- a/room/runtime/build.gradle
+++ b/room/runtime/build.gradle
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+import android.support.LibraryVersions
 import android.support.SupportLibraryExtension
 
 apply plugin: android.support.FlatfootAndroidLibraryPlugin
@@ -75,6 +76,7 @@
     }
 }
 
+version = LibraryVersions.ROOM.toString()
 supportLibrary {
     name 'Android Room-Runtime'
     publish true
diff --git a/room/rxjava2/build.gradle b/room/rxjava2/build.gradle
index 0b6a499..d35e7d5 100644
--- a/room/rxjava2/build.gradle
+++ b/room/rxjava2/build.gradle
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+import android.support.LibraryVersions
 import android.support.SupportLibraryExtension
 
 apply plugin: android.support.FlatfootAndroidLibraryPlugin
@@ -68,6 +69,7 @@
     }
 }
 
+version = LibraryVersions.ROOM.toString()
 supportLibrary {
     name 'Android Room RXJava2'
     publish true
diff --git a/room/testing/build.gradle b/room/testing/build.gradle
index e0264f2..ad25e64 100644
--- a/room/testing/build.gradle
+++ b/room/testing/build.gradle
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+import android.support.LibraryVersions
 import android.support.SupportLibraryExtension
 
 apply plugin: android.support.FlatfootAndroidLibraryPlugin
@@ -61,6 +62,7 @@
     }
 }
 
+version = LibraryVersions.ROOM.toString()
 supportLibrary {
     name 'Android Room Testimg'
     publish true
diff --git a/samples/SupportLeanbackDemos/src/com/example/android/leanback/GuidedStepSupportActivity.java b/samples/SupportLeanbackDemos/src/com/example/android/leanback/GuidedStepSupportActivity.java
index 717fccd..c0f9361 100644
--- a/samples/SupportLeanbackDemos/src/com/example/android/leanback/GuidedStepSupportActivity.java
+++ b/samples/SupportLeanbackDemos/src/com/example/android/leanback/GuidedStepSupportActivity.java
@@ -546,8 +546,10 @@
 
         @Override
         public void onCreateActions(List<GuidedAction> actions, Bundle savedInstanceState) {
-            String desc = "The description can be quite long as well.  " +
-                    "Just be sure to set multilineDescription to true in the GuidedAction.";
+            String desc = "The description can be quite long as well.  "
+                    + "Just be sure to set multilineDescription to true in the GuidedAction."
+                    + "For testing purpose we make this line even longer since "
+                    + "multilineDescriptionMinLines will be set to 2.";
             actions.add(new GuidedAction.Builder(getActivity())
                     .title("Note that Guided Actions can have titles that are quite long.")
                     .description(desc)
diff --git a/samples/SupportLeanbackDemos/src/com/example/android/leanback/PhotoItem.java b/samples/SupportLeanbackDemos/src/com/example/android/leanback/PhotoItem.java
index adde7d3..c839560 100644
--- a/samples/SupportLeanbackDemos/src/com/example/android/leanback/PhotoItem.java
+++ b/samples/SupportLeanbackDemos/src/com/example/android/leanback/PhotoItem.java
@@ -17,7 +17,7 @@
 import android.os.Parcelable;
 
 public class PhotoItem implements Parcelable {
-
+    private int mId;
     private String mTitle;
     private String mContent;
     private int mImageResourceId;
@@ -26,10 +26,22 @@
         this(title, null, imageResourceId);
     }
 
+    public PhotoItem(String title, int imageResourceId, int id) {
+        this(title, imageResourceId);
+        mId = id;
+    }
+
     public PhotoItem(String title, String content, int imageResourceId) {
         mTitle = title;
         mContent = content;
         mImageResourceId = imageResourceId;
+        // the id was set to -1 if user don't provide this parameter
+        mId = -1;
+    }
+
+    public PhotoItem(String title, String content, int imageResourceId, int id) {
+        this(title, content, imageResourceId);
+        mId = id;
     }
 
     public int getImageResourceId() {
@@ -73,8 +85,34 @@
         }
     };
 
+    public int getId() {
+        return this.mId;
+    }
+
     private PhotoItem(Parcel in) {
         mTitle = in.readString();
         mImageResourceId = in.readInt();
     }
-}
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+        PhotoItem photoItem = (PhotoItem) o;
+        if (mId != photoItem.mId) return false;
+        if (mImageResourceId != photoItem.mImageResourceId) return false;
+        if (mTitle != null ? !mTitle.equals(photoItem.mTitle) : photoItem.mTitle != null) {
+            return false;
+        }
+        return mContent != null ? mContent.equals(photoItem.mContent) : photoItem.mContent == null;
+    }
+
+    @Override
+    public int hashCode() {
+        int result = mId;
+        result = 31 * result + (mTitle != null ? mTitle.hashCode() : 0);
+        result = 31 * result + (mContent != null ? mContent.hashCode() : 0);
+        result = 31 * result + mImageResourceId;
+        return result;
+    }
+}
\ No newline at end of file
diff --git a/samples/SupportLeanbackDemos/src/com/example/android/leanback/SampleVideoSupportFragment.java b/samples/SupportLeanbackDemos/src/com/example/android/leanback/SampleVideoSupportFragment.java
index 5891560..4af3ef7 100644
--- a/samples/SupportLeanbackDemos/src/com/example/android/leanback/SampleVideoSupportFragment.java
+++ b/samples/SupportLeanbackDemos/src/com/example/android/leanback/SampleVideoSupportFragment.java
@@ -50,7 +50,7 @@
 public class SampleVideoSupportFragment extends android.support.v17.leanback.app.VideoSupportFragment {
 
     // Media Session Token
-    private static final String MEDIA_SESSION_COMPAT_TOKEN = "media session video";
+    private static final String MEDIA_SESSION_COMPAT_TOKEN = "media session support video";
 
     private PlaybackTransportControlGlueSample<MediaPlayerAdapter> mMediaPlayerGlue;
 
@@ -158,7 +158,7 @@
         mMediaPlayerGlue = new PlaybackTransportControlGlueSample(getActivity(),
                 new MediaPlayerAdapter(getActivity()));
 
-        // If the glue is switched, re-register the mediasession
+        // If the glue is switched, re-register the media session
         mMediaPlayerGlue.connectToMediaSession(mMediaSessionCompat);
 
         mMediaPlayerGlue.setMode(PlaybackControlsRow.RepeatAction.INDEX_ONE);
diff --git a/samples/SupportLeanbackDemos/src/com/example/android/leanback/SearchFragment.java b/samples/SupportLeanbackDemos/src/com/example/android/leanback/SearchFragment.java
index 7152bae..0c9cb7f 100644
--- a/samples/SupportLeanbackDemos/src/com/example/android/leanback/SearchFragment.java
+++ b/samples/SupportLeanbackDemos/src/com/example/android/leanback/SearchFragment.java
@@ -5,6 +5,7 @@
 import android.os.Bundle;
 import android.os.Handler;
 import android.support.v17.leanback.widget.ArrayObjectAdapter;
+import android.support.v17.leanback.widget.DiffCallback;
 import android.support.v17.leanback.widget.HeaderItem;
 import android.support.v17.leanback.widget.ImageCardView;
 import android.support.v17.leanback.widget.ListRow;
@@ -19,8 +20,10 @@
 import android.text.TextUtils;
 import android.util.Log;
 
+import java.util.ArrayList;
+
 public class SearchFragment extends android.support.v17.leanback.app.SearchFragment
-    implements android.support.v17.leanback.app.SearchFragment.SearchResultProvider {
+        implements android.support.v17.leanback.app.SearchFragment.SearchResultProvider {
     private static final String TAG = "leanback.SearchFragment";
     private static final int NUM_ROWS = 3;
     private static final int SEARCH_DELAY_MS = 1000;
@@ -29,6 +32,31 @@
     private Handler mHandler = new Handler();
     private String mQuery;
 
+    // Flag to represent if data set one is presented in the fragment
+    private boolean mIsDataSetOnePresented;
+
+    // Adapter for first row
+    private ArrayObjectAdapter mFirstRowAdapter;
+
+    // The diff callback which defines the standard to judge if two items are the same or if
+    // two items have the same content.
+    private DiffCallback<PhotoItem> mDiffCallback = new DiffCallback<PhotoItem>() {
+
+        // when two photo items have the same id, they are the same from adapter's
+        // perspective
+        @Override
+        public boolean areItemsTheSame(PhotoItem oldItem, PhotoItem newItem) {
+            return oldItem.getId() == newItem.getId();
+        }
+
+        // when two photo items is equal to each other (based on the equal method defined in
+        // PhotoItem), they have the same content.
+        @Override
+        public boolean areContentsTheSame(PhotoItem oldItem, PhotoItem newItem) {
+            return oldItem.equals(newItem);
+        }
+    };
+
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
@@ -73,11 +101,29 @@
     }
 
     private void loadRows() {
-        for (int i = 0; i < NUM_ROWS; ++i) {
+        HeaderItem header = new HeaderItem(0, mQuery + " results row " + 0);
+
+        // Every time when the query event is fired, we will update the fake search result in the
+        // first row based on the flag mIsDataSetOnePresented flag.
+        // Also the first row adapter will only be created once so the animation will be triggered
+        // when the items in the adapter changed.
+        if (!mIsDataSetOnePresented) {
+            if (mFirstRowAdapter == null) {
+                mFirstRowAdapter = createFirstListRowAdapter();
+            } else {
+                mFirstRowAdapter.setItems(createDataSetOne(), mDiffCallback);
+            }
+            mIsDataSetOnePresented = true;
+        } else {
+            mFirstRowAdapter.setItems(createDataSetTwo(), mDiffCallback);
+            mIsDataSetOnePresented = false;
+        }
+        mRowsAdapter.add(new ListRow(header, mFirstRowAdapter));
+        for (int i = 1; i < NUM_ROWS + 1; ++i) {
             ArrayObjectAdapter listRowAdapter = new ArrayObjectAdapter(new CardPresenter());
             listRowAdapter.add(new PhotoItem("Hello world", R.drawable.gallery_photo_1));
             listRowAdapter.add(new PhotoItem("This is a test", R.drawable.gallery_photo_2));
-            HeaderItem header = new HeaderItem(i, mQuery + " results row " + i);
+            header = new HeaderItem(i, mQuery + " results row " + i);
             mRowsAdapter.add(new ListRow(header, listRowAdapter));
         }
     }
@@ -98,9 +144,155 @@
 
             Bundle bundle = ActivityOptionsCompat.makeSceneTransitionAnimation(
                     getActivity(),
-                    ((ImageCardView)itemViewHolder.view).getMainImageView(),
+                    ((ImageCardView) itemViewHolder.view).getMainImageView(),
                     DetailsActivity.SHARED_ELEMENT_NAME).toBundle();
             getActivity().startActivity(intent, bundle);
         }
     }
+
+
+    private ArrayObjectAdapter createFirstListRowAdapter() {
+        ArrayObjectAdapter listRowAdapter = new ArrayObjectAdapter(new CardPresenter());
+        listRowAdapter.setItems(createDataSetOne(), mDiffCallback);
+        mIsDataSetOnePresented = true;
+        return listRowAdapter;
+    }
+
+    /**
+     * Create a 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> createDataSetOne() {
+        ArrayList<PhotoItem> photoItems = new ArrayList<>();
+        photoItems.add(new PhotoItem(
+                "Hello world",
+                R.drawable.gallery_photo_1,
+                1));
+        photoItems.add(new PhotoItem(
+                "This is a test",
+                "Only a test",
+                R.drawable.gallery_photo_2,
+                2));
+        photoItems.add(new PhotoItem(
+                "Android TV",
+                "by Google",
+                R.drawable.gallery_photo_3,
+                3));
+        photoItems.add(new PhotoItem(
+                "Leanback",
+                R.drawable.gallery_photo_4,
+                4));
+        photoItems.add(new PhotoItem(
+                "GuidedStep (Slide left/right)",
+                R.drawable.gallery_photo_5,
+                5));
+        photoItems.add(new PhotoItem(
+                "GuidedStep (Slide bottom up)",
+                "Open GuidedStepFragment",
+                R.drawable.gallery_photo_6,
+                6));
+        photoItems.add(new PhotoItem(
+                "Android TV",
+                "open RowsActivity",
+                R.drawable.gallery_photo_7,
+                7));
+        photoItems.add(new PhotoItem(
+                "Leanback",
+                "open BrowseActivity",
+                R.drawable.gallery_photo_8,
+                8));
+        photoItems.add(new PhotoItem(
+                "Hello world",
+                R.drawable.gallery_photo_1,
+                1));
+        photoItems.add(new PhotoItem(
+                "This is a test",
+                "Only a test",
+                R.drawable.gallery_photo_2,
+                2));
+        photoItems.add(new PhotoItem(
+                "Android TV",
+                "by Google",
+                R.drawable.gallery_photo_3,
+                3));
+        photoItems.add(new PhotoItem(
+                "Leanback",
+                R.drawable.gallery_photo_4,
+                4));
+        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> createDataSetTwo() {
+        ArrayList<PhotoItem> photoItems = new ArrayList<>();
+        photoItems.add(new PhotoItem(
+                "This is a test",
+                "Only a test",
+                R.drawable.gallery_photo_2,
+                2));
+        photoItems.add(new PhotoItem(
+                "Hello world",
+                R.drawable.gallery_photo_1,
+                1));
+        photoItems.add(new PhotoItem(
+                "Leanback",
+                R.drawable.gallery_photo_4,
+                4));
+        photoItems.add(new PhotoItem(
+                "Android TV",
+                "by Google",
+                R.drawable.gallery_photo_3,
+                3));
+        photoItems.add(new PhotoItem(
+                "change title",
+                R.drawable.gallery_photo_5,
+                5));
+        photoItems.add(new PhotoItem(
+                "GuidedStep (Slide bottom up)",
+                "change comment",
+                R.drawable.gallery_photo_6,
+                6));
+        photoItems.add(new PhotoItem(
+                "Android TV",
+                R.drawable.gallery_photo_7,
+                7));
+        photoItems.add(new PhotoItem(
+                "Leanback",
+                "open BrowseActivity",
+                R.drawable.gallery_photo_7,
+                8));
+        photoItems.add(new PhotoItem(
+                "Hello world",
+                R.drawable.gallery_photo_1,
+                10));
+        photoItems.add(new PhotoItem(
+                "This is a test",
+                "Only a test",
+                R.drawable.gallery_photo_2,
+                20));
+        photoItems.add(new PhotoItem(
+                "Android TV",
+                "by Google",
+                R.drawable.gallery_photo_3,
+                30));
+        photoItems.add(new PhotoItem(
+                "Leanback",
+                R.drawable.gallery_photo_4,
+                40));
+        return photoItems;
+    }
+
 }
diff --git a/samples/SupportLeanbackDemos/src/com/example/android/leanback/SearchSupportFragment.java b/samples/SupportLeanbackDemos/src/com/example/android/leanback/SearchSupportFragment.java
index 0a3baf2..af56352 100644
--- a/samples/SupportLeanbackDemos/src/com/example/android/leanback/SearchSupportFragment.java
+++ b/samples/SupportLeanbackDemos/src/com/example/android/leanback/SearchSupportFragment.java
@@ -8,6 +8,7 @@
 import android.os.Bundle;
 import android.os.Handler;
 import android.support.v17.leanback.widget.ArrayObjectAdapter;
+import android.support.v17.leanback.widget.DiffCallback;
 import android.support.v17.leanback.widget.HeaderItem;
 import android.support.v17.leanback.widget.ImageCardView;
 import android.support.v17.leanback.widget.ListRow;
@@ -22,8 +23,10 @@
 import android.text.TextUtils;
 import android.util.Log;
 
+import java.util.ArrayList;
+
 public class SearchSupportFragment extends android.support.v17.leanback.app.SearchSupportFragment
-    implements android.support.v17.leanback.app.SearchSupportFragment.SearchResultProvider {
+        implements android.support.v17.leanback.app.SearchSupportFragment.SearchResultProvider {
     private static final String TAG = "leanback.SearchSupportFragment";
     private static final int NUM_ROWS = 3;
     private static final int SEARCH_DELAY_MS = 1000;
@@ -32,6 +35,31 @@
     private Handler mHandler = new Handler();
     private String mQuery;
 
+    // Flag to represent if data set one is presented in the fragment
+    private boolean mIsDataSetOnePresented;
+
+    // Adapter for first row
+    private ArrayObjectAdapter mFirstRowAdapter;
+
+    // The diff callback which defines the standard to judge if two items are the same or if
+    // two items have the same content.
+    private DiffCallback<PhotoItem> mDiffCallback = new DiffCallback<PhotoItem>() {
+
+        // when two photo items have the same id, they are the same from adapter's
+        // perspective
+        @Override
+        public boolean areItemsTheSame(PhotoItem oldItem, PhotoItem newItem) {
+            return oldItem.getId() == newItem.getId();
+        }
+
+        // when two photo items is equal to each other (based on the equal method defined in
+        // PhotoItem), they have the same content.
+        @Override
+        public boolean areContentsTheSame(PhotoItem oldItem, PhotoItem newItem) {
+            return oldItem.equals(newItem);
+        }
+    };
+
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
@@ -76,11 +104,29 @@
     }
 
     private void loadRows() {
-        for (int i = 0; i < NUM_ROWS; ++i) {
+        HeaderItem header = new HeaderItem(0, mQuery + " results row " + 0);
+
+        // Every time when the query event is fired, we will update the fake search result in the
+        // first row based on the flag mIsDataSetOnePresented flag.
+        // Also the first row adapter will only be created once so the animation will be triggered
+        // when the items in the adapter changed.
+        if (!mIsDataSetOnePresented) {
+            if (mFirstRowAdapter == null) {
+                mFirstRowAdapter = createFirstListRowAdapter();
+            } else {
+                mFirstRowAdapter.setItems(createDataSetOne(), mDiffCallback);
+            }
+            mIsDataSetOnePresented = true;
+        } else {
+            mFirstRowAdapter.setItems(createDataSetTwo(), mDiffCallback);
+            mIsDataSetOnePresented = false;
+        }
+        mRowsAdapter.add(new ListRow(header, mFirstRowAdapter));
+        for (int i = 1; i < NUM_ROWS + 1; ++i) {
             ArrayObjectAdapter listRowAdapter = new ArrayObjectAdapter(new CardPresenter());
             listRowAdapter.add(new PhotoItem("Hello world", R.drawable.gallery_photo_1));
             listRowAdapter.add(new PhotoItem("This is a test", R.drawable.gallery_photo_2));
-            HeaderItem header = new HeaderItem(i, mQuery + " results row " + i);
+            header = new HeaderItem(i, mQuery + " results row " + i);
             mRowsAdapter.add(new ListRow(header, listRowAdapter));
         }
     }
@@ -101,9 +147,155 @@
 
             Bundle bundle = ActivityOptionsCompat.makeSceneTransitionAnimation(
                     getActivity(),
-                    ((ImageCardView)itemViewHolder.view).getMainImageView(),
+                    ((ImageCardView) itemViewHolder.view).getMainImageView(),
                     DetailsSupportActivity.SHARED_ELEMENT_NAME).toBundle();
             getActivity().startActivity(intent, bundle);
         }
     }
+
+
+    private ArrayObjectAdapter createFirstListRowAdapter() {
+        ArrayObjectAdapter listRowAdapter = new ArrayObjectAdapter(new CardPresenter());
+        listRowAdapter.setItems(createDataSetOne(), mDiffCallback);
+        mIsDataSetOnePresented = true;
+        return listRowAdapter;
+    }
+
+    /**
+     * Create a 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> createDataSetOne() {
+        ArrayList<PhotoItem> photoItems = new ArrayList<>();
+        photoItems.add(new PhotoItem(
+                "Hello world",
+                R.drawable.gallery_photo_1,
+                1));
+        photoItems.add(new PhotoItem(
+                "This is a test",
+                "Only a test",
+                R.drawable.gallery_photo_2,
+                2));
+        photoItems.add(new PhotoItem(
+                "Android TV",
+                "by Google",
+                R.drawable.gallery_photo_3,
+                3));
+        photoItems.add(new PhotoItem(
+                "Leanback",
+                R.drawable.gallery_photo_4,
+                4));
+        photoItems.add(new PhotoItem(
+                "GuidedStep (Slide left/right)",
+                R.drawable.gallery_photo_5,
+                5));
+        photoItems.add(new PhotoItem(
+                "GuidedStep (Slide bottom up)",
+                "Open GuidedStepFragment",
+                R.drawable.gallery_photo_6,
+                6));
+        photoItems.add(new PhotoItem(
+                "Android TV",
+                "open RowsActivity",
+                R.drawable.gallery_photo_7,
+                7));
+        photoItems.add(new PhotoItem(
+                "Leanback",
+                "open BrowseActivity",
+                R.drawable.gallery_photo_8,
+                8));
+        photoItems.add(new PhotoItem(
+                "Hello world",
+                R.drawable.gallery_photo_1,
+                1));
+        photoItems.add(new PhotoItem(
+                "This is a test",
+                "Only a test",
+                R.drawable.gallery_photo_2,
+                2));
+        photoItems.add(new PhotoItem(
+                "Android TV",
+                "by Google",
+                R.drawable.gallery_photo_3,
+                3));
+        photoItems.add(new PhotoItem(
+                "Leanback",
+                R.drawable.gallery_photo_4,
+                4));
+        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> createDataSetTwo() {
+        ArrayList<PhotoItem> photoItems = new ArrayList<>();
+        photoItems.add(new PhotoItem(
+                "This is a test",
+                "Only a test",
+                R.drawable.gallery_photo_2,
+                2));
+        photoItems.add(new PhotoItem(
+                "Hello world",
+                R.drawable.gallery_photo_1,
+                1));
+        photoItems.add(new PhotoItem(
+                "Leanback",
+                R.drawable.gallery_photo_4,
+                4));
+        photoItems.add(new PhotoItem(
+                "Android TV",
+                "by Google",
+                R.drawable.gallery_photo_3,
+                3));
+        photoItems.add(new PhotoItem(
+                "change title",
+                R.drawable.gallery_photo_5,
+                5));
+        photoItems.add(new PhotoItem(
+                "GuidedStep (Slide bottom up)",
+                "change comment",
+                R.drawable.gallery_photo_6,
+                6));
+        photoItems.add(new PhotoItem(
+                "Android TV",
+                R.drawable.gallery_photo_7,
+                7));
+        photoItems.add(new PhotoItem(
+                "Leanback",
+                "open BrowseActivity",
+                R.drawable.gallery_photo_7,
+                8));
+        photoItems.add(new PhotoItem(
+                "Hello world",
+                R.drawable.gallery_photo_1,
+                10));
+        photoItems.add(new PhotoItem(
+                "This is a test",
+                "Only a test",
+                R.drawable.gallery_photo_2,
+                20));
+        photoItems.add(new PhotoItem(
+                "Android TV",
+                "by Google",
+                R.drawable.gallery_photo_3,
+                30));
+        photoItems.add(new PhotoItem(
+                "Leanback",
+                R.drawable.gallery_photo_4,
+                40));
+        return photoItems;
+    }
+
 }
diff --git a/v17/leanback/api/current.txt b/v17/leanback/api/current.txt
index 4795807..1db7e5f 100644
--- a/v17/leanback/api/current.txt
+++ b/v17/leanback/api/current.txt
@@ -1541,10 +1541,12 @@
     method public void clear();
     method public java.lang.Object get(int);
     method public int indexOf(java.lang.Object);
+    method public void move(int, int);
     method public void notifyArrayItemRangeChanged(int, int);
     method public boolean remove(java.lang.Object);
     method public int removeItems(int, int);
     method public void replace(int, java.lang.Object);
+    method public void setItems(java.util.List, android.support.v17.leanback.widget.DiffCallback);
     method public int size();
     method public <E> java.util.List<E> unmodifiableList();
   }
@@ -1813,6 +1815,12 @@
     method public android.support.v17.leanback.widget.Parallax.IntProperty getOverviewRowTop();
   }
 
+  public abstract class DiffCallback<T> {
+    ctor public DiffCallback();
+    method public abstract boolean areContentsTheSame(T, T);
+    method public abstract boolean areItemsTheSame(T, T);
+  }
+
   public class DividerPresenter extends android.support.v17.leanback.widget.Presenter {
     ctor public DividerPresenter();
     method public void onBindViewHolder(android.support.v17.leanback.widget.Presenter.ViewHolder, java.lang.Object);
@@ -2389,6 +2397,7 @@
     method public final boolean hasStableIds();
     method public boolean isImmediateNotifySupported();
     method protected final void notifyChanged();
+    method protected final void notifyItemMoved(int, int);
     method public final void notifyItemRangeChanged(int, int);
     method protected final void notifyItemRangeInserted(int, int);
     method protected final void notifyItemRangeRemoved(int, int);
@@ -2406,6 +2415,7 @@
   public static abstract class ObjectAdapter.DataObserver {
     ctor public ObjectAdapter.DataObserver();
     method public void onChanged();
+    method public void onItemMoved(int, int);
     method public void onItemRangeChanged(int, int);
     method public void onItemRangeInserted(int, int);
     method public void onItemRangeRemoved(int, int);
diff --git a/v17/leanback/res/values-pa/strings.xml b/v17/leanback/res/values-pa/strings.xml
index eb58bd6..4b3c515 100644
--- a/v17/leanback/res/values-pa/strings.xml
+++ b/v17/leanback/res/values-pa/strings.xml
@@ -41,11 +41,11 @@
     <string name="lb_playback_controls_repeat_none" msgid="87476947476529036">"ਕੋਈ ਵੀ ਨਾ ਦੁਹਰਾਓ"</string>
     <string name="lb_playback_controls_repeat_all" msgid="6730354406289599000">"ਸਾਰਿਆਂ ਨੂੰ ਦੁਹਰਾਓ"</string>
     <string name="lb_playback_controls_repeat_one" msgid="3285202316452203619">"ਇੱਕ ਦੁਹਰਾਓ"</string>
-    <string name="lb_playback_controls_shuffle_enable" msgid="1099874107835264529">"ਸ਼ਫਲ ਨੂੰ ਸਮਰੱਥ ਬਣਾਓ"</string>
+    <string name="lb_playback_controls_shuffle_enable" msgid="1099874107835264529">"ਬੇਤਰਤੀਬ ਨੂੰ ਚਾਲੂ ਕਰੋ"</string>
     <string name="lb_playback_controls_shuffle_disable" msgid="8388150597335115226">"ਸ਼ਫਲ ਨੂੰ ਅਸਮਰੱਥ ਬਣਾਓ"</string>
-    <string name="lb_playback_controls_high_quality_enable" msgid="202415780019335254">"ਉੱਚ ਗੁਣਵੱਤਾ ਨੂੰ ਸਮਰੱਥ ਬਣਾਓ"</string>
+    <string name="lb_playback_controls_high_quality_enable" msgid="202415780019335254">"ਉੱਚ ਗੁਣਵੱਤਾ ਨੂੰ ਚਾਲੂ ਕਰੋ"</string>
     <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"ਉੱਚ ਗੁਣਵੱਤਾ ਨੂੰ ਅਸਮਰੱਥ ਬਣਾਓ"</string>
-    <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"ਬੰਦ ਕੈਪਸ਼ਨਿੰਗ ਸਮਰੱਥ ਬਣਾਓ"</string>
+    <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"ਬੰਦ ਸੁਰਖੀਆਂ ਚਾਲੂ ਕਰੋ"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"ਬੰਦ ਕੈਪਸ਼ਨਿੰਗ ਅਸਮਰੱਥ ਬਣਾਓ"</string>
     <string name="lb_playback_controls_picture_in_picture" msgid="3040035547765350690">"ਤਸਵੀਰ ਮੋਡ ਵਿੱਚ ਤਸਵੀਰ ਦਾਖਲ ਕਰੋ"</string>
     <string name="lb_playback_time_separator" msgid="3208380806582304911">"/"</string>
diff --git a/v17/leanback/res/values-te/strings.xml b/v17/leanback/res/values-te/strings.xml
index 34ea221..5188d19 100644
--- a/v17/leanback/res/values-te/strings.xml
+++ b/v17/leanback/res/values-te/strings.xml
@@ -31,7 +31,7 @@
     <string name="lb_playback_controls_fast_forward_multiplier" msgid="1058753672110224526">"%1$dX ఫాస్ట్ ఫార్వార్డ్ చేయి"</string>
     <string name="lb_playback_controls_rewind" msgid="2227196334132350684">"రివైండ్ చేయి"</string>
     <string name="lb_playback_controls_rewind_multiplier" msgid="1640629531440849942">"%1$dX రివైండ్ చేయి"</string>
-    <string name="lb_playback_controls_skip_next" msgid="2946499493161095772">"తదుపరి దానికి దాటవేయి"</string>
+    <string name="lb_playback_controls_skip_next" msgid="2946499493161095772">"తర్వాత దానికి దాటవేయి"</string>
     <string name="lb_playback_controls_skip_previous" msgid="2326801832933178348">"మునుపటి దానికి దాటవేయి"</string>
     <string name="lb_playback_controls_more_actions" msgid="2330770008796987655">"మరిన్ని చర్యలు"</string>
     <string name="lb_playback_controls_thumb_up" msgid="6530420347129222601">"విజయ సంకేతం ఎంపికను తీసివేయి"</string>
@@ -55,5 +55,5 @@
     <string name="lb_guidedaction_continue_title" msgid="8842094924543063706">"కొనసాగించు"</string>
     <string name="lb_media_player_error" msgid="3650250994187305396">"MediaPlayer ఎర్రర్ కోడ్ %1$d అదనంగా %2$d"</string>
     <string name="lb_onboarding_get_started" msgid="6961440391306351139">"ప్రారంభించు"</string>
-    <string name="lb_onboarding_accessibility_next" msgid="2918313444257732434">"తదుపరి"</string>
+    <string name="lb_onboarding_accessibility_next" msgid="2918313444257732434">"తర్వాత"</string>
 </resources>
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/ArrayObjectAdapter.java b/v17/leanback/src/android/support/v17/leanback/widget/ArrayObjectAdapter.java
index b31d30a..40bd05f 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/ArrayObjectAdapter.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/ArrayObjectAdapter.java
@@ -13,6 +13,10 @@
  */
 package android.support.v17.leanback.widget;
 
+import android.support.v7.util.DiffUtil;
+import android.support.v7.util.ListUpdateCallback;
+import android.util.Log;
+
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
@@ -23,7 +27,13 @@
  */
 public class ArrayObjectAdapter extends ObjectAdapter {
 
-    private ArrayList<Object> mItems = new ArrayList<Object>();
+    private static final Boolean DEBUG = false;
+    private static final String TAG = "ArrayObjectAdapter";
+
+    private final List mItems = new ArrayList<Object>();
+
+    // Un modifiable version of mItems;
+    private List mUnmodifiableItems;
 
     /**
      * Constructs an adapter with the given {@link PresenterSelector}.
@@ -60,9 +70,9 @@
      * Returns the index for the first occurrence of item in the adapter, or -1 if
      * not found.
      *
-     * @param item  The item to find in the list.
+     * @param item The item to find in the list.
      * @return Index of the first occurrence of the item in the adapter, or -1
-     *         if not found.
+     * if not found.
      */
     public int indexOf(Object item) {
         return mItems.indexOf(item);
@@ -73,7 +83,7 @@
      * not same as items being added or removed.
      *
      * @param positionStart The position of first item that has changed.
-     * @param itemCount The count of how many items have changed.
+     * @param itemCount     The count of how many items have changed.
      */
     public void notifyArrayItemRangeChanged(int positionStart, int itemCount) {
         notifyItemRangeChanged(positionStart, itemCount);
@@ -93,7 +103,7 @@
      * If the index is > {@link #size} an exception will be thrown.
      *
      * @param index The index at which the item should be inserted.
-     * @param item The item to insert into the adapter.
+     * @param item  The item to insert into the adapter.
      */
     public void add(int index, Object item) {
         mItems.add(index, item);
@@ -132,11 +142,28 @@
     }
 
     /**
+     * Moved the item at fromPosition to toPosition.
+     *
+     * @param fromPosition Previous position of the item.
+     * @param toPosition   New position of the item.
+     */
+    public void move(int fromPosition, int toPosition) {
+        if (fromPosition == toPosition) {
+            // no-op
+            return;
+        }
+        Object item = mItems.remove(fromPosition);
+        mItems.add(toPosition, item);
+        notifyItemMoved(fromPosition, toPosition);
+    }
+
+    /**
      * Replaces item at position with a new item and calls notifyItemRangeChanged()
      * at the given position.  Note that this method does not compare new item to
      * existing item.
-     * @param position  The index of item to replace.
-     * @param item      The new item to be placed at given position.
+     *
+     * @param position The index of item to replace.
+     * @param item     The new item to be placed at given position.
      */
     public void replace(int position, Object item) {
         mItems.set(position, item);
@@ -148,7 +175,7 @@
      * the starting position and the number of elements to remove.
      *
      * @param position The index of the first item to remove.
-     * @param count The number of items to remove.
+     * @param count    The number of items to remove.
      * @return The number of items removed.
      */
     public int removeItems(int position, int count) {
@@ -180,11 +207,92 @@
      * Gets a read-only view of the list of object of this ArrayObjectAdapter.
      */
     public <E> List<E> unmodifiableList() {
-        return Collections.unmodifiableList((List<E>) mItems);
+
+        // The mUnmodifiableItems will only be created once as long as the content of mItems has not
+        // been changed.
+        if (mUnmodifiableItems == null) {
+            mUnmodifiableItems = Collections.unmodifiableList(mItems);
+        }
+        return mUnmodifiableItems;
     }
 
     @Override
     public boolean isImmediateNotifySupported() {
         return true;
     }
+
+    /**
+     * Set a new item list to adapter. The DiffUtil will compute the difference and dispatch it to
+     * specified position.
+     *
+     * @param itemList List of new Items
+     * @param callback DiffCallback Object to compute the difference between the old data set and
+     *                 new data set.
+     */
+    public void setItems(final List itemList, final DiffCallback callback) {
+
+        DiffUtil.DiffResult diffResult = DiffUtil.calculateDiff(new DiffUtil.Callback() {
+            @Override
+            public int getOldListSize() {
+                return mItems.size();
+            }
+
+            @Override
+            public int getNewListSize() {
+                return itemList.size();
+            }
+
+            @Override
+            public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) {
+                return callback.areItemsTheSame(mItems.get(oldItemPosition),
+                        itemList.get(newItemPosition));
+            }
+
+            @Override
+            public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) {
+                return callback.areContentsTheSame(mItems.get(oldItemPosition),
+                        itemList.get(newItemPosition));
+            }
+        });
+
+        // update items.
+        mItems.clear();
+        mItems.addAll(itemList);
+
+        // dispatch diff result
+        diffResult.dispatchUpdatesTo(new ListUpdateCallback() {
+
+            @Override
+            public void onInserted(int position, int count) {
+                if (DEBUG) {
+                    Log.d(TAG, "onInserted");
+                }
+                notifyItemRangeInserted(position, count);
+            }
+
+            @Override
+            public void onRemoved(int position, int count) {
+                if (DEBUG) {
+                    Log.d(TAG, "onRemoved");
+                }
+                notifyItemRangeRemoved(position, count);
+            }
+
+            @Override
+            public void onMoved(int fromPosition, int toPosition) {
+                if (DEBUG) {
+                    Log.d(TAG, "onMoved");
+                }
+                notifyItemMoved(fromPosition, toPosition);
+            }
+
+            @Override
+            public void onChanged(int position, int count, Object payload) {
+                if (DEBUG) {
+                    Log.d(TAG, "onChanged");
+                }
+                notifyItemRangeChanged(position, count);
+            }
+        });
+    }
 }
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/DiffCallback.java b/v17/leanback/src/android/support/v17/leanback/widget/DiffCallback.java
new file mode 100644
index 0000000..841c864
--- /dev/null
+++ b/v17/leanback/src/android/support/v17/leanback/widget/DiffCallback.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v17.leanback.widget;
+
+/**
+ * This callback class which will be passed as the parameter for setItems method to compute the
+ * difference between the old items and new items.
+ *
+ * @param <T> The type of the item in list.
+ */
+public abstract class DiffCallback<T> {
+
+    /**
+     * This method is used to provide a standard to judge if two items are the same or not.
+     * Will be used by DiffUtil.calculateDiff method.
+     *
+     * @param oldItem Previous item.
+     * @param newItem New item.
+     * @return If two items are the same or not.
+     */
+    public abstract boolean areItemsTheSame(T oldItem, T newItem);
+
+    /**
+     * This method is used to provide a standard to judge if two items have the same content or
+     * not. Will be used by DiffUtil.calculateDiff method.
+     *
+     * @param oldItem Previous item.
+     * @param newItem New item.
+     * @return If two items have the same content.
+     */
+    public abstract boolean areContentsTheSame(T oldItem, T newItem);
+}
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/GridLayoutManager.java b/v17/leanback/src/android/support/v17/leanback/widget/GridLayoutManager.java
index 529f566..8b0c4a7 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/GridLayoutManager.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/GridLayoutManager.java
@@ -423,6 +423,7 @@
     /**
      * The orientation of a "row".
      */
+    @RecyclerView.Orientation
     int mOrientation = HORIZONTAL;
     private OrientationHelper mOrientationHelper = OrientationHelper.createHorizontalHelper(this);
 
@@ -674,7 +675,7 @@
         setItemPrefetchEnabled(false);
     }
 
-    public void setOrientation(int orientation) {
+    public void setOrientation(@RecyclerView.Orientation int orientation) {
         if (orientation != HORIZONTAL && orientation != VERTICAL) {
             if (DEBUG) Log.v(getTag(), "invalid orientation: " + orientation);
             return;
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/ItemBridgeAdapter.java b/v17/leanback/src/android/support/v17/leanback/widget/ItemBridgeAdapter.java
index f5dfd99..3ac708f 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/ItemBridgeAdapter.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/ItemBridgeAdapter.java
@@ -159,6 +159,11 @@
         public void onItemRangeRemoved(int positionStart, int itemCount) {
             ItemBridgeAdapter.this.notifyItemRangeRemoved(positionStart, itemCount);
         }
+
+        @Override
+        public void onItemMoved(int fromPosition, int toPosition) {
+            ItemBridgeAdapter.this.notifyItemMoved(fromPosition, toPosition);
+        }
     };
 
     public ItemBridgeAdapter(ObjectAdapter adapter, PresenterSelector presenterSelector) {
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/ObjectAdapter.java b/v17/leanback/src/android/support/v17/leanback/widget/ObjectAdapter.java
index ff10028..d833385 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/ObjectAdapter.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/ObjectAdapter.java
@@ -60,6 +60,15 @@
         }
 
         /**
+         * Called when an item is moved from one position to another position
+         * @param fromPosition Previous position of the item.
+         * @param toPosition New position of the item.
+         */
+        public void onItemMoved(int fromPosition, int toPosition) {
+            onChanged();
+        }
+
+        /**
          * Called when a range of items is removed from the ObjectAdapter.
          *
          * @param positionStart The position of the first removed item.
@@ -98,6 +107,12 @@
                 mObservers.get(i).onItemRangeRemoved(positionStart, itemCount);
             }
         }
+
+        public void notifyItemMoved(int positionStart, int toPosition) {
+            for (int i = mObservers.size() - 1; i >= 0; i--) {
+                mObservers.get(i).onItemMoved(positionStart, toPosition);
+            }
+        }
     }
 
     private final DataObservable mObservable = new DataObservable();
@@ -210,6 +225,16 @@
     }
 
     /**
+     * Notifies UI that item at fromPosition has been moved to toPosition.
+     *
+     * @param fromPosition Previous position of the item.
+     * @param toPosition New position of the item.
+     */
+    protected final void notifyItemMoved(int fromPosition, int toPosition) {
+        mObservable.notifyItemMoved(fromPosition, toPosition);
+    }
+
+    /**
      * Notifies UI that the underlying data has changed.
      */
     final protected void notifyChanged() {
diff --git a/v17/leanback/tests/java/android/support/v17/leanback/widget/ObjectAdapterTest.java b/v17/leanback/tests/java/android/support/v17/leanback/widget/ObjectAdapterTest.java
new file mode 100644
index 0000000..7327166
--- /dev/null
+++ b/v17/leanback/tests/java/android/support/v17/leanback/widget/ObjectAdapterTest.java
@@ -0,0 +1,369 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v17.leanback.widget;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.never;
+
+import android.support.test.filters.SmallTest;
+import android.support.v7.widget.RecyclerView;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import org.mockito.Mockito;
+
+import java.util.ArrayList;
+
+@SmallTest
+@RunWith(JUnit4.class)
+public class ObjectAdapterTest {
+
+    protected ItemBridgeAdapter mBridgeAdapter;
+    protected ObjectAdapter mAdapter;
+
+    static void assertAdapterContent(ObjectAdapter adapter, Object[] data) {
+        assertEquals(adapter.size(), data.length);
+        for (int i = 0; i < adapter.size(); i++) {
+            assertEquals(adapter.get(i), data[i]);
+        }
+    }
+
+    static class AdapterItem {
+        private int mId;
+        private String mName;
+
+        AdapterItem(int id, String name) {
+            this.mId = id;
+            this.mName = name;
+        }
+
+        public int getId() {
+            return mId;
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) return true;
+            if (o == null || getClass() != o.getClass()) return false;
+
+            AdapterItem test = (AdapterItem) o;
+
+            if (mId != test.mId) return false;
+            return mName != null ? mName.equals(test.mName) : test.mName == null;
+        }
+
+        @Override
+        public int hashCode() {
+            int result = mId;
+            result = 31 * result + (mName != null ? mName.hashCode() : 0);
+            return result;
+        }
+    }
+
+    @Test
+    public void arrayObjectAdapter() {
+        ArrayObjectAdapter adapter = new ArrayObjectAdapter();
+        mAdapter = adapter;
+        mBridgeAdapter = new ItemBridgeAdapter(mAdapter);
+        ArrayList items = new ArrayList();
+        items.add("a");
+        items.add("b");
+        items.add("c");
+        adapter.addAll(0, items);
+
+        RecyclerView.AdapterDataObserver observer = Mockito.mock(
+                RecyclerView.AdapterDataObserver.class);
+        mBridgeAdapter.registerAdapterDataObserver(observer);
+
+        // size
+        assertEquals(adapter.size(), 3);
+
+        // get
+        assertEquals(adapter.get(0), "a");
+        assertEquals(adapter.get(1), "b");
+        assertEquals(adapter.get(2), "c");
+
+        // indexOf
+        assertEquals(adapter.indexOf("a"), 0);
+        assertEquals(adapter.indexOf("b"), 1);
+        assertEquals(adapter.indexOf("c"), 2);
+
+        // insert
+        adapter.add(1, "a1");
+        Mockito.verify(observer).onItemRangeInserted(1, 1);
+        assertAdapterContent(adapter, new Object[]{"a", "a1", "b", "c"});
+        Mockito.reset(observer);
+
+        // insert multiple
+        ArrayList newItems1 = new ArrayList();
+        newItems1.add("a2");
+        newItems1.add("a3");
+        adapter.addAll(1, newItems1);
+        Mockito.verify(observer).onItemRangeInserted(1, 2);
+        assertAdapterContent(adapter, new Object[]{"a", "a2", "a3", "a1", "b", "c"});
+        Mockito.reset(observer);
+
+        // update
+        adapter.notifyArrayItemRangeChanged(2, 3);
+        Mockito.verify(observer).onItemRangeChanged(2, 3, null);
+        assertAdapterContent(adapter, new Object[]{"a", "a2", "a3", "a1", "b", "c"});
+        Mockito.reset(observer);
+
+        // remove
+        adapter.removeItems(1, 4);
+        Mockito.verify(observer).onItemRangeRemoved(1, 4);
+        assertAdapterContent(adapter, new Object[]{"a", "c"});
+        Mockito.reset(observer);
+
+        // move
+        adapter.move(0, 1);
+        Mockito.verify(observer).onItemRangeMoved(0, 1, 1);
+        assertAdapterContent(adapter, new Object[]{"c", "a"});
+        Mockito.reset(observer);
+
+        // replace
+        adapter.replace(0, "a");
+        Mockito.verify(observer).onItemRangeChanged(0, 1, null);
+        assertAdapterContent(adapter, new Object[]{"a", "a"});
+        Mockito.reset(observer);
+        adapter.replace(1, "b");
+        Mockito.verify(observer).onItemRangeChanged(1, 1, null);
+        assertAdapterContent(adapter, new Object[]{"a", "b"});
+        Mockito.reset(observer);
+
+        // remove multiple
+        items.clear();
+        items.add("a");
+        items.add("b");
+        adapter.addAll(0, items);
+        adapter.removeItems(0, 2);
+        Mockito.verify(observer).onItemRangeRemoved(0, 2);
+        assertAdapterContent(adapter, new Object[]{"a", "b"});
+        Mockito.reset(observer);
+
+        // clear
+        adapter.clear();
+        Mockito.verify(observer).onItemRangeRemoved(0, 2);
+        assertAdapterContent(adapter, new Object[]{});
+        Mockito.reset(observer);
+
+        // isImmediateNotifySupported
+        assertTrue(adapter.isImmediateNotifySupported());
+
+        // setItems (test basic functionality with specialized comparator and verify adapter's item
+        // lists)
+        items.clear();
+        items.add("a");
+        items.add("b");
+        items.add("c");
+
+        DiffCallback callback = new DiffCallback<String>() {
+
+            // Always treat two items are the same.
+            @Override
+            public boolean areItemsTheSame(String oldItem, String newItem) {
+                return true;
+            }
+
+            // Always treat two items have the same content.
+            @Override
+            public boolean areContentsTheSame(String oldItem, String newItem) {
+                return true;
+            }
+        };
+
+        adapter.setItems(items, callback);
+        Mockito.verify(observer).onItemRangeInserted(0, 3);
+        assertAdapterContent(adapter, new Object[]{"a", "b", "c"});
+        Mockito.reset(observer);
+
+        // setItems (test basic functionality with specialized comparator and verify adapter's item
+        // lists)
+        items.clear();
+        items.add("a");
+        items.add("b");
+        items.add("c");
+
+        callback = new DiffCallback<String>() {
+
+            // Always treat two items are the different.
+            @Override
+            public boolean areItemsTheSame(String oldItem, String newItem) {
+                return false;
+            }
+
+            // Always treat two items have the different content.
+            @Override
+            public boolean areContentsTheSame(String oldItem, String newItem) {
+                return false;
+            }
+        };
+
+        adapter.setItems(items, callback);
+        Mockito.verify(observer).onItemRangeRemoved(0, 3);
+        Mockito.verify(observer).onItemRangeInserted(0, 3);
+
+        // No change or move event should be fired under current callback.
+        Mockito.verify(observer, never()).onItemRangeChanged(anyInt(), anyInt(), any());
+        Mockito.verify(observer, never()).onItemRangeMoved(anyInt(), anyInt(), anyInt());
+        assertAdapterContent(adapter, new Object[]{"a", "b", "c"});
+        Mockito.reset(observer);
+
+        // setItems (Using specialized java class to simulate actual scenario)
+        callback = new DiffCallback<AdapterItem>() {
+
+            // Using item's mId as the standard to judge if two items is the same
+            @Override
+            public boolean areItemsTheSame(AdapterItem oldItem, AdapterItem newItem) {
+                return oldItem.getId() == newItem.getId();
+            }
+
+            // Using equals method to judge if two items have the same content.
+            @Override
+            public boolean areContentsTheSame(AdapterItem oldItem, AdapterItem newItem) {
+                return oldItem.equals(newItem);
+            }
+        };
+
+
+        // Trigger notifyItemMoved event
+        adapter.clear();
+        items.clear();
+        items.add(new AdapterItem(1, "a"));
+        items.add(new AdapterItem(2, "b"));
+        items.add(new AdapterItem(3, "c"));
+        adapter.setItems(items, callback);
+        Mockito.reset(observer);
+        items.clear();
+        items.add(new AdapterItem(1, "a"));
+        items.add(new AdapterItem(2, "c"));
+        items.add(new AdapterItem(3, "b"));
+        adapter.setItems(items, callback);
+        Mockito.verify(observer).onItemRangeChanged(1, 2, null);
+        Mockito.reset(observer);
+
+        // Trigger notifyItemRangeChanged event
+        adapter.clear();
+        items.clear();
+        items.add(new AdapterItem(1, "a"));
+        items.add(new AdapterItem(2, "b"));
+        items.add(new AdapterItem(3, "c"));
+        adapter.clear();
+        adapter.setItems(items, callback);
+        Mockito.reset(observer);
+        items.clear();
+        items.add(new AdapterItem(2, "b"));
+        items.add(new AdapterItem(1, "a"));
+        items.add(new AdapterItem(3, "c"));
+        adapter.setItems(items, callback);
+        Mockito.verify(observer).onItemRangeMoved(1, 0, 1);
+        Mockito.reset(observer);
+
+        // Trigger notifyItemRangeRemoved event
+        adapter.clear();
+        items.clear();
+        items.add(new AdapterItem(1, "a"));
+        items.add(new AdapterItem(2, "b"));
+        items.add(new AdapterItem(3, "c"));
+        adapter.clear();
+        adapter.setItems(items, callback);
+        Mockito.reset(observer);
+        items.clear();
+        items.add(new AdapterItem(2, "b"));
+        items.add(new AdapterItem(3, "c"));
+        adapter.setItems(items, callback);
+        Mockito.verify(observer).onItemRangeRemoved(0, 1);
+        Mockito.reset(observer);
+
+        // Trigger notifyItemRangeInserted event
+        adapter.clear();
+        items.clear();
+        items.add(new AdapterItem(1, "a"));
+        items.add(new AdapterItem(2, "b"));
+        items.add(new AdapterItem(3, "c"));
+        adapter.clear();
+        adapter.setItems(items, callback);
+        Mockito.reset(observer);
+        items.clear();
+        items.add(new AdapterItem(1, "a"));
+        items.add(new AdapterItem(2, "b"));
+        items.add(new AdapterItem(3, "c"));
+        items.add(new AdapterItem(4, "d"));
+        adapter.setItems(items, callback);
+        Mockito.verify(observer).onItemRangeInserted(3, 1);
+        Mockito.reset(observer);
+
+        // Trigger notifyItemRangeInserted event and notifyItemRangeRemoved event simultaneously
+        adapter.clear();
+        items.clear();
+        items.add(new AdapterItem(1, "a"));
+        items.add(new AdapterItem(2, "b"));
+        items.add(new AdapterItem(3, "c"));
+        adapter.clear();
+        adapter.setItems(items, callback);
+        Mockito.reset(observer);
+        items.clear();
+        items.add(new AdapterItem(2, "a"));
+        items.add(new AdapterItem(2, "b"));
+        items.add(new AdapterItem(3, "c"));
+        adapter.setItems(items, callback);
+        Mockito.verify(observer).onItemRangeRemoved(0, 1);
+        Mockito.verify(observer).onItemRangeInserted(0, 1);
+        Mockito.reset(observer);
+
+
+        // Trigger notifyItemRangeMoved and notifyItemRangeChanged event simultaneously
+        adapter.clear();
+        items.clear();
+        items.add(new AdapterItem(1, "a"));
+        items.add(new AdapterItem(2, "b"));
+        items.add(new AdapterItem(3, "c"));
+        adapter.clear();
+        adapter.setItems(items, callback);
+        Mockito.reset(observer);
+        items.clear();
+        items.add(new AdapterItem(1, "aa"));
+        items.add(new AdapterItem(3, "c"));
+        items.add(new AdapterItem(2, "b"));
+        adapter.setItems(items, callback);
+        Mockito.verify(observer).onItemRangeChanged(0, 1, null);
+        Mockito.verify(observer).onItemRangeMoved(2, 1, 1);
+        Mockito.reset(observer);
+
+        // Trigger multiple items insertion event
+        adapter.clear();
+        items.clear();
+        items.add(new AdapterItem(0, "a"));
+        items.add(new AdapterItem(1, "b"));
+        adapter.clear();
+        adapter.setItems(items, callback);
+        Mockito.reset(observer);
+        items.clear();
+        items.add(new AdapterItem(0, "a"));
+        items.add(new AdapterItem(1, "b"));
+        items.add(new AdapterItem(2, "c"));
+        items.add(new AdapterItem(3, "d"));
+        adapter.setItems(items, callback);
+        Mockito.verify(observer).onItemRangeInserted(2, 2);
+        Mockito.reset(observer);
+    }
+
+}
diff --git a/v7/appcompat/res/values-hi/strings.xml b/v7/appcompat/res/values-hi/strings.xml
index 30d3001..0d90e55 100644
--- a/v7/appcompat/res/values-hi/strings.xml
+++ b/v7/appcompat/res/values-hi/strings.xml
@@ -17,21 +17,21 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="abc_action_mode_done" msgid="4076576682505996667">"पूर्ण"</string>
-    <string name="abc_action_bar_home_description" msgid="4600421777120114993">"मुख्यपृष्ठ पर नेविगेट करें"</string>
-    <string name="abc_action_bar_up_description" msgid="1594238315039666878">"ऊपर नेविगेट करें"</string>
-    <string name="abc_action_menu_overflow_description" msgid="3588849162933574182">"अधिक विकल्प"</string>
+    <string name="abc_action_bar_home_description" msgid="4600421777120114993">"होम पेज पर जाएं"</string>
+    <string name="abc_action_bar_up_description" msgid="1594238315039666878">"ऊपर जाएं"</string>
+    <string name="abc_action_menu_overflow_description" msgid="3588849162933574182">"ज़्यादा विकल्प"</string>
     <string name="abc_toolbar_collapse_description" msgid="1603543279005712093">"संक्षिप्त करें"</string>
-    <string name="abc_searchview_description_search" msgid="8264924765203268293">"खोजें"</string>
+    <string name="abc_searchview_description_search" msgid="8264924765203268293">"सर्च करें"</string>
     <string name="abc_search_hint" msgid="7723749260725869598">"खोजा जा रहा है…"</string>
-    <string name="abc_searchview_description_query" msgid="2550479030709304392">"खोज क्वेरी"</string>
+    <string name="abc_searchview_description_query" msgid="2550479030709304392">"सर्च क्वेरी"</string>
     <string name="abc_searchview_description_clear" msgid="3691816814315814921">"क्‍वेरी साफ़ करें"</string>
     <string name="abc_searchview_description_submit" msgid="8928215447528550784">"क्वेरी सबमिट करें"</string>
-    <string name="abc_searchview_description_voice" msgid="893419373245838918">"ध्वनि खोज"</string>
+    <string name="abc_searchview_description_voice" msgid="893419373245838918">"आवाज़ सर्च"</string>
     <string name="abc_activitychooserview_choose_application" msgid="2031811694353399454">"कोई एप्‍लिकेशन चुनें"</string>
     <string name="abc_activity_chooser_view_see_all" msgid="7468859129482906941">"सभी देखें"</string>
     <string name="abc_shareactionprovider_share_with_application" msgid="3300176832234831527">"<xliff:g id="APPLICATION_NAME">%s</xliff:g> के साथ साझा करें"</string>
     <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"इसके द्वारा साझा करें"</string>
     <string name="abc_capital_on" msgid="3405795526292276155">"चालू"</string>
     <string name="abc_capital_off" msgid="121134116657445385">"बंद"</string>
-    <string name="search_menu_title" msgid="146198913615257606">"खोज"</string>
+    <string name="search_menu_title" msgid="146198913615257606">"सर्च"</string>
 </resources>
diff --git a/v7/appcompat/res/values-iw/strings.xml b/v7/appcompat/res/values-iw/strings.xml
index 9ac2072..0a7d0bb 100644
--- a/v7/appcompat/res/values-iw/strings.xml
+++ b/v7/appcompat/res/values-iw/strings.xml
@@ -21,8 +21,8 @@
     <string name="abc_action_bar_up_description" msgid="1594238315039666878">"נווט למעלה"</string>
     <string name="abc_action_menu_overflow_description" msgid="3588849162933574182">"עוד אפשרויות"</string>
     <string name="abc_toolbar_collapse_description" msgid="1603543279005712093">"כווץ"</string>
-    <string name="abc_searchview_description_search" msgid="8264924765203268293">"חפש"</string>
-    <string name="abc_search_hint" msgid="7723749260725869598">"חפש…"</string>
+    <string name="abc_searchview_description_search" msgid="8264924765203268293">"חיפוש"</string>
+    <string name="abc_search_hint" msgid="7723749260725869598">"חיפוש…"</string>
     <string name="abc_searchview_description_query" msgid="2550479030709304392">"שאילתת חיפוש"</string>
     <string name="abc_searchview_description_clear" msgid="3691816814315814921">"מחק שאילתה"</string>
     <string name="abc_searchview_description_submit" msgid="8928215447528550784">"שלח שאילתה"</string>
@@ -33,5 +33,5 @@
     <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"שתף עם"</string>
     <string name="abc_capital_on" msgid="3405795526292276155">"פועל"</string>
     <string name="abc_capital_off" msgid="121134116657445385">"כבוי"</string>
-    <string name="search_menu_title" msgid="146198913615257606">"חפש"</string>
+    <string name="search_menu_title" msgid="146198913615257606">"חיפוש"</string>
 </resources>
diff --git a/v7/appcompat/res/values-te/strings.xml b/v7/appcompat/res/values-te/strings.xml
index 93f9aec..f7d7577 100644
--- a/v7/appcompat/res/values-te/strings.xml
+++ b/v7/appcompat/res/values-te/strings.xml
@@ -21,8 +21,8 @@
     <string name="abc_action_bar_up_description" msgid="1594238315039666878">"పైకి నావిగేట్ చేయండి"</string>
     <string name="abc_action_menu_overflow_description" msgid="3588849162933574182">"మరిన్ని ఎంపికలు"</string>
     <string name="abc_toolbar_collapse_description" msgid="1603543279005712093">"కుదించండి"</string>
-    <string name="abc_searchview_description_search" msgid="8264924765203268293">"శోధించు"</string>
-    <string name="abc_search_hint" msgid="7723749260725869598">"శోధించు..."</string>
+    <string name="abc_searchview_description_search" msgid="8264924765203268293">"వెతుకు"</string>
+    <string name="abc_search_hint" msgid="7723749260725869598">"వెతుకు..."</string>
     <string name="abc_searchview_description_query" msgid="2550479030709304392">"ప్రశ్న శోధించండి"</string>
     <string name="abc_searchview_description_clear" msgid="3691816814315814921">"ప్రశ్నను క్లియర్ చేయి"</string>
     <string name="abc_searchview_description_submit" msgid="8928215447528550784">"ప్రశ్నని సమర్పించు"</string>
@@ -33,5 +33,5 @@
     <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"వీరితో భాగస్వామ్యం చేయి"</string>
     <string name="abc_capital_on" msgid="3405795526292276155">"ఆన్ చేయి"</string>
     <string name="abc_capital_off" msgid="121134116657445385">"ఆఫ్ చేయి"</string>
-    <string name="search_menu_title" msgid="146198913615257606">"శోధించు"</string>
+    <string name="search_menu_title" msgid="146198913615257606">"వెతుకు"</string>
 </resources>
diff --git a/v7/mediarouter/res/values-bn/strings.xml b/v7/mediarouter/res/values-bn/strings.xml
index 56fcdd9..b827751 100644
--- a/v7/mediarouter/res/values-bn/strings.xml
+++ b/v7/mediarouter/res/values-bn/strings.xml
@@ -30,7 +30,7 @@
     <string name="mr_controller_play" msgid="683634565969987458">"চালান"</string>
     <string name="mr_controller_pause" msgid="5451884435510905406">"বিরাম দিন"</string>
     <string name="mr_controller_stop" msgid="735874641921425123">"থামান"</string>
-    <string name="mr_controller_expand_group" msgid="8062427022744266907">"প্রসারিত করুন"</string>
+    <string name="mr_controller_expand_group" msgid="8062427022744266907">"বড় করুন"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"সঙ্কুচিত করুন"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"অ্যালবাম শৈলি"</string>
     <string name="mr_controller_volume_slider" msgid="2361785992211841709">"ভলিউম স্লাইডার"</string>
diff --git a/v7/mediarouter/res/values-hi/strings.xml b/v7/mediarouter/res/values-hi/strings.xml
index 878a4b2..adf3e88 100644
--- a/v7/mediarouter/res/values-hi/strings.xml
+++ b/v7/mediarouter/res/values-hi/strings.xml
@@ -35,6 +35,6 @@
     <string name="mr_controller_album_art" msgid="6422801843540543585">"एल्बम आर्ट"</string>
     <string name="mr_controller_volume_slider" msgid="2361785992211841709">"वॉल्यूम स्लाइडर"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"कोई मीडिया चयनित नहीं है"</string>
-    <string name="mr_controller_no_info_available" msgid="5585418471741142924">"कोई जानकारी उपलब्‍ध नहीं"</string>
+    <string name="mr_controller_no_info_available" msgid="5585418471741142924">"कोई जानकारी मौजूद नहीं है"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"स्क्रीन कास्ट हो रही है"</string>
 </resources>
diff --git a/v7/recyclerview/src/android/support/v7/widget/GridLayoutManager.java b/v7/recyclerview/src/android/support/v7/widget/GridLayoutManager.java
index dfc7c12..67605b9 100644
--- a/v7/recyclerview/src/android/support/v7/widget/GridLayoutManager.java
+++ b/v7/recyclerview/src/android/support/v7/widget/GridLayoutManager.java
@@ -91,8 +91,8 @@
      *                      #VERTICAL}.
      * @param reverseLayout When set to true, layouts from end to start.
      */
-    public GridLayoutManager(Context context, int spanCount, int orientation,
-            boolean reverseLayout) {
+    public GridLayoutManager(Context context, int spanCount,
+            @RecyclerView.Orientation int orientation, boolean reverseLayout) {
         super(context, orientation, reverseLayout);
         setSpanCount(spanCount);
     }
diff --git a/v7/recyclerview/src/android/support/v7/widget/LinearLayoutManager.java b/v7/recyclerview/src/android/support/v7/widget/LinearLayoutManager.java
index a12e9a8..27df490 100644
--- a/v7/recyclerview/src/android/support/v7/widget/LinearLayoutManager.java
+++ b/v7/recyclerview/src/android/support/v7/widget/LinearLayoutManager.java
@@ -62,10 +62,10 @@
      */
     private static final float MAX_SCROLL_FACTOR = 1 / 3f;
 
-
     /**
      * Current orientation. Either {@link #HORIZONTAL} or {@link #VERTICAL}
      */
+    @RecyclerView.Orientation
     int mOrientation;
 
     /**
@@ -163,7 +163,8 @@
      *                      #VERTICAL}.
      * @param reverseLayout When set to true, layouts from end to start.
      */
-    public LinearLayoutManager(Context context, int orientation, boolean reverseLayout) {
+    public LinearLayoutManager(Context context, @RecyclerView.Orientation int orientation,
+            boolean reverseLayout) {
         setOrientation(orientation);
         setReverseLayout(reverseLayout);
         setAutoMeasureEnabled(true);
@@ -319,6 +320,7 @@
      * @return Current orientation,  either {@link #HORIZONTAL} or {@link #VERTICAL}
      * @see #setOrientation(int)
      */
+    @RecyclerView.Orientation
     public int getOrientation() {
         return mOrientation;
     }
@@ -329,7 +331,7 @@
      *
      * @param orientation {@link #HORIZONTAL} or {@link #VERTICAL}
      */
-    public void setOrientation(int orientation) {
+    public void setOrientation(@RecyclerView.Orientation int orientation) {
         if (orientation != HORIZONTAL && orientation != VERTICAL) {
             throw new IllegalArgumentException("invalid orientation:" + orientation);
         }
diff --git a/v7/recyclerview/src/android/support/v7/widget/OrientationHelper.java b/v7/recyclerview/src/android/support/v7/widget/OrientationHelper.java
index 8987b9c..5e90f2e 100644
--- a/v7/recyclerview/src/android/support/v7/widget/OrientationHelper.java
+++ b/v7/recyclerview/src/android/support/v7/widget/OrientationHelper.java
@@ -18,7 +18,6 @@
 
 import android.graphics.Rect;
 import android.view.View;
-import android.widget.LinearLayout;
 
 /**
  * Helper class for LayoutManagers to abstract measurements depending on the View's orientation.
@@ -36,9 +35,9 @@
 
     protected final RecyclerView.LayoutManager mLayoutManager;
 
-    public static final int HORIZONTAL = LinearLayout.HORIZONTAL;
+    public static final int HORIZONTAL = RecyclerView.HORIZONTAL;
 
-    public static final int VERTICAL = LinearLayout.VERTICAL;
+    public static final int VERTICAL = RecyclerView.VERTICAL;
 
     private int mLastTotalSpace = INVALID_SIZE;
 
@@ -230,7 +229,7 @@
      * @return A new OrientationHelper
      */
     public static OrientationHelper createOrientationHelper(
-            RecyclerView.LayoutManager layoutManager, int orientation) {
+            RecyclerView.LayoutManager layoutManager, @RecyclerView.Orientation int orientation) {
         switch (orientation) {
             case HORIZONTAL:
                 return createHorizontalHelper(layoutManager);
diff --git a/v7/recyclerview/src/android/support/v7/widget/RecyclerView.java b/v7/recyclerview/src/android/support/v7/widget/RecyclerView.java
index 9978adc..dea8546 100644
--- a/v7/recyclerview/src/android/support/v7/widget/RecyclerView.java
+++ b/v7/recyclerview/src/android/support/v7/widget/RecyclerView.java
@@ -73,6 +73,7 @@
 import android.view.accessibility.AccessibilityManager;
 import android.view.animation.Interpolator;
 import android.widget.EdgeEffect;
+import android.widget.LinearLayout;
 import android.widget.OverScroller;
 
 import java.lang.annotation.Retention;
@@ -205,8 +206,15 @@
     private static final boolean IGNORE_DETACHED_FOCUSED_CHILD = Build.VERSION.SDK_INT <= 15;
 
     static final boolean DISPATCH_TEMP_DETACH = false;
-    public static final int HORIZONTAL = 0;
-    public static final int VERTICAL = 1;
+
+    /** @hide */
+    @RestrictTo(LIBRARY_GROUP)
+    @IntDef({HORIZONTAL, VERTICAL})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface Orientation {}
+
+    public static final int HORIZONTAL = LinearLayout.HORIZONTAL;
+    public static final int VERTICAL = LinearLayout.VERTICAL;
 
     public static final int NO_POSITION = -1;
     public static final long NO_ID = -1;
diff --git a/wear/tests/src/android/support/wear/widget/RoundedDrawableTest.java b/wear/tests/src/android/support/wear/widget/RoundedDrawableTest.java
index 82027f7..21aee7b 100644
--- a/wear/tests/src/android/support/wear/widget/RoundedDrawableTest.java
+++ b/wear/tests/src/android/support/wear/widget/RoundedDrawableTest.java
@@ -32,10 +32,12 @@
 import android.graphics.Rect;
 import android.graphics.RectF;
 import android.graphics.drawable.BitmapDrawable;
+import android.os.Build;
 import android.support.test.filters.SmallTest;
 import android.support.test.rule.ActivityTestRule;
 import android.support.test.runner.AndroidJUnit4;
 import android.support.wear.test.R;
+import android.support.test.filters.SdkSuppress;
 
 import org.junit.Before;
 import org.junit.Rule;
@@ -129,9 +131,11 @@
     }
 
     @Test
+    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.N)
     public void inflate() {
-        RoundedDrawable roundedDrawable = (RoundedDrawable) mActivityRule.getActivity().getDrawable(
-                R.drawable.rounded_drawable);
+        RoundedDrawable roundedDrawable =
+                (RoundedDrawable) mActivityRule.getActivity().getDrawable(
+                        R.drawable.rounded_drawable);
         assertEquals(
                 mActivityRule.getActivity().getColor(R.color.rounded_drawable_background_color),
                 roundedDrawable.getBackgroundColor());