leanback DatePicker: fix range updates

Missing a notifyDataSetChange in scroll pass caused the mess, do the
updateSpinner in a post Runnable

Bug 27431465

Change-Id: I489b19645ee0934e15beb7dcb131f150b5cfa0d1
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/picker/DatePicker.java b/v17/leanback/src/android/support/v17/leanback/widget/picker/DatePicker.java
index b9cfc97..77b7665 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/picker/DatePicker.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/picker/DatePicker.java
@@ -345,7 +345,18 @@
         return false;
     }
 
-    private void updateSpinners(boolean animation) {
+    private void updateSpinners(final boolean animation) {
+        // update range in a post call.  The reason is that RV does not allow notifyDataSetChange()
+        // in scroll pass.  UpdateSpinner can be called in a scroll pass, UpdateSpinner() may
+        // notifyDataSetChange to update the range.
+        post(new Runnable() {
+            public void run() {
+                updateSpinnersImpl(animation);
+            }
+        });
+    }
+
+    private void updateSpinnersImpl(boolean animation) {
         // set the spinner ranges respecting the min and max dates
         boolean dayRangeChanged = false;
         boolean monthRangeChanged = false;
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/picker/Picker.java b/v17/leanback/src/android/support/v17/leanback/widget/picker/Picker.java
index 297d46c..1f35aae 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/picker/Picker.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/picker/Picker.java
@@ -217,7 +217,7 @@
 
     /**
      * When column labels change or column range changes, call this function to re-populate the
-     * selection list.
+     * selection list.  Note this function cannot be called from RecyclerView layout/scroll pass.
      * @param columnIndex Index of column to update.
      * @param column New column to update.
      */
@@ -225,7 +225,7 @@
         mColumns.set(columnIndex, column);
         VerticalGridView columnView = mColumnViews.get(columnIndex);
         PickerScrollArrayAdapter adapter = (PickerScrollArrayAdapter) columnView.getAdapter();
-        if (adapter != null && !columnView.isComputingLayout()) {
+        if (adapter != null) {
             adapter.notifyDataSetChanged();
         }
         columnView.setSelectedPosition(column.getCurrentValue() - column.getMinValue());
diff --git a/v17/tests/src/android/support/v17/leanback/widget/GridWidgetTest.java b/v17/tests/src/android/support/v17/leanback/widget/GridWidgetTest.java
index 0f55e66..513a74a 100644
--- a/v17/tests/src/android/support/v17/leanback/widget/GridWidgetTest.java
+++ b/v17/tests/src/android/support/v17/leanback/widget/GridWidgetTest.java
@@ -556,6 +556,63 @@
         verifyBeginAligned();
     }
 
+    public void testSetSelectedPositionDetached() throws Throwable {
+
+        mInstrumentation = getInstrumentation();
+        Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class);
+        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
+                R.layout.horizontal_linear);
+        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 50);
+        initActivity(intent);
+        mOrientation = BaseGridView.HORIZONTAL;
+        mNumRows = 1;
+
+        final int focusToIndex = 49;
+        final ViewGroup parent = (ViewGroup) mGridView.getParent();
+        runTestOnUiThread(new Runnable() {
+            public void run() {
+                parent.removeView(mGridView);
+            }
+        });
+        runTestOnUiThread(new Runnable() {
+            public void run() {
+                mGridView.setSelectedPositionSmooth(focusToIndex);
+            }
+        });
+        runTestOnUiThread(new Runnable() {
+            public void run() {
+                parent.addView(mGridView);
+                mGridView.requestFocus();
+            }
+        });
+        waitForTransientStateGone(null);
+        waitForScrollIdle();
+        assertEquals(mGridView.getSelectedPosition(), focusToIndex);
+        assertTrue(mGridView.getLayoutManager().findViewByPosition(focusToIndex).hasFocus());
+
+        final int focusToIndex2 = 0;
+        runTestOnUiThread(new Runnable() {
+            public void run() {
+                parent.removeView(mGridView);
+            }
+        });
+        runTestOnUiThread(new Runnable() {
+            public void run() {
+                mGridView.setSelectedPosition(focusToIndex2);
+            }
+        });
+        runTestOnUiThread(new Runnable() {
+            public void run() {
+                parent.addView(mGridView);
+                mGridView.requestFocus();
+            }
+        });
+        assertEquals(mGridView.getSelectedPosition(), focusToIndex2);
+        waitForTransientStateGone(null);
+        waitForScrollIdle();
+        assertTrue(mGridView.getLayoutManager().findViewByPosition(focusToIndex2).hasFocus());
+    }
+
     public void testBug22209986() throws Throwable {
 
         mInstrumentation = getInstrumentation();