1c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay/* 2c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay * Copyright (C) 2017 The Android Open Source Project 3c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay * 4c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay * Licensed under the Apache License, Version 2.0 (the "License"); 5c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay * you may not use this file except in compliance with the License. 6c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay * You may obtain a copy of the License at 7c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay * 8c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay * http://www.apache.org/licenses/LICENSE-2.0 9c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay * 10c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay * Unless required by applicable law or agreed to in writing, software 11c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay * distributed under the License is distributed on an "AS IS" BASIS, 12c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay * See the License for the specific language governing permissions and 14c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay * limitations under the License. 15c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay */ 16c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay 17ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikaspackage androidx.contentpager.content; 18c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay 19fa39e2bca1b284ad7c931d9194287770b7b507faAurimas Liutikasimport static org.junit.Assert.assertEquals; 20c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay 21c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKayimport android.content.ContentProvider; 22c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKayimport android.content.ContentResolver; 23c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKayimport android.content.ContentValues; 24c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKayimport android.database.AbstractWindowedCursor; 25c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKayimport android.database.Cursor; 26c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKayimport android.database.CursorWindow; 27c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKayimport android.database.MatrixCursor; 28c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKayimport android.database.MatrixCursor.RowBuilder; 29c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKayimport android.net.Uri; 30c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKayimport android.os.Bundle; 31c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKayimport android.os.CancellationSignal; 32fb4b6f71b6a30ea0acc67fce323853e4beb096d7Aurimas Liutikas 33ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikasimport androidx.annotation.Nullable; 34ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikasimport androidx.annotation.VisibleForTesting; 35c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay 36c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay/** 37c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay * A stub data paging provider used for testing of paging support. 38c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay * Ignores client supplied projections. 39c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay */ 40c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKaypublic final class TestContentProvider extends ContentProvider { 41c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay 42ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikas public static final String AUTHORITY = "androidx.contentpager.content.test.testpagingprovider"; 43c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay 44c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay public static final String UNPAGED_PATH = "/un-paged"; 45c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay public static final String PAGED_PATH = "/paged"; 46c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay public static final String PAGED_WINDOWED_PATH = PAGED_PATH + "/windowed"; 47c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay 48c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay public static final Uri UNPAGED_URI = new Uri.Builder() 49c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay .scheme("content") 50c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay .authority(AUTHORITY) 51c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay .path(UNPAGED_PATH) 52c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay .build(); 53c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay public static final Uri PAGED_URI = new Uri.Builder() 54c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay .scheme("content") 55c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay .authority(AUTHORITY) 56c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay .path(PAGED_PATH) 57c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay .build(); 58c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay public static final Uri PAGED_WINDOWED_URI = new Uri.Builder() 59c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay .scheme("content") 60c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay .authority(AUTHORITY) 61c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay .path(PAGED_WINDOWED_PATH) 62c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay .build(); 63c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay 64c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay public static final String COLUMN_POS = "ColumnPos"; 65c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay public static final String COLUMN_A = "ColumnA"; 66c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay public static final String COLUMN_B = "ColumnB"; 67c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay public static final String COLUMN_C = "ColumnC"; 68c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay public static final String COLUMN_D = "ColumnD"; 69c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay public static final String[] PROJECTION = { 70c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay COLUMN_POS, 71c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay COLUMN_A, 72c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay COLUMN_B, 73c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay COLUMN_C, 74c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay COLUMN_D 75c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay }; 76c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay 77c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay @VisibleForTesting 78c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay public static final String RECORD_COUNT = "test-record-count"; 79c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay 80c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay @VisibleForTesting 81c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay public static final int DEFAULT_RECORD_COUNT = 567; 82c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay 83c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay private static final String TAG = "TestPagingProvider"; 84c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay 85c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay @Override 86c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay public boolean onCreate() { 87c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay return true; 88c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay } 89c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay 90c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay @Override 91c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay public Cursor query( 92c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay Uri uri, @Nullable String[] projection, String selection, String[] selectionArgs, 93c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay String sortOrder) { 94c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay return query(uri, projection, null, null); 95c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay } 96c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay 97c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay @Override 98c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay public Cursor query(Uri uri, String[] ignored, Bundle queryArgs, 99c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay CancellationSignal cancellationSignal) { 100c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay 101c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay queryArgs = queryArgs != null ? queryArgs : Bundle.EMPTY; 102c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay 103c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay int recordCount = getIntValue(RECORD_COUNT, queryArgs, uri, DEFAULT_RECORD_COUNT); 104c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay if (recordCount < 0) { 105c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay throw new RuntimeException("Recordset size must be >= 0"); 106c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay } 107c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay 108c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay Cursor cursor = null; 109c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay switch (uri.getPath()) { 110c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay case UNPAGED_PATH: 111c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay cursor = buildUnpagedResults(recordCount); 112c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay break; 113c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay case PAGED_PATH: 114c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay cursor = buildPagedResults(uri, queryArgs, recordCount); 115c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay break; 116c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay case PAGED_WINDOWED_PATH: 117c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay cursor = buildPagedWindowedResults(uri, queryArgs, recordCount); 118c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay break; 119c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay default: 120c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay throw new IllegalArgumentException("Unrecognized path: " + uri.getPath()); 121c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay } 122c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay 123c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay cursor.setNotificationUri(getContext().getContentResolver(), uri); 124c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay 125c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay return cursor; 126c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay } 127c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay 128c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay /** 129c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay * Return a int value specified in Bundle key, Uri query arg, or fallback default value. 130c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay */ 131c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay private static int getIntValue(String key, Bundle queryArgs, Uri uri, int defaultValue) { 132c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay int value = queryArgs.getInt(key, Integer.MIN_VALUE); 133c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay if (value != Integer.MIN_VALUE) { 134c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay return value; 135c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay } 136c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay 137c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay @Nullable String argValue = uri.getQueryParameter(key); 138c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay if (argValue != null) { 139c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay try { 140c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay return Integer.parseInt(argValue); 141c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay } catch (NumberFormatException ignored) { 142c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay } 143c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay } 144c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay 145c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay return defaultValue; 146c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay } 147c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay 148c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay private MatrixCursor buildPagedResults(Uri uri, Bundle queryArgs, int recordsetSize) { 149c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay int offset = getIntValue(ContentResolver.QUERY_ARG_OFFSET, queryArgs, uri, 0); 150c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay int limit = getIntValue(ContentResolver.QUERY_ARG_LIMIT, queryArgs, uri, recordsetSize); 151c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay 152c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay MatrixCursor c = createInMemoryCursor(); 153c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay Bundle extras = c.getExtras(); 154c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay 155c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay // Calculate the number of items to include in the cursor. 156c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay int numItems = constrain(recordsetSize - offset, 0, limit); 157c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay 158c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay // Build the paged result set. 159c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay for (int i = offset; i < offset + numItems; i++) { 160c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay fillRow(c.newRow(), i); 161c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay } 162c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay 163c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay extras.putStringArray(ContentResolver.EXTRA_HONORED_ARGS, new String[] { 164c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay ContentResolver.QUERY_ARG_OFFSET, 165c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay ContentResolver.QUERY_ARG_LIMIT 166c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay }); 167c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay extras.putInt(ContentResolver.EXTRA_TOTAL_COUNT, recordsetSize); 168c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay return c; 169c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay } 170c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay 171c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay private AbstractWindowedCursor buildPagedWindowedResults( 172c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay Uri uri, Bundle queryArgs, int recordsetSize) { 173c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay int offset = getIntValue(ContentResolver.QUERY_ARG_OFFSET, queryArgs, uri, 0); 174c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay int limit = getIntValue(ContentResolver.QUERY_ARG_LIMIT, queryArgs, uri, recordsetSize); 175c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay 176c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay int windowSize = limit - 1; 177c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay 178c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay TestWindowedCursor c = new TestWindowedCursor(PROJECTION, recordsetSize); 179c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay CursorWindow window = c.getWindow(); 180c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay window.setNumColumns(PROJECTION.length); 181c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay 182c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay Bundle extras = c.getExtras(); 183c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay 184c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay // Build the unpaged result set. 185c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay for (int row = 0; row < windowSize; row++) { 186c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay if (!window.allocRow()) { 187c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay break; 188c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay } 189c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay if (!fillRow(window, row)) { 190c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay window.freeLastRow(); 191c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay break; 192c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay } 193c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay } 194c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay 195c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay extras.putStringArray(ContentResolver.EXTRA_HONORED_ARGS, new String[] { 196c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay ContentResolver.QUERY_ARG_OFFSET, 197c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay ContentResolver.QUERY_ARG_LIMIT 198c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay }); 199c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay extras.putInt(ContentResolver.EXTRA_TOTAL_COUNT, recordsetSize); 200c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay return c; 201c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay } 202c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay 203c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay private MatrixCursor buildUnpagedResults(int recordsetSize) { 204c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay MatrixCursor c = createInMemoryCursor(); 205c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay 206c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay // Build the unpaged result set. 207c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay for (int i = 0; i < recordsetSize; i++) { 208c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay fillRow(c.newRow(), i); 209c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay } 210c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay 211c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay return c; 212c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay } 213c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay 214c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay /** 215c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay * Returns data type of the given object's value. 216c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay *<p> 217c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay * Returned values are 218c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay * <ul> 219c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay * <li>{@link Cursor#FIELD_TYPE_NULL}</li> 220c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay * <li>{@link Cursor#FIELD_TYPE_INTEGER}</li> 221c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay * <li>{@link Cursor#FIELD_TYPE_FLOAT}</li> 222c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay * <li>{@link Cursor#FIELD_TYPE_STRING}</li> 223c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay * <li>{@link Cursor#FIELD_TYPE_BLOB}</li> 224c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay *</ul> 225c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay *</p> 226c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay */ 227c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay public static int getTypeOfObject(Object obj) { 228c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay if (obj == null) { 229c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay return Cursor.FIELD_TYPE_NULL; 230c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay } else if (obj instanceof byte[]) { 231c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay return Cursor.FIELD_TYPE_BLOB; 232c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay } else if (obj instanceof Float || obj instanceof Double) { 233c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay return Cursor.FIELD_TYPE_FLOAT; 234c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay } else if (obj instanceof Long || obj instanceof Integer 235c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay || obj instanceof Short || obj instanceof Byte) { 236c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay return Cursor.FIELD_TYPE_INTEGER; 237c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay } else { 238c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay return Cursor.FIELD_TYPE_STRING; 239c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay } 240c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay } 241c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay 242c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay private MatrixCursor createInMemoryCursor() { 243c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay MatrixCursor c = new MatrixCursor(PROJECTION); 244c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay Bundle extras = new Bundle(); 245c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay c.setExtras(extras); 246c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay return c; 247c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay } 248c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay 249c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay private void fillRow(RowBuilder row, int rowId) { 250c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay row.add(createCellValue(rowId, 0)); 251c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay row.add(createCellValue(rowId, 1)); 252c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay row.add(createCellValue(rowId, 2)); 253c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay row.add(createCellValue(rowId, 3)); 254c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay row.add(createCellValue(rowId, 4)); 255c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay } 256c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay 257c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay /** 258c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay * @return true if the row was successfully populated. If false, caller should freeLastRow. 259c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay */ 260c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay private static boolean fillRow(CursorWindow window, int row) { 261c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay if (!window.putLong((int) createCellValue(row, 0), row, 0)) { 262c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay return false; 263c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay } 264c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay for (int i = 1; i < PROJECTION.length; i++) { 265c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay if (!window.putString((String) createCellValue(row, i), row, i)) { 266c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay return false; 267c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay } 268c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay } 269c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay return true; 270c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay } 271c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay 272c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay private static Object createCellValue(int row, int col) { 273c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay switch(col) { 274c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay case 0: 275c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay return row; 276c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay case 1: 277c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay return "--aaa--" + row; 278c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay case 2: 279c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay return "**bbb**" + row; 280c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay case 3: 281c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay return ("^^ccc^^" + row); 282c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay case 4: 283c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay return "##ddd##" + row; 284c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay default: 285c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay throw new IllegalArgumentException("Unsupported column: " + col); 286c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay } 287c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay } 288c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay 289c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay /** 290c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay * Asserts that the value at the current cursor position x column 291c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay * is expected test data for the supplied row. 292c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay * 293c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay * <p>Cursor must be pre-positioned. 294c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay * 295c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay * @param cursor must be prepositioned to the row to be tested. 296c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay * @param row row value expected to be reflected in cell. This can be different 297c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay * than the cursor position due to paging. 298c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay * @param column 299c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay */ 300c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay @VisibleForTesting 301c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay public static void assertExpectedCellValue(Cursor cursor, int row, int column) { 302c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay int type = cursor.getType(column); 303c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay switch(type) { 304c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay case Cursor.FIELD_TYPE_NULL: 305c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay throw new UnsupportedOperationException("Not implemented."); 306c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay case Cursor.FIELD_TYPE_INTEGER: 307c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay assertEquals(createCellValue(row, column), cursor.getInt(column)); 308c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay break; 309c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay case Cursor.FIELD_TYPE_FLOAT: 310c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay assertEquals(createCellValue(row, column), cursor.getDouble(column)); 311c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay break; 312c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay case Cursor.FIELD_TYPE_BLOB: 313c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay assertEquals(createCellValue(row, column), cursor.getBlob(column)); 314c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay break; 315c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay case Cursor.FIELD_TYPE_STRING: 316c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay assertEquals(createCellValue(row, column), cursor.getString(column)); 317c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay break; 318c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay default: 319c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay throw new UnsupportedOperationException("Unknown column type: " + type); 320c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay } 321c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay } 322c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay 323c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay @Override 324c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay public String getType(Uri uri) { 325c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay throw new UnsupportedOperationException(); 326c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay } 327c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay 328c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay @Override 329c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay public Uri insert(Uri uri, ContentValues values) { 330c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay throw new UnsupportedOperationException(); 331c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay } 332c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay 333c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay @Override 334c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay public int delete(Uri uri, String selection, String[] selectionArgs) { 335c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay throw new UnsupportedOperationException(); 336c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay } 337c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay 338c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay @Override 339c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { 340c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay throw new UnsupportedOperationException(); 341c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay } 342c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay 343c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay private static int constrain(int amount, int low, int high) { 344c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay return amount < low ? low : (amount > high ? high : amount); 345c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay } 346c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay 347c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay /** 348c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay * Returns a Uri that includes paging information embedded in the URI. 349c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay * This allows a test client to force paged results when running on older SDKs... 350c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay * pre Android O SDKs lacking the ContentResolver#query w/ Bundle override 351c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay * necessary for paging. 352c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay */ 353c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay public static Uri forcePagingSpec(Uri uri, int offset, int limit) { 354c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay assert (uri.getPath().equals(TestContentProvider.PAGED_PATH) 355c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay || uri.getPath().equals(TestContentProvider.PAGED_WINDOWED_PATH)); 356c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay return uri.buildUpon() 357c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay .appendQueryParameter(ContentResolver.QUERY_ARG_OFFSET, String.valueOf(offset)) 358c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay .appendQueryParameter(ContentResolver.QUERY_ARG_LIMIT, String.valueOf(limit)) 359c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay .build(); 360c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay } 361c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay 362c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay public static Uri forceRecordCount(Uri uri, int recordCount) { 363c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay return uri.buildUpon() 364c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay .appendQueryParameter(RECORD_COUNT, String.valueOf(recordCount)) 365c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay .build(); 366c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay } 367c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay 368c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay private static final class TestWindowedCursor extends AbstractWindowedCursor { 369c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay 370c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay private final String[] mProjection; 371c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay private final int mCount; 372c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay private final Bundle mExtras; 373c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay 374c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay TestWindowedCursor(String[] projection, int count) { 375c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay mProjection = projection; 376c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay mCount = count; 377c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay mExtras = new Bundle(); 378c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay 379c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay setWindow(new CursorWindow("stevie")); 380c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay } 381c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay 382c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay @Override 383c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay public Bundle getExtras() { 384c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay return mExtras; 385c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay } 386c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay 387c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay @Override 388c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay public int getCount() { 389c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay return mCount; 390c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay } 391c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay 392c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay @Override 393c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay public String[] getColumnNames() { 394c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay return mProjection; 395c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay } 396c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay } 397c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay} 398