1220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown/*
2220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown * Copyright (C) 2013 The Android Open Source Project
3220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown *
4220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown * Licensed under the Apache License, Version 2.0 (the "License");
5220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown * you may not use this file except in compliance with the License.
6220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown * You may obtain a copy of the License at
7220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown *
8220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown *      http://www.apache.org/licenses/LICENSE-2.0
9220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown *
10220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown * Unless required by applicable law or agreed to in writing, software
11220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown * distributed under the License is distributed on an "AS IS" BASIS,
12220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown * See the License for the specific language governing permissions and
14220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown * limitations under the License.
15220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown */
16220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown
17220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brownpackage android.support.v4.content;
18220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown
19220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brownimport android.content.ContentResolver;
20220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brownimport android.database.Cursor;
21220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brownimport android.net.Uri;
22220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brownimport android.os.Build;
23220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brownimport android.support.v4.os.CancellationSignal;
24220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brownimport android.support.v4.os.OperationCanceledException;
25220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown
26220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown/**
27220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown * Helper for accessing features in {@link android.content.ContentResolver}
28220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown * introduced after API level 4 in a backwards compatible fashion.
29220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown */
30c5847d13e40f5d52459f5c0dab32dc08f1a9a683Chris Banespublic final class ContentResolverCompat {
31220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown    interface ContentResolverCompatImpl {
32220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown        Cursor query(ContentResolver resolver,
33220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown                Uri uri, String[] projection, String selection, String[] selectionArgs,
34220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown                String sortOrder, CancellationSignal cancellationSignal);
35220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown    }
36220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown
37220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown    static class ContentResolverCompatImplBase implements ContentResolverCompatImpl {
38220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown        @Override
39220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown        public Cursor query(ContentResolver resolver, Uri uri, String[] projection,
40220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown                String selection, String[] selectionArgs, String sortOrder,
41220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown                CancellationSignal cancellationSignal) {
42220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown            // Note that the cancellation signal cannot cancel the query in progress
43220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown            // prior to Jellybean so we cancel it preemptively here if needed.
44220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown            if (cancellationSignal != null) {
45220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown                cancellationSignal.throwIfCanceled();
46220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown            }
47220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown            return resolver.query(uri, projection, selection, selectionArgs, sortOrder);
48220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown        }
49220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown    }
50220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown
51220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown    static class ContentResolverCompatImplJB extends ContentResolverCompatImplBase {
52220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown        @Override
53220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown        public Cursor query(ContentResolver resolver, Uri uri, String[] projection,
54220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown                String selection, String[] selectionArgs, String sortOrder,
55220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown                CancellationSignal cancellationSignal) {
5694d7acd9d29354189ef9c7caeb372363043f7df7Chris Banes            try {
5794d7acd9d29354189ef9c7caeb372363043f7df7Chris Banes                return ContentResolverCompatJellybean.query(resolver,
5894d7acd9d29354189ef9c7caeb372363043f7df7Chris Banes                        uri, projection, selection, selectionArgs, sortOrder,
5994d7acd9d29354189ef9c7caeb372363043f7df7Chris Banes                        cancellationSignal != null ?
6094d7acd9d29354189ef9c7caeb372363043f7df7Chris Banes                                cancellationSignal.getCancellationSignalObject() : null);
6194d7acd9d29354189ef9c7caeb372363043f7df7Chris Banes            } catch (Exception e) {
6294d7acd9d29354189ef9c7caeb372363043f7df7Chris Banes                if (ContentResolverCompatJellybean.isFrameworkOperationCanceledException(e)) {
6394d7acd9d29354189ef9c7caeb372363043f7df7Chris Banes                    // query() can throw a framework OperationCanceledException if it has been
6494d7acd9d29354189ef9c7caeb372363043f7df7Chris Banes                    // canceled. We catch that and throw the support version instead.
6594d7acd9d29354189ef9c7caeb372363043f7df7Chris Banes                    throw new OperationCanceledException();
6694d7acd9d29354189ef9c7caeb372363043f7df7Chris Banes                } else {
6794d7acd9d29354189ef9c7caeb372363043f7df7Chris Banes                    // If it's not a framework OperationCanceledException, re-throw the exception
6894d7acd9d29354189ef9c7caeb372363043f7df7Chris Banes                    throw e;
6994d7acd9d29354189ef9c7caeb372363043f7df7Chris Banes                }
7094d7acd9d29354189ef9c7caeb372363043f7df7Chris Banes            }
71220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown        }
72220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown    }
73220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown
74220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown    private static final ContentResolverCompatImpl IMPL;
75220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown    static {
76220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown        final int version = Build.VERSION.SDK_INT;
77220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown        if (version >= 16) {
78220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown            IMPL = new ContentResolverCompatImplJB();
79220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown        } else {
80220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown            IMPL = new ContentResolverCompatImplBase();
81220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown        }
82220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown    }
83220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown
84220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown    private ContentResolverCompat() {
85220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown        /* Hide constructor */
86220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown    }
87220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown
88220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown    /**
89220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown     * Query the given URI, returning a {@link Cursor} over the result set
90220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown     * with optional support for cancellation.
91220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown     * <p>
92220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown     * For best performance, the caller should follow these guidelines:
93220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown     * <ul>
94220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown     * <li>Provide an explicit projection, to prevent
95220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown     * reading data from storage that aren't going to be used.</li>
96220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown     * <li>Use question mark parameter markers such as 'phone=?' instead of
97220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown     * explicit values in the {@code selection} parameter, so that queries
98220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown     * that differ only by those values will be recognized as the same
99220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown     * for caching purposes.</li>
100220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown     * </ul>
101220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown     * </p>
102220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown     *
103220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown     * @param uri The URI, using the content:// scheme, for the content to
104220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown     *         retrieve.
105220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown     * @param projection A list of which columns to return. Passing null will
106220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown     *         return all columns, which is inefficient.
107220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown     * @param selection A filter declaring which rows to return, formatted as an
108220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown     *         SQL WHERE clause (excluding the WHERE itself). Passing null will
109220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown     *         return all rows for the given URI.
110220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown     * @param selectionArgs You may include ?s in selection, which will be
111220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown     *         replaced by the values from selectionArgs, in the order that they
112220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown     *         appear in the selection. The values will be bound as Strings.
113220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown     * @param sortOrder How to order the rows, formatted as an SQL ORDER BY
114220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown     *         clause (excluding the ORDER BY itself). Passing null will use the
115220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown     *         default sort order, which may be unordered.
116220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown     * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
117220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown     * If the operation is canceled, then {@link OperationCanceledException} will be thrown
118220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown     * when the query is executed.
119220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown     * @return A Cursor object, which is positioned before the first entry, or null
120220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown     * @see Cursor
121220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown     */
122220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown    public static Cursor query(ContentResolver resolver,
123220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown            Uri uri, String[] projection, String selection, String[] selectionArgs,
124220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown            String sortOrder, CancellationSignal cancellationSignal) {
125220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown        return IMPL.query(resolver, uri, projection, selection, selectionArgs,
126220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown                sortOrder, cancellationSignal);
127220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown    }
128220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown}
129