1/* 2 * Copyright (C) 2015 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 * in compliance with the License. You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software distributed under the License 10 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 * or implied. See the License for the specific language governing permissions and limitations under 12 * the License. 13 */ 14package android.support.v17.leanback.widget; 15 16import android.support.annotation.NonNull; 17import android.support.v4.util.CircularIntArray; 18import android.support.v7.widget.RecyclerView; 19 20import java.io.PrintWriter; 21 22/** 23 * A Grid with restriction to single row. 24 */ 25class SingleRow extends Grid { 26 27 private final Location mTmpLocation = new Location(0); 28 29 SingleRow() { 30 setNumRows(1); 31 } 32 33 @Override 34 public final Location getLocation(int index) { 35 // all items are on row 0, share the same Location object. 36 return mTmpLocation; 37 } 38 39 @Override 40 public final void debugPrint(PrintWriter pw) { 41 pw.print("SingleRow<"); 42 pw.print(mFirstVisibleIndex); 43 pw.print(","); 44 pw.print(mLastVisibleIndex); 45 pw.print(">"); 46 pw.println(); 47 } 48 49 int getStartIndexForAppend() { 50 if (mLastVisibleIndex >= 0) { 51 return mLastVisibleIndex + 1; 52 } else if (mStartIndex != START_DEFAULT) { 53 return Math.min(mStartIndex, mProvider.getCount() - 1); 54 } else { 55 return 0; 56 } 57 } 58 59 int getStartIndexForPrepend() { 60 if (mFirstVisibleIndex >= 0) { 61 return mFirstVisibleIndex - 1; 62 } else if (mStartIndex != START_DEFAULT) { 63 return Math.min(mStartIndex, mProvider.getCount() - 1); 64 } else { 65 return mProvider.getCount() - 1; 66 } 67 } 68 69 @Override 70 protected final boolean prependVisibleItems(int toLimit, boolean oneColumnMode) { 71 if (mProvider.getCount() == 0) { 72 return false; 73 } 74 if (!oneColumnMode && checkPrependOverLimit(toLimit)) { 75 return false; 76 } 77 boolean filledOne = false; 78 int minIndex = mProvider.getMinIndex(); 79 for (int index = getStartIndexForPrepend(); index >= minIndex; index--) { 80 int size = mProvider.createItem(index, false, mTmpItem, false); 81 int edge; 82 if (mFirstVisibleIndex < 0 || mLastVisibleIndex < 0) { 83 edge = mReversedFlow ? Integer.MIN_VALUE : Integer.MAX_VALUE; 84 mLastVisibleIndex = mFirstVisibleIndex = index; 85 } else { 86 if (mReversedFlow) { 87 edge = mProvider.getEdge(index + 1) + mSpacing + size; 88 } else { 89 edge = mProvider.getEdge(index + 1) - mSpacing - size; 90 } 91 mFirstVisibleIndex = index; 92 } 93 mProvider.addItem(mTmpItem[0], index, size, 0, edge); 94 filledOne = true; 95 if (oneColumnMode || checkPrependOverLimit(toLimit)) { 96 break; 97 } 98 } 99 return filledOne; 100 } 101 102 @Override 103 protected final boolean appendVisibleItems(int toLimit, boolean oneColumnMode) { 104 if (mProvider.getCount() == 0) { 105 return false; 106 } 107 if (!oneColumnMode && checkAppendOverLimit(toLimit)) { 108 // not in one column mode, return immediately if over limit 109 return false; 110 } 111 boolean filledOne = false; 112 for (int index = getStartIndexForAppend(); index < mProvider.getCount(); index++) { 113 int size = mProvider.createItem(index, true, mTmpItem, false); 114 int edge; 115 if (mFirstVisibleIndex < 0 || mLastVisibleIndex< 0) { 116 edge = mReversedFlow ? Integer.MAX_VALUE : Integer.MIN_VALUE; 117 mLastVisibleIndex = mFirstVisibleIndex = index; 118 } else { 119 if (mReversedFlow) { 120 edge = mProvider.getEdge(index - 1) - mProvider.getSize(index - 1) - mSpacing; 121 } else { 122 edge = mProvider.getEdge(index - 1) + mProvider.getSize(index - 1) + mSpacing; 123 } 124 mLastVisibleIndex = index; 125 } 126 mProvider.addItem(mTmpItem[0], index, size, 0, edge); 127 filledOne = true; 128 if (oneColumnMode || checkAppendOverLimit(toLimit)) { 129 break; 130 } 131 } 132 return filledOne; 133 } 134 135 @Override 136 public void collectAdjacentPrefetchPositions(int fromLimit, int da, 137 @NonNull RecyclerView.LayoutManager.LayoutPrefetchRegistry layoutPrefetchRegistry) { 138 int indexToPrefetch; 139 int nearestEdge; 140 if (mReversedFlow ? da > 0 : da < 0) { 141 // prefetch next prepend, lower index number 142 if (getFirstVisibleIndex() == 0) { 143 return; // no remaining items to prefetch 144 } 145 146 indexToPrefetch = getStartIndexForPrepend(); 147 nearestEdge = mProvider.getEdge(mFirstVisibleIndex) 148 + (mReversedFlow ? mSpacing : -mSpacing); 149 } else { 150 // prefetch next append, higher index number 151 if (getLastVisibleIndex() == mProvider.getCount() - 1) { 152 return; // no remaining items to prefetch 153 } 154 155 indexToPrefetch = getStartIndexForAppend(); 156 int itemSizeWithSpace = mProvider.getSize(mLastVisibleIndex) + mSpacing; 157 nearestEdge = mProvider.getEdge(mLastVisibleIndex) 158 + (mReversedFlow ? -itemSizeWithSpace : itemSizeWithSpace); 159 } 160 161 int distance = Math.abs(nearestEdge - fromLimit); 162 layoutPrefetchRegistry.addPosition(indexToPrefetch, distance); 163 } 164 165 @Override 166 public final CircularIntArray[] getItemPositionsInRows(int startPos, int endPos) { 167 // all items are on the same row: 168 mTmpItemPositionsInRows[0].clear(); 169 mTmpItemPositionsInRows[0].addLast(startPos); 170 mTmpItemPositionsInRows[0].addLast(endPos); 171 return mTmpItemPositionsInRows; 172 } 173 174 @Override 175 protected final int findRowMin(boolean findLarge, int indexLimit, int[] indices) { 176 if (indices != null) { 177 indices[0] = 0; 178 indices[1] = indexLimit; 179 } 180 return mReversedFlow ? mProvider.getEdge(indexLimit) - mProvider.getSize(indexLimit) 181 : mProvider.getEdge(indexLimit); 182 } 183 184 @Override 185 protected final int findRowMax(boolean findLarge, int indexLimit, int[] indices) { 186 if (indices != null) { 187 indices[0] = 0; 188 indices[1] = indexLimit; 189 } 190 return mReversedFlow ? mProvider.getEdge(indexLimit) 191 : mProvider.getEdge(indexLimit) + mProvider.getSize(indexLimit); 192 } 193 194} 195