summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Steve McKay <smckay@google.com> 2017-03-24 09:14:14 -0700
committer Steve McKay <smckay@google.com> 2017-03-25 07:43:37 -0700
commitd39da943dad071de289a8a9845b56a3e9dd86f75 (patch)
tree146ff7f6e4e6ec58cb2faa8ae9fe95e505067bd3
parent98e4ae9fa52f19f43d937165ac2921b3dbb0f4ca (diff)
Add honored args when auto-paging.
Increase test coverage. Test: Improved! Change-Id: Icba97c5e821e6cb60157e0c8a5b204d0d2813bc8
-rw-r--r--api/test-current.txt2
-rw-r--r--core/java/android/database/PageViewCursor.java102
-rw-r--r--core/tests/coretests/src/android/database/PageViewCursorTest.java170
3 files changed, 185 insertions, 89 deletions
diff --git a/api/test-current.txt b/api/test-current.txt
index 8262223c033c..79fe89a38b83 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -11749,7 +11749,7 @@ package android.database {
}
public final class PageViewCursor extends android.database.CursorWrapper implements android.database.CrossProcessCursor {
- ctor public PageViewCursor(android.database.Cursor, int, int);
+ ctor public PageViewCursor(android.database.Cursor, android.os.Bundle);
method public void fillWindow(int, android.database.CursorWindow);
method public android.database.CursorWindow getWindow();
method public boolean onMove(int, int);
diff --git a/core/java/android/database/PageViewCursor.java b/core/java/android/database/PageViewCursor.java
index 44727a0d300e..4569a2765f51 100644
--- a/core/java/android/database/PageViewCursor.java
+++ b/core/java/android/database/PageViewCursor.java
@@ -15,6 +15,7 @@
*/
package android.database;
+import static com.android.internal.util.ArrayUtils.contains;
import static com.android.internal.util.Preconditions.checkArgument;
import android.annotation.Nullable;
@@ -25,7 +26,7 @@ import android.os.Bundle;
import android.util.Log;
import android.util.MathUtils;
-import com.android.internal.util.ArrayUtils;
+import java.util.Arrays;
/**
* Cursor wrapper that provides visibility into a subset of a wrapped cursor.
@@ -40,11 +41,12 @@ public final class PageViewCursor extends CursorWrapper implements CrossProcessC
/** An extra added to results that are auto-paged using the wrapper. */
public static final String EXTRA_AUTO_PAGED = "android.content.extra.AUTO_PAGED";
+ private static final String[] EMPTY_ARGS = new String[0];
private static final String TAG = "PageViewCursor";
private static final boolean DEBUG = Build.IS_DEBUGGABLE;
private static final boolean VERBOSE = Build.IS_DEBUGGABLE && Log.isLoggable(TAG, Log.VERBOSE);
- private final int mOffset; // aka first index
+ private final int mOffset; // aka first index
private final int mCount;
private final Bundle mExtras;
@@ -55,12 +57,17 @@ public final class PageViewCursor extends CursorWrapper implements CrossProcessC
/**
* @see PageViewCursor#wrap(Cursor, Bundle)
*/
- public PageViewCursor(Cursor cursor, int offset, int limit) {
+ public PageViewCursor(Cursor cursor, Bundle queryArgs) {
super(cursor);
+ int offset = queryArgs.getInt(ContentResolver.QUERY_ARG_OFFSET, 0);
+ int limit = queryArgs.getInt(ContentResolver.QUERY_ARG_LIMIT, Integer.MAX_VALUE);
+
checkArgument(offset > -1);
checkArgument(limit > -1);
+ int count = mCursor.getCount();
+
mOffset = offset;
mExtras = new Bundle();
@@ -68,26 +75,47 @@ public final class PageViewCursor extends CursorWrapper implements CrossProcessC
if (extras != null) {
mExtras.putAll(extras);
}
- mExtras.putBoolean(EXTRA_AUTO_PAGED, true);
-
- // We need a mutable bundle so we can add QUERY_RESULT_SIZE.
- // Direct equality check is correct here. Bundle.EMPTY is a specific instance
- // of Bundle that is immutable by way of implementation.
- // mExtras = (extras == Bundle.EMPTY) ? new Bundle() : extras;
// When we're wrapping another cursor, it should not already be "paged".
- checkArgument(!mExtras.containsKey(ContentResolver.EXTRA_TOTAL_SIZE));
+ checkArgument(!hasPagedResponseDetails(mExtras));
- int count = mCursor.getCount();
+ mExtras.putBoolean(EXTRA_AUTO_PAGED, true);
mExtras.putInt(ContentResolver.EXTRA_TOTAL_SIZE, count);
+ // Ensure we retain any extra args supplied in cursor extras, and add
+ // offset and/or limit.
+ String[] existingArgs = mExtras.getStringArray(ContentResolver.EXTRA_HONORED_ARGS);
+ existingArgs = existingArgs != null ? existingArgs : EMPTY_ARGS;
+
+ int size = existingArgs.length;
+
+ // copy the array with space for the extra query args we'll be adding.
+ String[] newArgs = Arrays.copyOf(existingArgs, size + 2);
+
+ if (queryArgs.containsKey(ContentResolver.QUERY_ARG_OFFSET)) {
+ newArgs[size++] = ContentResolver.QUERY_ARG_OFFSET;
+ }
+ if (queryArgs.containsKey(ContentResolver.QUERY_ARG_LIMIT)) {
+ newArgs[size++] = ContentResolver.QUERY_ARG_LIMIT;
+ }
+
+ assert(size > existingArgs.length); // must add at least one arg.
+
+ // At this point there may be a null element at the end of
+ // the array because our pre-sizing didn't match the actualy
+ // number of args we added. So we trim.
+ if (size == newArgs.length - 1) {
+ newArgs = Arrays.copyOf(newArgs, size);
+ }
+ mExtras.putStringArray(ContentResolver.EXTRA_HONORED_ARGS, newArgs);
+
mCount = MathUtils.constrain(count - offset, 0, limit);
if (DEBUG) Log.d(TAG, "Wrapped cursor"
- + " offset: " + mOffset
- + ", limit: " + limit
- + ", delegate_size: " + count
- + ", paged_count: " + mCount);
+ + " offset: " + mOffset
+ + ", limit: " + limit
+ + ", delegate_size: " + count
+ + ", paged_count: " + mCount);
}
@Override
@@ -155,9 +183,9 @@ public final class PageViewCursor extends CursorWrapper implements CrossProcessC
public boolean moveToPosition(int position) {
if (position >= mCount) {
if (VERBOSE) Log.v(TAG, "Invalid Positon: " + position + " >= count: " + mCount
- + ". Moving to last record.");
+ + ". Moving to last record.");
mPos = mCount;
- super.moveToPosition(mOffset + mPos); // move into "after last" state.
+ super.moveToPosition(mOffset + mPos); // move into "after last" state.
return false;
}
@@ -198,15 +226,15 @@ public final class PageViewCursor extends CursorWrapper implements CrossProcessC
@Override
public boolean getWantsAllOnMoveCalls() {
- return false; // we want bulk cursor adapter to lift data into a CursorWindow.
+ return false; // we want bulk cursor adapter to lift data into a CursorWindow.
}
@Override
public CursorWindow getWindow() {
assert(mPos == -1 || mPos == 0);
if (mWindow == null) {
- mWindow = new CursorWindow("PageViewCursorWindow");
- fillWindow(0, mWindow);
+ mWindow = new CursorWindow("PageViewCursorWindow");
+ fillWindow(0, mWindow);
}
return mWindow;
@@ -224,17 +252,16 @@ public final class PageViewCursor extends CursorWrapper implements CrossProcessC
}
/**
- * Wraps the cursor such that it will honor paging args (if present), AND if the cursor
- * does not report paging size.
- *
- * <p>No-op if cursor already contains paging or is less than specified page size.
+ * Wraps the cursor such that it will honor paging args (if present), AND if the cursor does
+ * not report paging size.
+ * <p>
+ * No-op if cursor already contains paging or is less than specified page size.
*/
public static Cursor wrap(Cursor cursor, @Nullable Bundle queryArgs) {
- boolean hasPagingArgs =
- queryArgs != null
+ boolean hasPagingArgs = queryArgs != null
&& (queryArgs.containsKey(ContentResolver.QUERY_ARG_OFFSET)
- || queryArgs.containsKey(ContentResolver.QUERY_ARG_LIMIT));
+ || queryArgs.containsKey(ContentResolver.QUERY_ARG_LIMIT));
if (!hasPagingArgs) {
if (VERBOSE) Log.v(TAG, "No-wrap: No paging args in request.");
@@ -253,25 +280,26 @@ public final class PageViewCursor extends CursorWrapper implements CrossProcessC
return cursor;
}
- return new PageViewCursor(
- cursor,
- queryArgs.getInt(ContentResolver.QUERY_ARG_OFFSET, 0),
- queryArgs.getInt(ContentResolver.QUERY_ARG_LIMIT, Integer.MAX_VALUE));
+ return new PageViewCursor(cursor, queryArgs);
}
/**
- * @return true if the extras contains information indicating the associated
- * cursor is paged.
+ * @return true if the extras contains information indicating the associated cursor is
+ * paged.
*/
private static boolean hasPagedResponseDetails(@Nullable Bundle extras) {
- if (extras != null && extras.containsKey(ContentResolver.EXTRA_TOTAL_SIZE)) {
+ if (extras == null) {
+ return false;
+ }
+
+ if (extras.containsKey(ContentResolver.EXTRA_TOTAL_SIZE)) {
return true;
}
String[] honoredArgs = extras.getStringArray(ContentResolver.EXTRA_HONORED_ARGS);
- if (honoredArgs != null && (
- ArrayUtils.contains(honoredArgs, ContentResolver.QUERY_ARG_OFFSET)
- || ArrayUtils.contains(honoredArgs, ContentResolver.QUERY_ARG_LIMIT))) {
+ if (honoredArgs != null
+ && (contains(honoredArgs, ContentResolver.QUERY_ARG_OFFSET)
+ || contains(honoredArgs, ContentResolver.QUERY_ARG_LIMIT))) {
return true;
}
diff --git a/core/tests/coretests/src/android/database/PageViewCursorTest.java b/core/tests/coretests/src/android/database/PageViewCursorTest.java
index 62b54105cf9a..fba6aaf3f406 100644
--- a/core/tests/coretests/src/android/database/PageViewCursorTest.java
+++ b/core/tests/coretests/src/android/database/PageViewCursorTest.java
@@ -13,20 +13,28 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
package android.database;
+import static com.android.internal.util.ArrayUtils.contains;
+import static com.android.internal.util.Preconditions.checkArgument;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
+import android.annotation.Nullable;
import android.content.ContentResolver;
+import android.os.Build;
import android.os.Bundle;
import android.support.test.runner.AndroidJUnit4;
+import android.util.Log;
+import android.util.MathUtils;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.util.Arrays;
import java.util.Random;
@RunWith(AndroidJUnit4.class)
@@ -37,32 +45,32 @@ public class PageViewCursorTest {
private static final String NAME_COLUMN = "name";
private static final String NUM_COLUMN = "num";
- private static final String[] COLUMNS = new String[]{
- NAME_COLUMN,
- NUM_COLUMN
+ private static final String[] COLUMNS = new String[] {
+ NAME_COLUMN,
+ NUM_COLUMN
};
private static final String[] NAMES = new String[] {
- "000",
- "111",
- "222",
- "333",
- "444",
- "555",
- "666",
- "777",
- "888",
- "999",
- "aaa",
- "bbb",
- "ccc",
- "ddd",
- "eee",
- "fff",
- "ggg",
- "hhh",
- "iii",
- "jjj"
+ "000",
+ "111",
+ "222",
+ "333",
+ "444",
+ "555",
+ "666",
+ "777",
+ "888",
+ "999",
+ "aaa",
+ "bbb",
+ "ccc",
+ "ddd",
+ "eee",
+ "fff",
+ "ggg",
+ "hhh",
+ "iii",
+ "jjj"
};
private MatrixCursor mDelegate;
@@ -79,7 +87,7 @@ public class PageViewCursorTest {
row.add(NUM_COLUMN, rand.nextInt());
}
- mCursor = new PageViewCursor(mDelegate, 10, 5);
+ mCursor = new PageViewCursor(mDelegate, createArgs(10, 5));
}
@Test
@@ -94,7 +102,7 @@ public class PageViewCursorTest {
@Test
public void testPage_OffsetExceedsCursorCount_EffectivelyEmptyCursor() {
- mCursor = new PageViewCursor(mDelegate, ITEM_COUNT * 2, 5);
+ mCursor = new PageViewCursor(mDelegate, createArgs(ITEM_COUNT * 2, 5));
assertEquals(0, mCursor.getCount());
}
@@ -155,13 +163,13 @@ public class PageViewCursorTest {
@Test
public void testCount_ZeroForEmptyCursor() {
- mCursor = new PageViewCursor(mDelegate, 0, 0);
+ mCursor = new PageViewCursor(mDelegate, createArgs(0, 0));
assertEquals(0, mCursor.getCount());
}
@Test
public void testIsBeforeFirst_TrueForEmptyCursor() {
- mCursor = new PageViewCursor(mDelegate, 0, 0);
+ mCursor = new PageViewCursor(mDelegate, createArgs(0, 0));
assertTrue(mCursor.isBeforeFirst());
}
@@ -175,7 +183,7 @@ public class PageViewCursorTest {
@Test
public void testIsAfterLast_TrueForEmptyCursor() {
- mCursor = new PageViewCursor(mDelegate, 0, 0);
+ mCursor = new PageViewCursor(mDelegate, createArgs(0, 0));
assertTrue(mCursor.isAfterLast());
}
@@ -247,71 +255,131 @@ public class PageViewCursorTest {
}
@Test
- public void testOffset_LimitOutOfBounds() {
- mCursor = new PageViewCursor(mDelegate, 5, 100);
+ public void testLimitOutOfBounds() {
+ mCursor = new PageViewCursor(mDelegate, createArgs(5, 100));
assertEquals(15, mCursor.getCount());
}
@Test
- public void testAutoPagedExtra() {
- mCursor = new PageViewCursor(mDelegate, 5, 100);
+ public void testOffsetOutOfBounds_EmptyResult() {
+ mCursor = new PageViewCursor(mDelegate, createArgs(100000, 100));
+ assertEquals(0, mCursor.getCount());
+ }
+
+ @Test
+ public void testAddsExtras() {
+ mCursor = new PageViewCursor(mDelegate, createArgs(5, 100));
assertTrue(mCursor.getExtras().getBoolean(PageViewCursor.EXTRA_AUTO_PAGED));
+ String[] honoredArgs = mCursor.getExtras()
+ .getStringArray(ContentResolver.EXTRA_HONORED_ARGS);
+ assertTrue(contains(honoredArgs, ContentResolver.QUERY_ARG_OFFSET));
+ assertTrue(contains(honoredArgs, ContentResolver.QUERY_ARG_LIMIT));
+ }
+
+ @Test
+ public void testAddsExtras_OnlyOffset() {
+ Bundle args = new Bundle();
+ args.putInt(ContentResolver.QUERY_ARG_OFFSET, 5);
+ mCursor = new PageViewCursor(mDelegate, args);
+ String[] honoredArgs = mCursor.getExtras()
+ .getStringArray(ContentResolver.EXTRA_HONORED_ARGS);
+ assertTrue(contains(honoredArgs, ContentResolver.QUERY_ARG_OFFSET));
+ assertFalse(contains(honoredArgs, ContentResolver.QUERY_ARG_LIMIT));
+ }
+
+ @Test
+ public void testAddsExtras_OnlyLimit() {
+ Bundle args = new Bundle();
+ args.putInt(ContentResolver.QUERY_ARG_LIMIT, 5);
+ mCursor = new PageViewCursor(mDelegate, args);
+ String[] honoredArgs = mCursor.getExtras()
+ .getStringArray(ContentResolver.EXTRA_HONORED_ARGS);
+ assertFalse(contains(honoredArgs, ContentResolver.QUERY_ARG_OFFSET));
+ assertTrue(contains(honoredArgs, ContentResolver.QUERY_ARG_LIMIT));
}
@Test
public void testGetWindow() {
- mCursor = new PageViewCursor(mDelegate, 5, 5);
+ mCursor = new PageViewCursor(mDelegate, createArgs(5, 5));
CursorWindow window = mCursor.getWindow();
assertEquals(5, window.getNumRows());
}
@Test
- public void testWrap() {
- Bundle queryArgs = new Bundle();
- queryArgs.putInt(ContentResolver.QUERY_ARG_OFFSET, 5);
- queryArgs.putInt(ContentResolver.QUERY_ARG_LIMIT, 5);
- Cursor wrapped = PageViewCursor.wrap(mDelegate, queryArgs);
+ public void testWraps() {
+ Bundle args = createArgs(5, 5);
+ Cursor wrapped = PageViewCursor.wrap(mDelegate, args);
assertTrue(wrapped instanceof PageViewCursor);
assertEquals(5, wrapped.getCount());
}
@Test
- public void testWrap_NoOpWithoutPagingArgs() {
+ public void testWraps_NullExtras() {
+ Bundle args = createArgs(5, 5);
+ mDelegate.setExtras(null);
+ Cursor wrapped = PageViewCursor.wrap(mDelegate, args);
+ assertTrue(wrapped instanceof PageViewCursor);
+ assertEquals(5, wrapped.getCount());
+ }
+
+ @Test
+ public void testWraps_WithJustOffset() {
+ Bundle args = new Bundle();
+ args.putInt(ContentResolver.QUERY_ARG_OFFSET, 5);
+ Cursor wrapped = PageViewCursor.wrap(mDelegate, args);
+ assertTrue(wrapped instanceof PageViewCursor);
+ assertEquals(15, wrapped.getCount());
+ }
+
+ @Test
+ public void testWraps_WithJustLimit() {
+ Bundle args = new Bundle();
+ args.putInt(ContentResolver.QUERY_ARG_LIMIT, 5);
+ Cursor wrapped = PageViewCursor.wrap(mDelegate, args);
+ assertTrue(wrapped instanceof PageViewCursor);
+ assertEquals(5, wrapped.getCount());
+ }
+
+ @Test
+ public void testNoWrap_WithoutPagingArgs() {
Cursor wrapped = PageViewCursor.wrap(mDelegate, Bundle.EMPTY);
assertTrue(mDelegate == wrapped);
}
@Test
- public void testWrap_NoOpCursorsWithExistingPaging_ByTotalSize() {
+ public void testNoWrap_CursorsHasExistingPaging_ByTotalSize() {
Bundle extras = new Bundle();
extras.putInt(ContentResolver.EXTRA_TOTAL_SIZE, 5);
mDelegate.setExtras(extras);
- Bundle queryArgs = new Bundle();
- queryArgs.putInt(ContentResolver.QUERY_ARG_OFFSET, 5);
- queryArgs.putInt(ContentResolver.QUERY_ARG_LIMIT, 5);
- Cursor wrapped = PageViewCursor.wrap(mDelegate, queryArgs);
+ Bundle args = createArgs(5, 5);
+ Cursor wrapped = PageViewCursor.wrap(mDelegate, args);
assertTrue(mDelegate == wrapped);
}
@Test
- public void testWrap_NoOpCursorsWithExistingPaging_ByHonoredArgs() {
+ public void testNoWrap_CursorsHasExistingPaging_ByHonoredArgs() {
Bundle extras = new Bundle();
extras.putStringArray(
ContentResolver.EXTRA_HONORED_ARGS,
new String[] {
- ContentResolver.QUERY_ARG_OFFSET,
- ContentResolver.QUERY_ARG_LIMIT
+ ContentResolver.QUERY_ARG_OFFSET,
+ ContentResolver.QUERY_ARG_LIMIT
});
mDelegate.setExtras(extras);
- Bundle queryArgs = new Bundle();
- queryArgs.putInt(ContentResolver.QUERY_ARG_OFFSET, 5);
- queryArgs.putInt(ContentResolver.QUERY_ARG_LIMIT, 5);
- Cursor wrapped = PageViewCursor.wrap(mDelegate, queryArgs);
+ Bundle args = createArgs(5, 5);
+ Cursor wrapped = PageViewCursor.wrap(mDelegate, args);
assertTrue(mDelegate == wrapped);
}
+ private static Bundle createArgs(int offset, int limit) {
+ Bundle args = new Bundle();
+ args.putInt(ContentResolver.QUERY_ARG_OFFSET, offset);
+ args.putInt(ContentResolver.QUERY_ARG_LIMIT, limit);
+ return args;
+ }
+
private void assertStringAt(int row, int column, String expected) {
mCursor.moveToPosition(row);
assertEquals(expected, mCursor.getString(column));