ContentResolverCompat.java revision 3ac77bf186f87ecad4bf0063b2f6c4384efbd56a
1/*
2 * Copyright (C) 2013 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.support.v4.content;
18
19import android.content.ContentResolver;
20import android.database.Cursor;
21import android.net.Uri;
22import android.os.Build;
23import android.support.v4.os.CancellationSignal;
24import android.support.v4.os.OperationCanceledException;
25
26/**
27 * Helper for accessing features in {@link android.content.ContentResolver}
28 * introduced after API level 4 in a backwards compatible fashion.
29 */
30public final class ContentResolverCompat {
31    interface ContentResolverCompatImpl {
32        Cursor query(ContentResolver resolver,
33                Uri uri, String[] projection, String selection, String[] selectionArgs,
34                String sortOrder, CancellationSignal cancellationSignal);
35    }
36
37    static class ContentResolverCompatImplBase implements ContentResolverCompatImpl {
38        @Override
39        public Cursor query(ContentResolver resolver, Uri uri, String[] projection,
40                String selection, String[] selectionArgs, String sortOrder,
41                CancellationSignal cancellationSignal) {
42            // Note that the cancellation signal cannot cancel the query in progress
43            // prior to Jellybean so we cancel it preemptively here if needed.
44            if (cancellationSignal != null) {
45                cancellationSignal.throwIfCanceled();
46            }
47            return resolver.query(uri, projection, selection, selectionArgs, sortOrder);
48        }
49    }
50
51    static class ContentResolverCompatImplJB extends ContentResolverCompatImplBase {
52        @Override
53        public Cursor query(ContentResolver resolver, Uri uri, String[] projection,
54                String selection, String[] selectionArgs, String sortOrder,
55                CancellationSignal cancellationSignal) {
56            try {
57                return ContentResolverCompatJellybean.query(resolver,
58                        uri, projection, selection, selectionArgs, sortOrder,
59                        cancellationSignal != null ?
60                                cancellationSignal.getCancellationSignalObject() : null);
61            } catch (Exception e) {
62                if (ContentResolverCompatJellybean.isFrameworkOperationCanceledException(e)) {
63                    // query() can throw a framework OperationCanceledException if it has been
64                    // canceled. We catch that and throw the support version instead.
65                    throw new OperationCanceledException();
66                } else {
67                    // If it's not a framework OperationCanceledException, re-throw the exception
68                    throw e;
69                }
70            }
71        }
72    }
73
74    private static final ContentResolverCompatImpl IMPL;
75    static {
76        final int version = Build.VERSION.SDK_INT;
77        if (version >= 16) {
78            IMPL = new ContentResolverCompatImplJB();
79        } else {
80            IMPL = new ContentResolverCompatImplBase();
81        }
82    }
83
84    private ContentResolverCompat() {
85        /* Hide constructor */
86    }
87
88    /**
89     * Query the given URI, returning a {@link Cursor} over the result set
90     * with optional support for cancellation.
91     * <p>
92     * For best performance, the caller should follow these guidelines:
93     * <ul>
94     * <li>Provide an explicit projection, to prevent
95     * reading data from storage that aren't going to be used.</li>
96     * <li>Use question mark parameter markers such as 'phone=?' instead of
97     * explicit values in the {@code selection} parameter, so that queries
98     * that differ only by those values will be recognized as the same
99     * for caching purposes.</li>
100     * </ul>
101     * </p>
102     *
103     * @param uri The URI, using the content:// scheme, for the content to
104     *         retrieve.
105     * @param projection A list of which columns to return. Passing null will
106     *         return all columns, which is inefficient.
107     * @param selection A filter declaring which rows to return, formatted as an
108     *         SQL WHERE clause (excluding the WHERE itself). Passing null will
109     *         return all rows for the given URI.
110     * @param selectionArgs You may include ?s in selection, which will be
111     *         replaced by the values from selectionArgs, in the order that they
112     *         appear in the selection. The values will be bound as Strings.
113     * @param sortOrder How to order the rows, formatted as an SQL ORDER BY
114     *         clause (excluding the ORDER BY itself). Passing null will use the
115     *         default sort order, which may be unordered.
116     * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
117     * If the operation is canceled, then {@link OperationCanceledException} will be thrown
118     * when the query is executed.
119     * @return A Cursor object, which is positioned before the first entry, or null
120     * @see Cursor
121     */
122    public static Cursor query(ContentResolver resolver,
123            Uri uri, String[] projection, String selection, String[] selectionArgs,
124            String sortOrder, CancellationSignal cancellationSignal) {
125        return IMPL.query(resolver, uri, projection, selection, selectionArgs,
126                sortOrder, cancellationSignal);
127    }
128}
129