am 83de2e82: Merge "Leanback: use SingleRow for most widgets" into lmp-mr1-ub-dev
* commit '83de2e82354859ce689e9bb253298f58ecbd69a2':
Leanback: use SingleRow for most widgets
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/Grid.java b/v17/leanback/src/android/support/v17/leanback/widget/Grid.java
index 5ebc4a6..ff09d7c 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/Grid.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/Grid.java
@@ -19,11 +19,9 @@
import java.io.PrintWriter;
/**
- * A grid is representation of multiple row layout data structure and algorithm.
- * Grid is the base class for both staggered case or simple non-staggered case.
+ * A grid is representation of single or multiple rows layout data structure and algorithm.
+ * Grid is the base class for single row, non-staggered grid and staggered grid.
* <p>
- * User calls Grid.createStaggeredMutipleRows() to create an staggered instance.
- * TODO add createNonStaggeredRows().
* To use the Grid, user must implement a Provider to create or remove visible item.
* Grid maintains a list of visible items. Visible items are created when
* user calls appendVisibleItems() or prependVisibleItems() with certain limitation
@@ -121,11 +119,17 @@
protected int mStartIndex = START_DEFAULT;
/**
- * Creates a multiple rows staggered grid.
+ * Creates a single or multiple rows (can be staggered or not staggered) grid
*/
- public static Grid createStaggeredMultipleRows(int rows) {
- StaggeredGridDefault grid = new StaggeredGridDefault();
- grid.setNumRows(rows);
+ public static Grid createGrid(int rows) {
+ Grid grid;
+ if (rows == 1) {
+ grid = new SingleRow();
+ } else {
+ // TODO support non staggered multiple rows grid
+ grid = new StaggeredGridDefault();
+ grid.setNumRows(rows);
+ }
return grid;
}
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 5719061..8e79dfe 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/GridLayoutManager.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/GridLayoutManager.java
@@ -1044,7 +1044,7 @@
if (mGrid == null || mNumRows != mGrid.getNumRows() ||
mReverseFlowPrimary != mGrid.isReversedFlow()) {
- mGrid = Grid.createStaggeredMultipleRows(mNumRows);
+ mGrid = Grid.createGrid(mNumRows);
mGrid.setProvider(mGridProvider);
mGrid.setReversedFlow(mReverseFlowPrimary);
}
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/SingleRow.java b/v17/leanback/src/android/support/v17/leanback/widget/SingleRow.java
new file mode 100644
index 0000000..52666ac
--- /dev/null
+++ b/v17/leanback/src/android/support/v17/leanback/widget/SingleRow.java
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package android.support.v17.leanback.widget;
+
+import android.support.v4.util.CircularIntArray;
+
+import java.io.PrintWriter;
+
+/**
+ * A Grid with restriction to single row.
+ */
+class SingleRow extends Grid {
+
+ private final Location mTmpLocation = new Location(0);
+ private Object[] mTmpItem = new Object[1];
+
+ SingleRow() {
+ setNumRows(1);
+ }
+
+ @Override
+ public final Location getLocation(int index) {
+ // all items are on row 0, share the same Location object.
+ return mTmpLocation;
+ }
+
+ @Override
+ public final void debugPrint(PrintWriter pw) {
+ pw.print("SingleRow<");
+ pw.print(mFirstVisibleIndex);
+ pw.print(",");
+ pw.print(mLastVisibleIndex);
+ pw.print(">");
+ pw.println();
+ }
+
+ int getStartIndexForAppend() {
+ if (mLastVisibleIndex >= 0) {
+ return mLastVisibleIndex + 1;
+ } else if (mStartIndex != START_DEFAULT) {
+ return Math.min(mStartIndex, mProvider.getCount() - 1);
+ } else {
+ return 0;
+ }
+ }
+
+ int getStartIndexForPrepend() {
+ if (mFirstVisibleIndex >= 0) {
+ return mFirstVisibleIndex - 1;
+ } else if (mStartIndex != START_DEFAULT) {
+ return Math.min(mStartIndex, mProvider.getCount() - 1);
+ } else {
+ return mProvider.getCount() - 1;
+ }
+ }
+
+ @Override
+ protected final boolean prependVisibleItems(int toLimit, boolean oneColumnMode) {
+ if (mProvider.getCount() == 0) {
+ return false;
+ }
+ if (!oneColumnMode && checkPrependOverLimit(toLimit)) {
+ return false;
+ }
+ boolean filledOne = false;
+ for (int index = getStartIndexForPrepend(); index >= 0; index--) {
+ int size = mProvider.createItem(index, false, mTmpItem);
+ int edge;
+ if (mFirstVisibleIndex < 0 || mLastVisibleIndex < 0) {
+ edge = mReversedFlow ? Integer.MIN_VALUE : Integer.MAX_VALUE;
+ mLastVisibleIndex = mFirstVisibleIndex = index;
+ } else {
+ if (mReversedFlow) {
+ edge = mProvider.getEdge(index + 1) + mMargin + size;
+ } else {
+ edge = mProvider.getEdge(index + 1) - mMargin - size;
+ }
+ mFirstVisibleIndex = index;
+ }
+ mProvider.addItem(mTmpItem[0], index, size, 0, edge);
+ filledOne = true;
+ if (oneColumnMode || checkPrependOverLimit(toLimit)) {
+ break;
+ }
+ }
+ return filledOne;
+ }
+
+ @Override
+ protected final boolean appendVisibleItems(int toLimit, boolean oneColumnMode) {
+ if (mProvider.getCount() == 0) {
+ return false;
+ }
+ if (!oneColumnMode && checkAppendOverLimit(toLimit)) {
+ // not in one column mode, return immediately if over limit
+ return false;
+ }
+ boolean filledOne = false;
+ for (int index = getStartIndexForAppend(); index < mProvider.getCount(); index++) {
+ int size = mProvider.createItem(index, true, mTmpItem);
+ int edge;
+ if (mFirstVisibleIndex < 0 || mLastVisibleIndex< 0) {
+ edge = mReversedFlow ? Integer.MAX_VALUE : Integer.MIN_VALUE;
+ mLastVisibleIndex = mFirstVisibleIndex = index;
+ } else {
+ if (mReversedFlow) {
+ edge = mProvider.getEdge(index - 1) - mProvider.getSize(index - 1) - mMargin;
+ } else {
+ edge = mProvider.getEdge(index - 1) + mProvider.getSize(index - 1) + mMargin;
+ }
+ mLastVisibleIndex = index;
+ }
+ mProvider.addItem(mTmpItem[0], index, size, 0, edge);
+ filledOne = true;
+ if (oneColumnMode || checkAppendOverLimit(toLimit)) {
+ break;
+ }
+ }
+ return filledOne;
+ }
+
+ @Override
+ public final CircularIntArray[] getItemPositionsInRows(int startPos, int endPos) {
+ // all items are on the same row:
+ mTmpItemPositionsInRows[0].clear();
+ mTmpItemPositionsInRows[0].addLast(startPos);
+ mTmpItemPositionsInRows[0].addLast(endPos);
+ return mTmpItemPositionsInRows;
+ }
+
+ @Override
+ protected final int findRowMin(boolean findLarge, int indexLimit, int[] indices) {
+ if (indices != null) {
+ indices[0] = 0;
+ indices[1] = indexLimit;
+ }
+ return mReversedFlow ? mProvider.getEdge(indexLimit) - mProvider.getSize(indexLimit)
+ : mProvider.getEdge(indexLimit);
+ }
+
+ @Override
+ protected final int findRowMax(boolean findLarge, int indexLimit, int[] indices) {
+ if (indices != null) {
+ indices[0] = 0;
+ indices[1] = indexLimit;
+ }
+ return mReversedFlow ? mProvider.getEdge(indexLimit)
+ : mProvider.getEdge(indexLimit) + mProvider.getSize(indexLimit);
+ }
+
+}
diff --git a/v17/tests/src/android/support/v17/leanback/widget/SingleRowTest.java b/v17/tests/src/android/support/v17/leanback/widget/SingleRowTest.java
new file mode 100644
index 0000000..43b0a29
--- /dev/null
+++ b/v17/tests/src/android/support/v17/leanback/widget/SingleRowTest.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.support.v17.leanback.widget;
+
+/**
+ * Testing SingleRow algorithm
+ * @hide
+ */
+public class SingleRowTest extends GridTest {
+
+ SingleRow mSingleRow;
+
+ public void testAppendPrependRemove() throws Throwable {
+ mProvider = new Provider(new int[]{80, 80, 30, 100, 40, 10});
+
+ mSingleRow = new SingleRow();
+ mSingleRow.setMargin(20);
+ mSingleRow.setProvider(mProvider);
+ mSingleRow.appendVisibleItems(200);
+ assertEquals(dump(mSingleRow) + " Should filled 2 items", 1, mSingleRow.mLastVisibleIndex);
+
+ mSingleRow.appendVisibleItems(201);
+ assertEquals(dump(mSingleRow) + " Should filled 3 items",
+ 2, mSingleRow.mLastVisibleIndex);
+
+ mSingleRow.appendVisibleItems(251);
+ assertEquals(dump(mSingleRow) + " Should filled 4 items",
+ 3, mSingleRow.mLastVisibleIndex);
+
+ mSingleRow.appendVisibleItems(Integer.MAX_VALUE);
+ assertEquals(dump(mSingleRow) + " Should filled 6 items",
+ 5, mSingleRow.mLastVisibleIndex);
+ assertEquals(mProvider.getEdge(0), 0);
+ assertEquals(mProvider.getEdge(1), 100);
+ assertEquals(mProvider.getEdge(2), 200);
+ assertEquals(mProvider.getEdge(3), 250);
+ assertEquals(mProvider.getEdge(4), 370);
+ assertEquals(mProvider.getEdge(5), 430);
+
+ mSingleRow.removeInvisibleItemsAtEnd(0, 200);
+ assertEquals(dump(mSingleRow) + " Should filled 2 items", 1, mSingleRow.mLastVisibleIndex);
+
+ mSingleRow.appendVisibleItems(Integer.MAX_VALUE);
+ assertEquals(dump(mSingleRow) + " Should filled 6 items",
+ 5, mSingleRow.mLastVisibleIndex);
+
+ mSingleRow.removeInvisibleItemsAtFront(1000, 80);
+ assertEquals(dump(mSingleRow) + " visible index should start from 1",
+ 1, mSingleRow.mFirstVisibleIndex);
+
+ mSingleRow.prependVisibleItems(0);
+ assertEquals(dump(mSingleRow) + " visible index should start from 0",
+ 0, mSingleRow.mFirstVisibleIndex);
+ }
+
+ public void testAppendPrependRemoveReversed() throws Throwable {
+ mProvider = new Provider(new int[]{80, 80, 30, 100, 40, 10});
+
+ mSingleRow = new SingleRow();
+ mSingleRow.setMargin(20);
+ mSingleRow.setProvider(mProvider);
+ mSingleRow.setReversedFlow(true);
+ mSingleRow.appendVisibleItems(-200);
+ assertEquals(dump(mSingleRow) + " Should filled 2 items", 1, mSingleRow.mLastVisibleIndex);
+
+ mSingleRow.appendVisibleItems(-201);
+ assertEquals(dump(mSingleRow) + " Should filled 3 items",
+ 2, mSingleRow.mLastVisibleIndex);
+
+ mSingleRow.appendVisibleItems(-251);
+ assertEquals(dump(mSingleRow) + " Should filled 4 items",
+ 3, mSingleRow.mLastVisibleIndex);
+
+ mSingleRow.appendVisibleItems(Integer.MIN_VALUE);
+ assertEquals(dump(mSingleRow) + " Should filled 6 items",
+ 5, mSingleRow.mLastVisibleIndex);
+ assertEquals(mProvider.getEdge(0), 0);
+ assertEquals(mProvider.getEdge(1), -100);
+ assertEquals(mProvider.getEdge(2), -200);
+ assertEquals(mProvider.getEdge(3), -250);
+ assertEquals(mProvider.getEdge(4), -370);
+ assertEquals(mProvider.getEdge(5), -430);
+
+ mSingleRow.removeInvisibleItemsAtEnd(0, -200);
+ assertEquals(dump(mSingleRow) + " Should filled 2 items", 1, mSingleRow.mLastVisibleIndex);
+
+ mSingleRow.appendVisibleItems(Integer.MIN_VALUE);
+ assertEquals(dump(mSingleRow) + " Should filled 6 items",
+ 5, mSingleRow.mLastVisibleIndex);
+
+ mSingleRow.removeInvisibleItemsAtFront(1000, -80);
+ assertEquals(dump(mSingleRow) + " Should filled 6 items",
+ 1, mSingleRow.mFirstVisibleIndex);
+ }
+}