diff --git a/api/test-current.txt b/api/test-current.txt index 192ce756752f0..3acc9ff18f134 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -11775,15 +11775,6 @@ package android.database { field protected final java.util.ArrayList mObservers; } - public final class PageViewCursor extends android.database.CursorWrapper implements android.database.CrossProcessCursor { - 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); - method public static android.database.Cursor wrap(android.database.Cursor, android.os.Bundle); - field public static final java.lang.String EXTRA_AUTO_PAGED = "android.content.extra.AUTO_PAGED"; - } - public class SQLException extends java.lang.RuntimeException { ctor public SQLException(); ctor public SQLException(java.lang.String); diff --git a/core/java/android/content/ContentProviderNative.java b/core/java/android/content/ContentProviderNative.java index 2f87633a39d3b..d428a3a857b7c 100644 --- a/core/java/android/content/ContentProviderNative.java +++ b/core/java/android/content/ContentProviderNative.java @@ -24,7 +24,6 @@ import android.database.Cursor; import android.database.CursorToBulkCursorAdaptor; import android.database.DatabaseUtils; import android.database.IContentObserver; -import android.database.PageViewCursor; import android.net.Uri; import android.os.Binder; import android.os.Bundle; @@ -104,7 +103,6 @@ abstract public class ContentProviderNative extends Binder implements IContentPr if (cursor != null) { CursorToBulkCursorAdaptor adaptor = null; - cursor = PageViewCursor.wrap(cursor, queryArgs); try { adaptor = new CursorToBulkCursorAdaptor(cursor, observer, getProviderName()); diff --git a/core/java/android/database/PageViewCursor.java b/core/java/android/database/PageViewCursor.java deleted file mode 100644 index 4569a2765f51c..0000000000000 --- a/core/java/android/database/PageViewCursor.java +++ /dev/null @@ -1,308 +0,0 @@ -/* - * Copyright (C) 2017 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.database; - -import static com.android.internal.util.ArrayUtils.contains; -import static com.android.internal.util.Preconditions.checkArgument; - -import android.annotation.Nullable; -import android.annotation.TestApi; -import android.content.ContentResolver; -import android.os.Build; -import android.os.Bundle; -import android.util.Log; -import android.util.MathUtils; - -import java.util.Arrays; - -/** - * Cursor wrapper that provides visibility into a subset of a wrapped cursor. - * - * The window is specified by offset and limit. - * - * @hide - */ -@TestApi -public final class PageViewCursor extends CursorWrapper implements CrossProcessCursor { - - /** 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 mCount; - private final Bundle mExtras; - - private @Nullable CursorWindow mWindow; - private int mPos = -1; - private int mWindowFillCount = 0; - - /** - * @see PageViewCursor#wrap(Cursor, Bundle) - */ - 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(); - Bundle extras = cursor.getExtras(); - if (extras != null) { - mExtras.putAll(extras); - } - - // When we're wrapping another cursor, it should not already be "paged". - checkArgument(!hasPagedResponseDetails(mExtras)); - - 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); - } - - @Override - public Bundle getExtras() { - return mExtras; - } - - @Override - public int getPosition() { - return mPos; - } - - @Override - public boolean isBeforeFirst() { - if (mCount == 0) { - return true; - } - return mPos == -1; - } - - @Override - public boolean isAfterLast() { - if (mCount == 0) { - return true; - } - return mPos == mCount; - } - - @Override - public boolean isFirst() { - return mPos == 0; - } - - @Override - public boolean isLast() { - return mPos == mCount - 1; - } - - @Override - public boolean moveToFirst() { - return moveToPosition(0); - } - - @Override - public boolean moveToLast() { - return moveToPosition(mCount - 1); - } - - @Override - public boolean moveToNext() { - return move(1); - } - - @Override - public boolean moveToPrevious() { - return move(-1); - } - - @Override - public boolean move(int offset) { - return moveToPosition(mPos + offset); - } - - @Override - public boolean moveToPosition(int position) { - if (position >= mCount) { - if (VERBOSE) Log.v(TAG, "Invalid Positon: " + position + " >= count: " + mCount - + ". Moving to last record."); - mPos = mCount; - super.moveToPosition(mOffset + mPos); // move into "after last" state. - return false; - } - - // Make sure position isn't before the beginning of the cursor - if (position < 0) { - if (VERBOSE) Log.v(TAG, "Ignoring invalid move to position: " + position); - mPos = -1; - super.moveToPosition(mPos); - return false; - } - - if (position == mPos) { - if (VERBOSE) Log.v(TAG, "Ignoring no-op move to position: " + position); - return true; - } - - int delegatePosition = position + mOffset; - if (VERBOSE) Log.v(TAG, "Moving delegate cursor to position: " + delegatePosition); - if (super.moveToPosition(delegatePosition)) { - mPos = position; - return true; - } else { - mPos = -1; - super.moveToPosition(-1); - return false; - } - } - - @Override - public boolean onMove(int oldPosition, int newPosition) { - throw new UnsupportedOperationException("Not supported."); - } - - @Override - public int getCount() { - return mCount; - } - - @Override - public boolean getWantsAllOnMoveCalls() { - 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); - } - - return mWindow; - } - - @Override - public void fillWindow(int position, CursorWindow window) { - assert(window == mWindow); - - if (mWindowFillCount++ > 0) { - Log.w(TAG, "Re-filling window on paged cursor! Reduce ContentResolver.QUERY_ARG_LIMIT"); - } - - DatabaseUtils.cursorFillWindow(this, position, window); - } - - /** - * Wraps the cursor such that it will honor paging args (if present), AND if the cursor does - * not report paging size. - *

- * 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 - && (queryArgs.containsKey(ContentResolver.QUERY_ARG_OFFSET) - || queryArgs.containsKey(ContentResolver.QUERY_ARG_LIMIT)); - - if (!hasPagingArgs) { - if (VERBOSE) Log.v(TAG, "No-wrap: No paging args in request."); - return cursor; - } - - if (hasPagedResponseDetails(cursor.getExtras())) { - if (VERBOSE) Log.v(TAG, "No-wrap. Cursor has paging details."); - return cursor; - } - - // Cursors that want all calls aren't compatible with our way - // of doing business. TODO: Cover this case in CTS. - if (cursor.getWantsAllOnMoveCalls()) { - Log.w(TAG, "Unable to wrap cursor that wants to hear about move calls."); - return cursor; - } - - return new PageViewCursor(cursor, queryArgs); - } - - /** - * @return true if the extras contains information indicating the associated cursor is - * paged. - */ - private static boolean hasPagedResponseDetails(@Nullable Bundle extras) { - 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 - && (contains(honoredArgs, ContentResolver.QUERY_ARG_OFFSET) - || contains(honoredArgs, ContentResolver.QUERY_ARG_LIMIT))) { - return true; - } - - return false; - } -} diff --git a/core/tests/coretests/src/android/database/PageViewCursorTest.java b/core/tests/coretests/src/android/database/PageViewCursorTest.java deleted file mode 100644 index fba6aaf3f4068..0000000000000 --- a/core/tests/coretests/src/android/database/PageViewCursorTest.java +++ /dev/null @@ -1,387 +0,0 @@ -/* - * Copyright (C) 2017 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.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) -public class PageViewCursorTest { - - private static final int ITEM_COUNT = 20; - - 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[] NAMES = new String[] { - "000", - "111", - "222", - "333", - "444", - "555", - "666", - "777", - "888", - "999", - "aaa", - "bbb", - "ccc", - "ddd", - "eee", - "fff", - "ggg", - "hhh", - "iii", - "jjj" - }; - - private MatrixCursor mDelegate; - private PageViewCursor mCursor; - - @Before - public void setUp() { - Random rand = new Random(); - - mDelegate = new MatrixCursor(COLUMNS); - for (int i = 0; i < ITEM_COUNT; i++) { - MatrixCursor.RowBuilder row = mDelegate.newRow(); - row.add(NAME_COLUMN, NAMES[i]); - row.add(NUM_COLUMN, rand.nextInt()); - } - - mCursor = new PageViewCursor(mDelegate, createArgs(10, 5)); - } - - @Test - public void testPage_Size() { - assertEquals(5, mCursor.getCount()); - } - - @Test - public void testPage_TotalSize() { - assertEquals(ITEM_COUNT, mCursor.getExtras().getInt(ContentResolver.EXTRA_TOTAL_SIZE)); - } - - @Test - public void testPage_OffsetExceedsCursorCount_EffectivelyEmptyCursor() { - mCursor = new PageViewCursor(mDelegate, createArgs(ITEM_COUNT * 2, 5)); - assertEquals(0, mCursor.getCount()); - } - - @Test - public void testMoveToPosition() { - assertTrue(mCursor.moveToPosition(0)); - assertEquals(NAMES[10], mCursor.getString(0)); - assertTrue(mCursor.moveToPosition(1)); - assertEquals(NAMES[11], mCursor.getString(0)); - assertTrue(mCursor.moveToPosition(4)); - assertEquals(NAMES[14], mCursor.getString(0)); - - // and then back down again for good measure. - assertTrue(mCursor.moveToPosition(1)); - assertEquals(NAMES[11], mCursor.getString(0)); - assertTrue(mCursor.moveToPosition(0)); - assertEquals(NAMES[10], mCursor.getString(0)); - } - - @Test - public void testMoveToPosition_MoveToSamePosition_NoOp() { - assertTrue(mCursor.moveToPosition(1)); - assertEquals(NAMES[11], mCursor.getString(0)); - assertTrue(mCursor.moveToPosition(1)); - assertEquals(NAMES[11], mCursor.getString(0)); - } - - @Test - public void testMoveToPosition_PositionOutOfBounds_MovesToBeforeFirst() { - assertTrue(mCursor.moveToPosition(0)); - assertEquals(NAMES[10], mCursor.getString(0)); - - // move before - assertFalse(mCursor.moveToPosition(-12)); - assertTrue(mCursor.isBeforeFirst()); - } - - @Test - public void testMoveToPosition_PositionOutOfBounds_MovesToAfterLast() { - assertTrue(mCursor.moveToPosition(0)); - assertEquals(NAMES[10], mCursor.getString(0)); - - assertFalse(mCursor.moveToPosition(222)); - assertTrue(mCursor.isAfterLast()); - } - - @Test - public void testPosition() { - assertEquals(-1, mCursor.getPosition()); - } - - @Test - public void testIsBeforeFirst() { - assertTrue(mCursor.isBeforeFirst()); - mCursor.moveToFirst(); - assertFalse(mCursor.isBeforeFirst()); - } - - @Test - public void testCount_ZeroForEmptyCursor() { - mCursor = new PageViewCursor(mDelegate, createArgs(0, 0)); - assertEquals(0, mCursor.getCount()); - } - - @Test - public void testIsBeforeFirst_TrueForEmptyCursor() { - mCursor = new PageViewCursor(mDelegate, createArgs(0, 0)); - assertTrue(mCursor.isBeforeFirst()); - } - - @Test - public void testIsAfterLast() { - assertFalse(mCursor.isAfterLast()); - mCursor.moveToLast(); - mCursor.moveToNext(); - assertTrue(mCursor.isAfterLast()); - } - - @Test - public void testIsAfterLast_TrueForEmptyCursor() { - mCursor = new PageViewCursor(mDelegate, createArgs(0, 0)); - assertTrue(mCursor.isAfterLast()); - } - - @Test - public void testIsFirst() { - assertFalse(mCursor.isFirst()); - mCursor.moveToFirst(); - assertTrue(mCursor.isFirst()); - } - - @Test - public void testIsLast() { - assertFalse(mCursor.isLast()); - mCursor.moveToLast(); - assertTrue(mCursor.isLast()); - } - - @Test - public void testMove() { - // note that initial position is -1, so moving - // 2 will only put as at 1. - mCursor.move(2); - assertEquals(NAMES[11], mCursor.getString(0)); - mCursor.move(-1); - assertEquals(NAMES[10], mCursor.getString(0)); - } - - @Test - public void testMoveToFist() { - mCursor.moveToPosition(3); - mCursor.moveToFirst(); - assertEquals(NAMES[10], mCursor.getString(0)); - } - - @Test - public void testMoveToLast() { - mCursor.moveToLast(); - assertEquals(NAMES[14], mCursor.getString(0)); - } - - @Test - public void testMoveToNext() { - // default position is -1, so next is 0. - mCursor.moveToNext(); - assertEquals(NAMES[10], mCursor.getString(0)); - } - - @Test - public void testMoveToNext_AfterLastReturnsFalse() { - mCursor.moveToLast(); - assertFalse(mCursor.moveToNext()); - } - - @Test - public void testMoveToPrevious() { - mCursor.moveToPosition(3); - mCursor.moveToPrevious(); - assertEquals(NAMES[12], mCursor.getString(0)); - } - - @Test - public void testMoveToPrevious_BeforeFirstReturnsFalse() { - assertFalse(mCursor.moveToPrevious()); - } - - @Test - public void testWindow_ReadPastEnd() { - assertFalse(mCursor.moveToPosition(10)); - } - - @Test - public void testLimitOutOfBounds() { - mCursor = new PageViewCursor(mDelegate, createArgs(5, 100)); - assertEquals(15, mCursor.getCount()); - } - - @Test - 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, createArgs(5, 5)); - CursorWindow window = mCursor.getWindow(); - assertEquals(5, window.getNumRows()); - } - - @Test - 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 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 testNoWrap_CursorsHasExistingPaging_ByTotalSize() { - Bundle extras = new Bundle(); - extras.putInt(ContentResolver.EXTRA_TOTAL_SIZE, 5); - mDelegate.setExtras(extras); - - Bundle args = createArgs(5, 5); - Cursor wrapped = PageViewCursor.wrap(mDelegate, args); - assertTrue(mDelegate == wrapped); - } - - @Test - 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 - }); - mDelegate.setExtras(extras); - - 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)); - } -}