TestContentProvider.java revision fa39e2bca1b284ad7c931d9194287770b7b507fa
1282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/*
2282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Copyright (C) 2017 The Android Open Source Project
3282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski *
4282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Licensed under the Apache License, Version 2.0 (the "License");
5282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * you may not use this file except in compliance with the License.
6282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * You may obtain a copy of the License at
7282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski *
8282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski *      http://www.apache.org/licenses/LICENSE-2.0
9282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski *
10282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Unless required by applicable law or agreed to in writing, software
11282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * distributed under the License is distributed on an "AS IS" BASIS,
12282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * See the License for the specific language governing permissions and
14282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * limitations under the License.
15282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */
16282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
17282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskipackage android.support.content;
18282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
19282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport static org.junit.Assert.assertEquals;
20282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
21282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport android.content.ContentProvider;
22282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport android.content.ContentResolver;
23282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport android.content.ContentValues;
24282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport android.database.AbstractWindowedCursor;
25282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport android.database.Cursor;
26282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport android.database.CursorWindow;
27282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport android.database.MatrixCursor;
28282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport android.database.MatrixCursor.RowBuilder;
29282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport android.net.Uri;
30282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport android.os.Bundle;
31282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport android.os.CancellationSignal;
32282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport android.support.annotation.Nullable;
33282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport android.support.annotation.VisibleForTesting;
34282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
35282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/**
36282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * A stub data paging provider used for testing of paging support.
37282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Ignores client supplied projections.
38282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */
39282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskipublic final class TestContentProvider extends ContentProvider {
40282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
41282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    public static final String AUTHORITY = "android.support.content.test.testpagingprovider";
42282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
43282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    public static final String UNPAGED_PATH = "/un-paged";
44282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    public static final String PAGED_PATH = "/paged";
45282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    public static final String PAGED_WINDOWED_PATH = PAGED_PATH + "/windowed";
46282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
47282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    public static final Uri UNPAGED_URI = new Uri.Builder()
48282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            .scheme("content")
49282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            .authority(AUTHORITY)
50282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            .path(UNPAGED_PATH)
51282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            .build();
52282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    public static final Uri PAGED_URI = new Uri.Builder()
53282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            .scheme("content")
54282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            .authority(AUTHORITY)
55282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            .path(PAGED_PATH)
56282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            .build();
57282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    public static final Uri PAGED_WINDOWED_URI = new Uri.Builder()
58282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            .scheme("content")
59282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            .authority(AUTHORITY)
60282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            .path(PAGED_WINDOWED_PATH)
61282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            .build();
62282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
63282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    public static final String COLUMN_POS = "ColumnPos";
64282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    public static final String COLUMN_A = "ColumnA";
65282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    public static final String COLUMN_B = "ColumnB";
66282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    public static final String COLUMN_C = "ColumnC";
67282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    public static final String COLUMN_D = "ColumnD";
68282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    public static final String[] PROJECTION = {
69282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            COLUMN_POS,
70282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            COLUMN_A,
71282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            COLUMN_B,
72282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            COLUMN_C,
73282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            COLUMN_D
74282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    };
75282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
76282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    @VisibleForTesting
77282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    public static final String RECORD_COUNT = "test-record-count";
78282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
79282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    @VisibleForTesting
80282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    public static final int DEFAULT_RECORD_COUNT = 567;
81282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
82282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    private static final String TAG = "TestPagingProvider";
8391447d88f2bdf9c2bf8d1a53570efef6172fba74Narayan Kamath
84282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    @Override
85282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    public boolean onCreate() {
86282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return true;
87282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
88282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
89282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    @Override
90282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    public Cursor query(
91282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            Uri uri, @Nullable String[] projection, String selection, String[] selectionArgs,
92282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            String sortOrder) {
93282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return query(uri, projection, null, null);
94282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
95282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
96282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    @Override
97282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    public Cursor query(Uri uri, String[] ignored, Bundle queryArgs,
98282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            CancellationSignal cancellationSignal) {
99282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
100282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        queryArgs = queryArgs != null ? queryArgs : Bundle.EMPTY;
101282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
102282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        int recordCount = getIntValue(RECORD_COUNT, queryArgs, uri, DEFAULT_RECORD_COUNT);
103282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (recordCount < 0) {
104282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            throw new RuntimeException("Recordset size must be >= 0");
105282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
106282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
107282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        Cursor cursor = null;
108282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        switch (uri.getPath()) {
109282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            case UNPAGED_PATH:
110282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                cursor = buildUnpagedResults(recordCount);
111282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                break;
112282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            case PAGED_PATH:
113282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                cursor = buildPagedResults(uri, queryArgs, recordCount);
114282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                break;
115282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            case PAGED_WINDOWED_PATH:
116282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                cursor = buildPagedWindowedResults(uri, queryArgs, recordCount);
117282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                break;
118282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            default:
119282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                throw new IllegalArgumentException("Unrecognized path: " + uri.getPath());
120282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
121282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
122282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        cursor.setNotificationUri(getContext().getContentResolver(), uri);
123282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
124282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return cursor;
125282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
126282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
127282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    /**
128282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * Return a int value specified in Bundle key, Uri query arg, or fallback default value.
129282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     */
130282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    private static int getIntValue(String key, Bundle queryArgs, Uri uri, int defaultValue) {
131282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        int value = queryArgs.getInt(key, Integer.MIN_VALUE);
132282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (value != Integer.MIN_VALUE) {
133282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            return value;
134282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
135282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
136282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        @Nullable String argValue = uri.getQueryParameter(key);
137282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (argValue != null) {
138282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            try {
139282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                return Integer.parseInt(argValue);
140282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            } catch (NumberFormatException ignored) {
141282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
142282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
143282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
144282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return defaultValue;
145282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
146282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
147282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    private MatrixCursor buildPagedResults(Uri uri, Bundle queryArgs, int recordsetSize) {
148282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        int offset = getIntValue(ContentResolver.QUERY_ARG_OFFSET, queryArgs, uri, 0);
149282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        int limit = getIntValue(ContentResolver.QUERY_ARG_LIMIT, queryArgs, uri, recordsetSize);
150282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
151282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        MatrixCursor c = createInMemoryCursor();
152282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        Bundle extras = c.getExtras();
153282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
154282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // Calculate the number of items to include in the cursor.
155282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        int numItems = constrain(recordsetSize - offset, 0, limit);
156282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
157282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // Build the paged result set.
158282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        for (int i = offset; i < offset + numItems; i++) {
159282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            fillRow(c.newRow(), i);
160282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
161282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
162282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        extras.putStringArray(ContentResolver.EXTRA_HONORED_ARGS, new String[] {
163282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                ContentResolver.QUERY_ARG_OFFSET,
164282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                ContentResolver.QUERY_ARG_LIMIT
165282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        });
166282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        extras.putInt(ContentResolver.EXTRA_TOTAL_COUNT, recordsetSize);
167282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return c;
168282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
169eb490d6194bd79adbe144a1230fc126f4c180a2fJeff Brown
170eb490d6194bd79adbe144a1230fc126f4c180a2fJeff Brown    private AbstractWindowedCursor buildPagedWindowedResults(
171eb490d6194bd79adbe144a1230fc126f4c180a2fJeff Brown            Uri uri, Bundle queryArgs, int recordsetSize) {
172eb490d6194bd79adbe144a1230fc126f4c180a2fJeff Brown        int offset = getIntValue(ContentResolver.QUERY_ARG_OFFSET, queryArgs, uri, 0);
173eb490d6194bd79adbe144a1230fc126f4c180a2fJeff Brown        int limit = getIntValue(ContentResolver.QUERY_ARG_LIMIT, queryArgs, uri, recordsetSize);
174eb490d6194bd79adbe144a1230fc126f4c180a2fJeff Brown
175eb490d6194bd79adbe144a1230fc126f4c180a2fJeff Brown        int windowSize = limit - 1;
176eb490d6194bd79adbe144a1230fc126f4c180a2fJeff Brown
177eb490d6194bd79adbe144a1230fc126f4c180a2fJeff Brown        TestWindowedCursor c = new TestWindowedCursor(PROJECTION, recordsetSize);
178eb490d6194bd79adbe144a1230fc126f4c180a2fJeff Brown        CursorWindow window = c.getWindow();
179eb490d6194bd79adbe144a1230fc126f4c180a2fJeff Brown        window.setNumColumns(PROJECTION.length);
180eb490d6194bd79adbe144a1230fc126f4c180a2fJeff Brown
181eb490d6194bd79adbe144a1230fc126f4c180a2fJeff Brown        Bundle extras = c.getExtras();
182eb490d6194bd79adbe144a1230fc126f4c180a2fJeff Brown
183eb490d6194bd79adbe144a1230fc126f4c180a2fJeff Brown        // Build the unpaged result set.
184eb490d6194bd79adbe144a1230fc126f4c180a2fJeff Brown        for (int row = 0; row < windowSize; row++) {
185eb490d6194bd79adbe144a1230fc126f4c180a2fJeff Brown            if (!window.allocRow()) {
186eb490d6194bd79adbe144a1230fc126f4c180a2fJeff Brown                break;
187eb490d6194bd79adbe144a1230fc126f4c180a2fJeff Brown            }
188eb490d6194bd79adbe144a1230fc126f4c180a2fJeff Brown            if (!fillRow(window, row)) {
189eb490d6194bd79adbe144a1230fc126f4c180a2fJeff Brown                window.freeLastRow();
190eb490d6194bd79adbe144a1230fc126f4c180a2fJeff Brown                break;
191eb490d6194bd79adbe144a1230fc126f4c180a2fJeff Brown            }
192eb490d6194bd79adbe144a1230fc126f4c180a2fJeff Brown        }
193eb490d6194bd79adbe144a1230fc126f4c180a2fJeff Brown
194eb490d6194bd79adbe144a1230fc126f4c180a2fJeff Brown        extras.putStringArray(ContentResolver.EXTRA_HONORED_ARGS, new String[] {
195eb490d6194bd79adbe144a1230fc126f4c180a2fJeff Brown                ContentResolver.QUERY_ARG_OFFSET,
196eb490d6194bd79adbe144a1230fc126f4c180a2fJeff Brown                ContentResolver.QUERY_ARG_LIMIT
197eb490d6194bd79adbe144a1230fc126f4c180a2fJeff Brown        });
198282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        extras.putInt(ContentResolver.EXTRA_TOTAL_COUNT, recordsetSize);
199282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return c;
200282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
201282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
202282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    private MatrixCursor buildUnpagedResults(int recordsetSize) {
203282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        MatrixCursor c = createInMemoryCursor();
204282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
2057cce7bb5d8d68e78a414c176dc89a803f706c9ceChet Haase        // Build the unpaged result set.
206282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        for (int i = 0; i < recordsetSize; i++) {
207282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            fillRow(c.newRow(), i);
208282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
209282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
210282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return c;
211282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
212282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
213282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    /**
214282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * Returns data type of the given object's value.
215282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     *<p>
216282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * Returned values are
217282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * <ul>
218282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     *   <li>{@link Cursor#FIELD_TYPE_NULL}</li>
219282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     *   <li>{@link Cursor#FIELD_TYPE_INTEGER}</li>
220282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     *   <li>{@link Cursor#FIELD_TYPE_FLOAT}</li>
221282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     *   <li>{@link Cursor#FIELD_TYPE_STRING}</li>
222282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     *   <li>{@link Cursor#FIELD_TYPE_BLOB}</li>
223282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     *</ul>
224282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     *</p>
225282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     */
226282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    public static int getTypeOfObject(Object obj) {
227282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (obj == null) {
228282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            return Cursor.FIELD_TYPE_NULL;
229282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        } else if (obj instanceof byte[]) {
230282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            return Cursor.FIELD_TYPE_BLOB;
231282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        } else if (obj instanceof Float || obj instanceof Double) {
232282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            return Cursor.FIELD_TYPE_FLOAT;
233282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        } else if (obj instanceof Long || obj instanceof Integer
234282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                || obj instanceof Short || obj instanceof Byte) {
235282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            return Cursor.FIELD_TYPE_INTEGER;
236282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        } else {
237282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            return Cursor.FIELD_TYPE_STRING;
238282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
239282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
240282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
241282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    private MatrixCursor createInMemoryCursor() {
242282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        MatrixCursor c = new MatrixCursor(PROJECTION);
243282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        Bundle extras = new Bundle();
244282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        c.setExtras(extras);
245282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return c;
246282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
247282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
248282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    private void fillRow(RowBuilder row, int rowId) {
249282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        row.add(createCellValue(rowId, 0));
250282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        row.add(createCellValue(rowId, 1));
251282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        row.add(createCellValue(rowId, 2));
252282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        row.add(createCellValue(rowId, 3));
253282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        row.add(createCellValue(rowId, 4));
254282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
255282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
256282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    /**
257282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * @return true if the row was successfully populated. If false, caller should freeLastRow.
258282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     */
259282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    private static boolean fillRow(CursorWindow window, int row) {
260282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (!window.putLong((int) createCellValue(row, 0), row, 0)) {
261282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            return false;
262282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
263282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        for (int i = 1; i < PROJECTION.length; i++) {
264282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (!window.putString((String) createCellValue(row, i), row, i)) {
265282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                return false;
266282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
267282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
268282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return true;
269282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
270282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
271282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    private static Object createCellValue(int row, int col) {
272282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        switch(col) {
273282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            case 0:
274282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                return row;
275282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            case 1:
276282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                return "--aaa--" + row;
277282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            case 2:
278282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                return "**bbb**" + row;
279282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            case 3:
280282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                return ("^^ccc^^" + row);
281282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            case 4:
282282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                return "##ddd##" + row;
283282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            default:
284282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                throw new IllegalArgumentException("Unsupported column: " + col);
285282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
286282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
287282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
288282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    /**
289282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * Asserts that the value at the current cursor position x column
290282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * is expected test data for the supplied row.
291282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     *
292282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * <p>Cursor must be pre-positioned.
293282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     *
294282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * @param cursor must be prepositioned to the row to be tested.
295282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * @param row row value expected to be reflected in cell. This can be different
296282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     *            than the cursor position due to paging.
297282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * @param column
298282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     */
299282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    @VisibleForTesting
300282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    public static void assertExpectedCellValue(Cursor cursor, int row, int column) {
301282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        int type = cursor.getType(column);
302282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        switch(type) {
303282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            case Cursor.FIELD_TYPE_NULL:
304282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                throw new UnsupportedOperationException("Not implemented.");
305282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            case Cursor.FIELD_TYPE_INTEGER:
306282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                assertEquals(createCellValue(row, column), cursor.getInt(column));
307282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                break;
308282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            case Cursor.FIELD_TYPE_FLOAT:
309282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                assertEquals(createCellValue(row, column), cursor.getDouble(column));
310282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                break;
311282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            case Cursor.FIELD_TYPE_BLOB:
312282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                assertEquals(createCellValue(row, column), cursor.getBlob(column));
313282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                break;
314282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            case Cursor.FIELD_TYPE_STRING:
315282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                assertEquals(createCellValue(row, column), cursor.getString(column));
316282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                break;
317282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            default:
318282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                throw new UnsupportedOperationException("Unknown column type: " + type);
319282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
320282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
321282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
322282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    @Override
323282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    public String getType(Uri uri) {
324282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        throw new UnsupportedOperationException();
325282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
326282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
327282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    @Override
328282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    public Uri insert(Uri uri, ContentValues values) {
329282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        throw new UnsupportedOperationException();
330282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
331282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
332282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    @Override
333282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    public int delete(Uri uri, String selection, String[] selectionArgs) {
334282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        throw new UnsupportedOperationException();
335282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
336282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
337282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    @Override
338282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
339282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        throw new UnsupportedOperationException();
340282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
341282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
342282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    private static int constrain(int amount, int low, int high) {
343282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return amount < low ? low : (amount > high ? high : amount);
344282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
345282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
346282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    /**
347282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * Returns a Uri that includes paging information embedded in the URI.
348282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * This allows a test client to force paged results when running on older SDKs...
349282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * pre Android O SDKs lacking the ContentResolver#query w/ Bundle override
350282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * necessary for paging.
351282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     */
352282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    public static Uri forcePagingSpec(Uri uri, int offset, int limit) {
353282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        assert (uri.getPath().equals(TestContentProvider.PAGED_PATH)
354282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                || uri.getPath().equals(TestContentProvider.PAGED_WINDOWED_PATH));
355282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return uri.buildUpon()
356282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                .appendQueryParameter(ContentResolver.QUERY_ARG_OFFSET, String.valueOf(offset))
357282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                .appendQueryParameter(ContentResolver.QUERY_ARG_LIMIT, String.valueOf(limit))
358282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                .build();
359282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
360282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
361282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    public static Uri forceRecordCount(Uri uri, int recordCount) {
362282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return uri.buildUpon()
363282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                .appendQueryParameter(RECORD_COUNT, String.valueOf(recordCount))
364282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                .build();
365282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
366282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
367282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    private static final class TestWindowedCursor extends AbstractWindowedCursor {
368282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
369282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        private final String[] mProjection;
370282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        private final int mCount;
371282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        private final Bundle mExtras;
372282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
373282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        TestWindowedCursor(String[] projection, int count) {
374282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            mProjection = projection;
375282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            mCount = count;
376282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            mExtras = new Bundle();
377282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
378282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            setWindow(new CursorWindow("stevie"));
379282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
380282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
381282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        @Override
382282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        public Bundle getExtras() {
383282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            return mExtras;
384282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
385282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
386282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        @Override
387282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        public int getCount() {
388282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            return mCount;
389282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
390282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
391282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        @Override
392282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        public String[] getColumnNames() {
393282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            return mProjection;
394282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
395282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
396282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
397282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski