Merge "Added descriptions for and renamed fields and methods related to deferring or ignoring nested calls to requestLayout.  I personally found that the names and lack of descriptions made it hard to follow the logic and meaning of the code." into oc-mr1-jetpack-dev
diff --git a/leanback/src/android/support/v17/leanback/widget/GridLayoutManager.java b/leanback/src/android/support/v17/leanback/widget/GridLayoutManager.java
index 9d159ec..613198f 100644
--- a/leanback/src/android/support/v17/leanback/widget/GridLayoutManager.java
+++ b/leanback/src/android/support/v17/leanback/widget/GridLayoutManager.java
@@ -22,6 +22,7 @@
 import android.content.Context;
 import android.graphics.PointF;
 import android.graphics.Rect;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -3655,7 +3656,32 @@
     public boolean performAccessibilityAction(Recycler recycler, State state, int action,
             Bundle args) {
         saveContext(recycler, state);
-        switch (action) {
+        int translatedAction = action;
+        boolean reverseFlowPrimary = (mFlag & PF_REVERSE_FLOW_PRIMARY) != 0;
+        if (Build.VERSION.SDK_INT >= 23) {
+            if (mOrientation == HORIZONTAL) {
+                if (action == AccessibilityNodeInfoCompat.AccessibilityActionCompat
+                        .ACTION_SCROLL_LEFT.getId()) {
+                    translatedAction = reverseFlowPrimary
+                            ? AccessibilityNodeInfoCompat.ACTION_SCROLL_FORWARD :
+                            AccessibilityNodeInfoCompat.ACTION_SCROLL_BACKWARD;
+                } else if (action == AccessibilityNodeInfoCompat.AccessibilityActionCompat
+                        .ACTION_SCROLL_RIGHT.getId()) {
+                    translatedAction = reverseFlowPrimary
+                            ? AccessibilityNodeInfoCompat.ACTION_SCROLL_BACKWARD :
+                            AccessibilityNodeInfoCompat.ACTION_SCROLL_FORWARD;
+                }
+            } else { // VERTICAL layout
+                if (action == AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_UP
+                        .getId()) {
+                    translatedAction = AccessibilityNodeInfoCompat.ACTION_SCROLL_BACKWARD;
+                } else if (action == AccessibilityNodeInfoCompat.AccessibilityActionCompat
+                        .ACTION_SCROLL_DOWN.getId()) {
+                    translatedAction = AccessibilityNodeInfoCompat.ACTION_SCROLL_FORWARD;
+                }
+            }
+        }
+        switch (translatedAction) {
             case AccessibilityNodeInfoCompat.ACTION_SCROLL_BACKWARD:
                 processSelectionMoves(false, -1);
                 break;
@@ -3726,12 +3752,39 @@
             AccessibilityNodeInfoCompat info) {
         saveContext(recycler, state);
         int count = state.getItemCount();
-        if ((mFlag & PF_SCROLL_ENABLED) != 0 && count > 1 && !isItemFullyVisible(0)) {
-            info.addAction(AccessibilityNodeInfoCompat.ACTION_SCROLL_BACKWARD);
+        boolean reverseFlowPrimary = (mFlag & PF_REVERSE_FLOW_PRIMARY) != 0;
+        if (count > 1 && !isItemFullyVisible(0)) {
+            if (Build.VERSION.SDK_INT >= 23) {
+                if (mOrientation == HORIZONTAL) {
+                    info.addAction(reverseFlowPrimary
+                            ? AccessibilityNodeInfoCompat.AccessibilityActionCompat
+                                    .ACTION_SCROLL_RIGHT :
+                            AccessibilityNodeInfoCompat.AccessibilityActionCompat
+                                    .ACTION_SCROLL_LEFT);
+                } else {
+                    info.addAction(
+                            AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_UP);
+                }
+            } else {
+                info.addAction(AccessibilityNodeInfoCompat.ACTION_SCROLL_BACKWARD);
+            }
             info.setScrollable(true);
         }
-        if ((mFlag & PF_SCROLL_ENABLED) != 0 && count > 1 && !isItemFullyVisible(count - 1)) {
-            info.addAction(AccessibilityNodeInfoCompat.ACTION_SCROLL_FORWARD);
+        if (count > 1 && !isItemFullyVisible(count - 1)) {
+            if (Build.VERSION.SDK_INT >= 23) {
+                if (mOrientation == HORIZONTAL) {
+                    info.addAction(reverseFlowPrimary
+                            ? AccessibilityNodeInfoCompat.AccessibilityActionCompat
+                                    .ACTION_SCROLL_LEFT :
+                            AccessibilityNodeInfoCompat.AccessibilityActionCompat
+                                    .ACTION_SCROLL_RIGHT);
+                } else {
+                    info.addAction(AccessibilityNodeInfoCompat.AccessibilityActionCompat
+                                    .ACTION_SCROLL_DOWN);
+                }
+            } else {
+                info.addAction(AccessibilityNodeInfoCompat.ACTION_SCROLL_FORWARD);
+            }
             info.setScrollable(true);
         }
         final AccessibilityNodeInfoCompat.CollectionInfoCompat collectionInfo =
diff --git a/leanback/tests/java/android/support/v17/leanback/widget/GridWidgetTest.java b/leanback/tests/java/android/support/v17/leanback/widget/GridWidgetTest.java
index 7bf96a5..4548494 100644
--- a/leanback/tests/java/android/support/v17/leanback/widget/GridWidgetTest.java
+++ b/leanback/tests/java/android/support/v17/leanback/widget/GridWidgetTest.java
@@ -4312,6 +4312,252 @@
         waitForScrollIdle(mVerifyLayout);
         assertEquals(1, mGridView.getSelectedPosition());
     }
+    @Test
+    public void testAccessibilityRespondToLeftRight() throws Throwable {
+        Intent intent = new Intent();
+        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, R.layout.horizontal_linear);
+        intent.putExtra(GridActivity.EXTRA_CHILD_LAYOUT_ID, R.layout.item_button_at_bottom);
+        intent.putExtra(GridActivity.EXTRA_ITEMS,  new int[]{});
+        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
+        initActivity(intent);
+        mOrientation = BaseGridView.HORIZONTAL;
+        mNumRows = 1;
+
+        int width = mGridView.getWidth() - mGridView.getPaddingLeft()
+                - mGridView.getPaddingRight();
+        final int childWidth = width - mGridView.getHorizontalSpacing() - 500;
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mGridView.setWindowAlignment(BaseGridView.WINDOW_ALIGN_NO_EDGE);
+                mGridView.setWindowAlignmentOffset(100);
+                mGridView.setWindowAlignmentOffsetPercent(BaseGridView
+                        .WINDOW_ALIGN_OFFSET_PERCENT_DISABLED);
+                mGridView.setItemAlignmentOffset(0);
+                mGridView.setItemAlignmentOffsetPercent(BaseGridView
+                        .ITEM_ALIGN_OFFSET_PERCENT_DISABLED);
+            }
+        });
+        mActivity.addItems(0, new int[]{childWidth, childWidth});
+        waitForItemAnimation();
+        setSelectedPosition(1);
+        final RecyclerViewAccessibilityDelegate delegateCompat = mGridView
+                .getCompatAccessibilityDelegate();
+        final AccessibilityNodeInfoCompat info = AccessibilityNodeInfoCompat.obtain();
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                delegateCompat.onInitializeAccessibilityNodeInfo(mGridView, info);
+            }
+        });
+        assertTrue("test sanity", info.isScrollable());
+        if (Build.VERSION.SDK_INT >= 23) {
+            assertTrue("test sanity", info.removeAction(AccessibilityNodeInfoCompat
+                    .AccessibilityActionCompat.ACTION_SCROLL_LEFT));
+        } else {
+            assertTrue("test sanity", info.removeAction(AccessibilityNodeInfoCompat
+                    .AccessibilityActionCompat.ACTION_SCROLL_BACKWARD));
+        }
+
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                if (Build.VERSION.SDK_INT >= 23) {
+                    delegateCompat.performAccessibilityAction(mGridView, AccessibilityNodeInfoCompat
+                            .AccessibilityActionCompat.ACTION_SCROLL_LEFT.getId(), null);
+                } else {
+                    delegateCompat.performAccessibilityAction(mGridView, AccessibilityNodeInfoCompat
+                            .ACTION_SCROLL_BACKWARD, null);
+                }
+            }
+        });
+        waitForScrollIdle(mVerifyLayout);
+        assertEquals(0, mGridView.getSelectedPosition());
+        setSelectedPosition(0);
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                delegateCompat.onInitializeAccessibilityNodeInfo(mGridView, info);
+            }
+        });
+        if (Build.VERSION.SDK_INT >= 23) {
+            assertTrue("test sanity", info.removeAction(AccessibilityNodeInfoCompat
+                    .AccessibilityActionCompat.ACTION_SCROLL_RIGHT));
+        } else {
+            assertTrue("test sanity", info.removeAction(AccessibilityNodeInfoCompat
+                    .AccessibilityActionCompat.ACTION_SCROLL_FORWARD));
+        }
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                if (Build.VERSION.SDK_INT >= 23) {
+                    delegateCompat.performAccessibilityAction(mGridView, AccessibilityNodeInfoCompat
+                            .AccessibilityActionCompat.ACTION_SCROLL_RIGHT.getId(), null);
+                } else {
+                    delegateCompat.performAccessibilityAction(mGridView, AccessibilityNodeInfoCompat
+                            .ACTION_SCROLL_FORWARD, null);
+                }
+            }
+        });
+        waitForScrollIdle(mVerifyLayout);
+        assertEquals(1, mGridView.getSelectedPosition());
+    }
+
+    @Test
+    public void testAccessibilityRespondToLeftRightRtl() throws Throwable {
+        Intent intent = new Intent();
+        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, R.layout.horizontal_linear_rtl);
+        intent.putExtra(GridActivity.EXTRA_CHILD_LAYOUT_ID, R.layout.item_button_at_bottom);
+        intent.putExtra(GridActivity.EXTRA_ITEMS,  new int[]{});
+        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
+        initActivity(intent);
+        mOrientation = BaseGridView.HORIZONTAL;
+        mNumRows = 1;
+
+        int width = mGridView.getWidth() - mGridView.getPaddingLeft()
+                - mGridView.getPaddingRight();
+        final int childWidth = width - mGridView.getHorizontalSpacing() - 500;
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mGridView.setLayoutDirection(View.LAYOUT_DIRECTION_RTL);
+                mGridView.setWindowAlignment(BaseGridView.WINDOW_ALIGN_NO_EDGE);
+                mGridView.setWindowAlignmentOffset(100);
+                mGridView.setWindowAlignmentOffsetPercent(BaseGridView
+                        .WINDOW_ALIGN_OFFSET_PERCENT_DISABLED);
+                mGridView.setItemAlignmentOffset(0);
+                mGridView.setItemAlignmentOffsetPercent(BaseGridView
+                        .ITEM_ALIGN_OFFSET_PERCENT_DISABLED);
+            }
+        });
+        mActivity.addItems(0, new int[]{childWidth, childWidth});
+        waitForItemAnimation();
+        setSelectedPosition(1);
+        final RecyclerViewAccessibilityDelegate delegateCompat = mGridView
+                .getCompatAccessibilityDelegate();
+        final AccessibilityNodeInfoCompat info = AccessibilityNodeInfoCompat.obtain();
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                delegateCompat.onInitializeAccessibilityNodeInfo(mGridView, info);
+            }
+        });
+        assertTrue("test sanity", info.isScrollable());
+        if (Build.VERSION.SDK_INT >= 23) {
+            assertTrue("test sanity", info.removeAction(AccessibilityNodeInfoCompat
+                    .AccessibilityActionCompat.ACTION_SCROLL_RIGHT));
+        } else {
+            assertTrue("test sanity", info.removeAction(AccessibilityNodeInfoCompat
+                    .AccessibilityActionCompat.ACTION_SCROLL_BACKWARD));
+        }
+
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                if (Build.VERSION.SDK_INT >= 23) {
+                    delegateCompat.performAccessibilityAction(mGridView, AccessibilityNodeInfoCompat
+                            .AccessibilityActionCompat.ACTION_SCROLL_RIGHT.getId(), null);
+                } else {
+                    delegateCompat.performAccessibilityAction(mGridView, AccessibilityNodeInfoCompat
+                            .ACTION_SCROLL_BACKWARD, null);
+                }
+            }
+        });
+        waitForScrollIdle(mVerifyLayout);
+        assertEquals(0, mGridView.getSelectedPosition());
+        setSelectedPosition(0);
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                delegateCompat.onInitializeAccessibilityNodeInfo(mGridView, info);
+            }
+        });
+        if (Build.VERSION.SDK_INT >= 23) {
+            assertTrue("test sanity", info.removeAction(AccessibilityNodeInfoCompat
+                    .AccessibilityActionCompat.ACTION_SCROLL_LEFT));
+        } else {
+            assertTrue("test sanity", info.removeAction(AccessibilityNodeInfoCompat
+                    .AccessibilityActionCompat.ACTION_SCROLL_FORWARD));
+        }
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                if (Build.VERSION.SDK_INT >= 23) {
+                    delegateCompat.performAccessibilityAction(mGridView, AccessibilityNodeInfoCompat
+                            .AccessibilityActionCompat.ACTION_SCROLL_LEFT.getId(), null);
+                } else {
+                    delegateCompat.performAccessibilityAction(mGridView, AccessibilityNodeInfoCompat
+                            .ACTION_SCROLL_FORWARD, null);
+                }
+            }
+        });
+        waitForScrollIdle(mVerifyLayout);
+        assertEquals(1, mGridView.getSelectedPosition());
+    }
+
+    @Test
+    public void testAccessibilityRespondToScrollUpAction() throws Throwable {
+        Intent intent = new Intent();
+        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, R.layout.vertical_linear);
+        intent.putExtra(GridActivity.EXTRA_CHILD_LAYOUT_ID, R.layout.item_button_at_bottom);
+        intent.putExtra(GridActivity.EXTRA_ITEMS,  new int[]{});
+        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
+        initActivity(intent);
+        mOrientation = BaseGridView.VERTICAL;
+        mNumRows = 1;
+
+        int height = mGridView.getHeight() - mGridView.getPaddingTop()
+                - mGridView.getPaddingBottom();
+        final int childHeight = height - mGridView.getVerticalSpacing() - 100;
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mGridView.setWindowAlignment(BaseGridView.WINDOW_ALIGN_NO_EDGE);
+                mGridView.setWindowAlignmentOffset(100);
+                mGridView.setWindowAlignmentOffsetPercent(BaseGridView
+                        .WINDOW_ALIGN_OFFSET_PERCENT_DISABLED);
+                mGridView.setItemAlignmentOffset(0);
+                mGridView.setItemAlignmentOffsetPercent(BaseGridView
+                        .ITEM_ALIGN_OFFSET_PERCENT_DISABLED);
+            }
+        });
+        mActivity.addItems(0, new int[]{childHeight, childHeight});
+        waitForItemAnimation();
+        setSelectedPosition(1);
+
+        final RecyclerViewAccessibilityDelegate delegateCompat = mGridView
+                .getCompatAccessibilityDelegate();
+        final AccessibilityNodeInfoCompat info = AccessibilityNodeInfoCompat.obtain();
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                delegateCompat.onInitializeAccessibilityNodeInfo(mGridView, info);
+            }
+        });
+        assertTrue("test sanity", info.isScrollable());
+        if (Build.VERSION.SDK_INT >= 23) {
+            assertTrue("test sanity", info.removeAction(AccessibilityNodeInfoCompat
+                    .AccessibilityActionCompat.ACTION_SCROLL_UP));
+        } else {
+            assertTrue("test sanity", info.removeAction(AccessibilityNodeInfoCompat
+                    .AccessibilityActionCompat.ACTION_SCROLL_BACKWARD));
+        }
+
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                if (Build.VERSION.SDK_INT >= 23) {
+                    delegateCompat.performAccessibilityAction(mGridView, AccessibilityNodeInfoCompat
+                            .AccessibilityActionCompat.ACTION_SCROLL_UP.getId(), null);
+                } else {
+                    delegateCompat.performAccessibilityAction(mGridView, AccessibilityNodeInfoCompat
+                            .ACTION_SCROLL_BACKWARD, null);
+                }
+            }
+        });
+        waitForScrollIdle(mVerifyLayout);
+        assertEquals(0, mGridView.getSelectedPosition());
+    }
 
     @Test
     public void testAccessibilityScrollBackwardHalfVisible() throws Throwable {
diff --git a/room/compiler/src/test/kotlin/android/arch/persistence/room/processor/PojoProcessorTest.kt b/room/compiler/src/test/kotlin/android/arch/persistence/room/processor/PojoProcessorTest.kt
index bf34b4c..97cfe74 100644
--- a/room/compiler/src/test/kotlin/android/arch/persistence/room/processor/PojoProcessorTest.kt
+++ b/room/compiler/src/test/kotlin/android/arch/persistence/room/processor/PojoProcessorTest.kt
@@ -552,7 +552,7 @@
     }
 
     @Test
-    fun constructor_ambiguous_twoFieldsExcatMatch() {
+    fun constructor_ambiguous_twoFieldsExactMatch() {
         val pojoCode = """
             public String mName;
             public String _name;
@@ -708,6 +708,18 @@
                 ProcessorErrors.TOO_MANY_POJO_CONSTRUCTORS_CHOOSING_NO_ARG)
     }
 
+    @Test // added for b/69562125
+    fun constructor_withNullabilityAnnotation() {
+        singleRun("""
+            String mName;
+            public MyPojo(@android.support.annotation.NonNull String name) {}
+            """) { pojo ->
+            val constructor = pojo.constructor
+            assertThat(constructor, notNullValue())
+            assertThat(constructor!!.params.size, `is`(1))
+        }.compilesWithoutError()
+    }
+
     @Test
     fun recursion_1Level() {
         singleRun(
diff --git a/room/integration-tests/testapp/src/androidTest/java/android/arch/persistence/room/integration/testapp/test/ConstructorTest.java b/room/integration-tests/testapp/src/androidTest/java/android/arch/persistence/room/integration/testapp/test/ConstructorTest.java
index 7a21d98..46c875c 100644
--- a/room/integration-tests/testapp/src/androidTest/java/android/arch/persistence/room/integration/testapp/test/ConstructorTest.java
+++ b/room/integration-tests/testapp/src/androidTest/java/android/arch/persistence/room/integration/testapp/test/ConstructorTest.java
@@ -28,6 +28,8 @@
 import android.arch.persistence.room.Query;
 import android.arch.persistence.room.Room;
 import android.arch.persistence.room.RoomDatabase;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
 import android.support.test.InstrumentationRegistry;
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
@@ -40,7 +42,8 @@
 @SuppressWarnings("SqlNoDataSourceInspection")
 @SmallTest
 public class ConstructorTest {
-    @Database(version = 1, entities = {FullConstructor.class, PartialConstructor.class},
+    @Database(version = 1, entities = {FullConstructor.class, PartialConstructor.class,
+            EntityWithAnnotations.class},
             exportSchema = false)
     abstract static class MyDb extends RoomDatabase {
         abstract MyDao dao();
@@ -59,6 +62,12 @@
 
         @Query("SELECT * FROM pc WHERE a = :a")
         PartialConstructor loadPartial(int a);
+
+        @Insert
+        void insertEntityWithAnnotations(EntityWithAnnotations... items);
+
+        @Query("SELECT * FROM EntityWithAnnotations")
+        EntityWithAnnotations getEntitiWithAnnotations();
     }
 
     @SuppressWarnings("WeakerAccess")
@@ -167,6 +176,50 @@
         }
     }
 
+    @SuppressWarnings("WeakerAccess")
+    @Entity
+    static class EntityWithAnnotations {
+        @PrimaryKey
+        @NonNull
+        public final String id;
+
+        @NonNull
+        public final String username;
+
+        @Nullable
+        public final String displayName;
+
+        EntityWithAnnotations(
+                @NonNull String id,
+                @NonNull String username,
+                @Nullable String displayName) {
+            this.id = id;
+            this.username = username;
+            this.displayName = displayName;
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) return true;
+            if (o == null || getClass() != o.getClass()) return false;
+
+            EntityWithAnnotations that = (EntityWithAnnotations) o;
+
+            if (!id.equals(that.id)) return false;
+            if (!username.equals(that.username)) return false;
+            return displayName != null ? displayName.equals(that.displayName)
+                    : that.displayName == null;
+        }
+
+        @Override
+        public int hashCode() {
+            int result = id.hashCode();
+            result = 31 * result + username.hashCode();
+            result = 31 * result + (displayName != null ? displayName.hashCode() : 0);
+            return result;
+        }
+    }
+
     private MyDb mDb;
     private MyDao mDao;
 
@@ -193,4 +246,11 @@
         PartialConstructor load = mDao.loadPartial(3);
         assertThat(load, is(item));
     }
+
+    @Test // for bug b/69562125
+    public void entityWithAnnotations() {
+        EntityWithAnnotations item = new EntityWithAnnotations("a", "b", null);
+        mDao.insertEntityWithAnnotations(item);
+        assertThat(mDao.getEntitiWithAnnotations(), is(item));
+    }
 }