1/*
2 * Copyright (C) 2010 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.content;
18
19import android.database.Cursor;
20import android.net.Uri;
21import android.os.CancellationSignal;
22import android.os.OperationCanceledException;
23
24import java.io.FileDescriptor;
25import java.io.PrintWriter;
26import java.util.Arrays;
27
28/**
29 * A loader that queries the {@link ContentResolver} and returns a {@link Cursor}.
30 * This class implements the {@link Loader} protocol in a standard way for
31 * querying cursors, building on {@link AsyncTaskLoader} to perform the cursor
32 * query on a background thread so that it does not block the application's UI.
33 *
34 * <p>A CursorLoader must be built with the full information for the query to
35 * perform, either through the
36 * {@link #CursorLoader(Context, Uri, String[], String, String[], String)} or
37 * creating an empty instance with {@link #CursorLoader(Context)} and filling
38 * in the desired paramters with {@link #setUri(Uri)}, {@link #setSelection(String)},
39 * {@link #setSelectionArgs(String[])}, {@link #setSortOrder(String)},
40 * and {@link #setProjection(String[])}.
41 *
42 * @deprecated Use the <a href="{@docRoot}tools/extras/support-library.html">Support Library</a>
43 *      {@link android.support.v4.content.CursorLoader}
44 */
45@Deprecated
46public class CursorLoader extends AsyncTaskLoader<Cursor> {
47    final ForceLoadContentObserver mObserver;
48
49    Uri mUri;
50    String[] mProjection;
51    String mSelection;
52    String[] mSelectionArgs;
53    String mSortOrder;
54
55    Cursor mCursor;
56    CancellationSignal mCancellationSignal;
57
58    /* Runs on a worker thread */
59    @Override
60    public Cursor loadInBackground() {
61        synchronized (this) {
62            if (isLoadInBackgroundCanceled()) {
63                throw new OperationCanceledException();
64            }
65            mCancellationSignal = new CancellationSignal();
66        }
67        try {
68            Cursor cursor = getContext().getContentResolver().query(mUri, mProjection, mSelection,
69                    mSelectionArgs, mSortOrder, mCancellationSignal);
70            if (cursor != null) {
71                try {
72                    // Ensure the cursor window is filled.
73                    cursor.getCount();
74                    cursor.registerContentObserver(mObserver);
75                } catch (RuntimeException ex) {
76                    cursor.close();
77                    throw ex;
78                }
79            }
80            return cursor;
81        } finally {
82            synchronized (this) {
83                mCancellationSignal = null;
84            }
85        }
86    }
87
88    @Override
89    public void cancelLoadInBackground() {
90        super.cancelLoadInBackground();
91
92        synchronized (this) {
93            if (mCancellationSignal != null) {
94                mCancellationSignal.cancel();
95            }
96        }
97    }
98
99    /* Runs on the UI thread */
100    @Override
101    public void deliverResult(Cursor cursor) {
102        if (isReset()) {
103            // An async query came in while the loader is stopped
104            if (cursor != null) {
105                cursor.close();
106            }
107            return;
108        }
109        Cursor oldCursor = mCursor;
110        mCursor = cursor;
111
112        if (isStarted()) {
113            super.deliverResult(cursor);
114        }
115
116        if (oldCursor != null && oldCursor != cursor && !oldCursor.isClosed()) {
117            oldCursor.close();
118        }
119    }
120
121    /**
122     * Creates an empty unspecified CursorLoader.  You must follow this with
123     * calls to {@link #setUri(Uri)}, {@link #setSelection(String)}, etc
124     * to specify the query to perform.
125     */
126    public CursorLoader(Context context) {
127        super(context);
128        mObserver = new ForceLoadContentObserver();
129    }
130
131    /**
132     * Creates a fully-specified CursorLoader.  See
133     * {@link ContentResolver#query(Uri, String[], String, String[], String)
134     * ContentResolver.query()} for documentation on the meaning of the
135     * parameters.  These will be passed as-is to that call.
136     */
137    public CursorLoader(Context context, Uri uri, String[] projection, String selection,
138            String[] selectionArgs, String sortOrder) {
139        super(context);
140        mObserver = new ForceLoadContentObserver();
141        mUri = uri;
142        mProjection = projection;
143        mSelection = selection;
144        mSelectionArgs = selectionArgs;
145        mSortOrder = sortOrder;
146    }
147
148    /**
149     * Starts an asynchronous load of the data. When the result is ready the callbacks
150     * will be called on the UI thread. If a previous load has been completed and is still valid
151     * the result may be passed to the callbacks immediately.
152     *
153     * Must be called from the UI thread
154     */
155    @Override
156    protected void onStartLoading() {
157        if (mCursor != null) {
158            deliverResult(mCursor);
159        }
160        if (takeContentChanged() || mCursor == null) {
161            forceLoad();
162        }
163    }
164
165    /**
166     * Must be called from the UI thread
167     */
168    @Override
169    protected void onStopLoading() {
170        // Attempt to cancel the current load task if possible.
171        cancelLoad();
172    }
173
174    @Override
175    public void onCanceled(Cursor cursor) {
176        if (cursor != null && !cursor.isClosed()) {
177            cursor.close();
178        }
179    }
180
181    @Override
182    protected void onReset() {
183        super.onReset();
184
185        // Ensure the loader is stopped
186        onStopLoading();
187
188        if (mCursor != null && !mCursor.isClosed()) {
189            mCursor.close();
190        }
191        mCursor = null;
192    }
193
194    public Uri getUri() {
195        return mUri;
196    }
197
198    public void setUri(Uri uri) {
199        mUri = uri;
200    }
201
202    public String[] getProjection() {
203        return mProjection;
204    }
205
206    public void setProjection(String[] projection) {
207        mProjection = projection;
208    }
209
210    public String getSelection() {
211        return mSelection;
212    }
213
214    public void setSelection(String selection) {
215        mSelection = selection;
216    }
217
218    public String[] getSelectionArgs() {
219        return mSelectionArgs;
220    }
221
222    public void setSelectionArgs(String[] selectionArgs) {
223        mSelectionArgs = selectionArgs;
224    }
225
226    public String getSortOrder() {
227        return mSortOrder;
228    }
229
230    public void setSortOrder(String sortOrder) {
231        mSortOrder = sortOrder;
232    }
233
234    @Override
235    public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
236        super.dump(prefix, fd, writer, args);
237        writer.print(prefix); writer.print("mUri="); writer.println(mUri);
238        writer.print(prefix); writer.print("mProjection=");
239                writer.println(Arrays.toString(mProjection));
240        writer.print(prefix); writer.print("mSelection="); writer.println(mSelection);
241        writer.print(prefix); writer.print("mSelectionArgs=");
242                writer.println(Arrays.toString(mSelectionArgs));
243        writer.print(prefix); writer.print("mSortOrder="); writer.println(mSortOrder);
244        writer.print(prefix); writer.print("mCursor="); writer.println(mCursor);
245        writer.print(prefix); writer.print("mContentChanged="); writer.println(mContentChanged);
246    }
247}
248