blob: fefd343691549e9d43dfb28c72925b5221df8348 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2006 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
Jeff Brownbaaf8c32011-10-09 14:07:00 -070019import dalvik.system.CloseGuard;
20
Brad Fitzpatricka63730d2010-02-07 22:25:34 -080021import android.accounts.Account;
Dianne Hackborncca1f0e2010-09-26 18:34:53 -070022import android.app.ActivityManagerNative;
Jeff Sharkey66a017b2013-01-17 18:18:22 -080023import android.app.ActivityThread;
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -070024import android.app.AppGlobals;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080025import android.content.pm.PackageManager.NameNotFoundException;
26import android.content.res.AssetFileDescriptor;
27import android.content.res.Resources;
28import android.database.ContentObserver;
Jeff Brown825c5132011-10-12 16:11:30 -070029import android.database.CrossProcessCursorWrapper;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080030import android.database.Cursor;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080031import android.database.IContentObserver;
32import android.net.Uri;
33import android.os.Bundle;
Jeff Browna7771df2012-05-07 20:06:46 -070034import android.os.CancellationSignal;
Dianne Hackborn6ae8d182012-05-23 13:12:42 -070035import android.os.DeadObjectException;
Dianne Hackborn231cc602009-04-27 17:10:36 -070036import android.os.IBinder;
Jeff Browna7771df2012-05-07 20:06:46 -070037import android.os.ICancellationSignal;
38import android.os.OperationCanceledException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080039import android.os.ParcelFileDescriptor;
40import android.os.RemoteException;
Dianne Hackborn231cc602009-04-27 17:10:36 -070041import android.os.ServiceManager;
Brad Fitzpatrickd72f7182010-02-11 17:07:51 -080042import android.os.SystemClock;
Dianne Hackborn5e03e2c2012-09-06 14:21:19 -070043import android.os.UserHandle;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080044import android.text.TextUtils;
Brad Fitzpatricka63730d2010-02-07 22:25:34 -080045import android.util.EventLog;
Dianne Hackborn231cc602009-04-27 17:10:36 -070046import android.util.Log;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080047
48import java.io.File;
49import java.io.FileInputStream;
50import java.io.FileNotFoundException;
51import java.io.IOException;
52import java.io.InputStream;
53import java.io.OutputStream;
Gilles Debunne03f02922010-06-09 14:11:45 -070054import java.util.ArrayList;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080055import java.util.List;
Brad Fitzpatricka63730d2010-02-07 22:25:34 -080056import java.util.Random;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080057
58
59/**
60 * This class provides applications access to the content model.
Joe Fernandez558459f2011-10-13 16:47:36 -070061 *
62 * <div class="special reference">
63 * <h3>Developer Guides</h3>
64 * <p>For more information about using a ContentResolver with content providers, read the
65 * <a href="{@docRoot}guide/topics/providers/content-providers.html">Content Providers</a>
66 * developer guide.</p>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080067 */
68public abstract class ContentResolver {
Fred Quintanaac9385e2009-06-22 18:00:59 -070069 /**
70 * @deprecated instead use
71 * {@link #requestSync(android.accounts.Account, String, android.os.Bundle)}
72 */
Fred Quintana4a6679b2009-08-17 13:05:39 -070073 @Deprecated
Fred Quintanaac9385e2009-06-22 18:00:59 -070074 public static final String SYNC_EXTRAS_ACCOUNT = "account";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080075 public static final String SYNC_EXTRAS_EXPEDITED = "expedited";
Fred Quintanaac9385e2009-06-22 18:00:59 -070076 /**
77 * @deprecated instead use
78 * {@link #SYNC_EXTRAS_MANUAL}
79 */
Fred Quintana4a6679b2009-08-17 13:05:39 -070080 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080081 public static final String SYNC_EXTRAS_FORCE = "force";
Fred Quintana53bd2522010-02-05 15:28:12 -080082
83 /**
84 * If this extra is set to true then the sync settings (like getSyncAutomatically())
85 * are ignored by the sync scheduler.
86 */
87 public static final String SYNC_EXTRAS_IGNORE_SETTINGS = "ignore_settings";
88
89 /**
90 * If this extra is set to true then any backoffs for the initial attempt (e.g. due to retries)
91 * are ignored by the sync scheduler. If this request fails and gets rescheduled then the
92 * retries will still honor the backoff.
93 */
94 public static final String SYNC_EXTRAS_IGNORE_BACKOFF = "ignore_backoff";
95
96 /**
97 * If this extra is set to true then the request will not be retried if it fails.
98 */
99 public static final String SYNC_EXTRAS_DO_NOT_RETRY = "do_not_retry";
100
101 /**
102 * Setting this extra is the equivalent of setting both {@link #SYNC_EXTRAS_IGNORE_SETTINGS}
103 * and {@link #SYNC_EXTRAS_IGNORE_BACKOFF}
104 */
Fred Quintanaac9385e2009-06-22 18:00:59 -0700105 public static final String SYNC_EXTRAS_MANUAL = "force";
Fred Quintana53bd2522010-02-05 15:28:12 -0800106
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800107 public static final String SYNC_EXTRAS_UPLOAD = "upload";
108 public static final String SYNC_EXTRAS_OVERRIDE_TOO_MANY_DELETIONS = "deletions_override";
109 public static final String SYNC_EXTRAS_DISCARD_LOCAL_DELETIONS = "discard_deletions";
110
Fred Quintana4a6679b2009-08-17 13:05:39 -0700111 /**
112 * Set by the SyncManager to request that the SyncAdapter initialize itself for
113 * the given account/authority pair. One required initialization step is to
114 * ensure that {@link #setIsSyncable(android.accounts.Account, String, int)} has been
115 * called with a >= 0 value. When this flag is set the SyncAdapter does not need to
116 * do a full sync, though it is allowed to do so.
117 */
118 public static final String SYNC_EXTRAS_INITIALIZE = "initialize";
119
Jeff Sharkey7a96c392012-11-15 14:01:46 -0800120 /** @hide */
121 public static final Intent ACTION_SYNC_CONN_STATUS_CHANGED =
122 new Intent("com.android.sync.SYNC_CONN_STATUS_CHANGED");
123
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800124 public static final String SCHEME_CONTENT = "content";
125 public static final String SCHEME_ANDROID_RESOURCE = "android.resource";
126 public static final String SCHEME_FILE = "file";
127
128 /**
129 * This is the Android platform's base MIME type for a content: URI
130 * containing a Cursor of a single item. Applications should use this
131 * as the base type along with their own sub-type of their content: URIs
132 * that represent a particular item. For example, hypothetical IMAP email
133 * client may have a URI
134 * <code>content://com.company.provider.imap/inbox/1</code> for a particular
135 * message in the inbox, whose MIME type would be reported as
136 * <code>CURSOR_ITEM_BASE_TYPE + "/vnd.company.imap-msg"</code>
Tom O'Neill0ba1cb02010-01-08 12:53:50 -0800137 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800138 * <p>Compare with {@link #CURSOR_DIR_BASE_TYPE}.
139 */
140 public static final String CURSOR_ITEM_BASE_TYPE = "vnd.android.cursor.item";
Tom O'Neill0ba1cb02010-01-08 12:53:50 -0800141
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800142 /**
143 * This is the Android platform's base MIME type for a content: URI
144 * containing a Cursor of zero or more items. Applications should use this
145 * as the base type along with their own sub-type of their content: URIs
146 * that represent a directory of items. For example, hypothetical IMAP email
147 * client may have a URI
148 * <code>content://com.company.provider.imap/inbox</code> for all of the
149 * messages in its inbox, whose MIME type would be reported as
150 * <code>CURSOR_DIR_BASE_TYPE + "/vnd.company.imap-msg"</code>
Tom O'Neill0ba1cb02010-01-08 12:53:50 -0800151 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800152 * <p>Note how the base MIME type varies between this and
153 * {@link #CURSOR_ITEM_BASE_TYPE} depending on whether there is
154 * one single item or multiple items in the data set, while the sub-type
155 * remains the same because in either case the data structure contained
156 * in the cursor is the same.
157 */
158 public static final String CURSOR_DIR_BASE_TYPE = "vnd.android.cursor.dir";
Fred Quintanaac9385e2009-06-22 18:00:59 -0700159
160 /** @hide */
161 public static final int SYNC_ERROR_SYNC_ALREADY_IN_PROGRESS = 1;
162 /** @hide */
163 public static final int SYNC_ERROR_AUTHENTICATION = 2;
164 /** @hide */
165 public static final int SYNC_ERROR_IO = 3;
166 /** @hide */
167 public static final int SYNC_ERROR_PARSE = 4;
168 /** @hide */
169 public static final int SYNC_ERROR_CONFLICT = 5;
170 /** @hide */
171 public static final int SYNC_ERROR_TOO_MANY_DELETIONS = 6;
172 /** @hide */
173 public static final int SYNC_ERROR_TOO_MANY_RETRIES = 7;
174 /** @hide */
175 public static final int SYNC_ERROR_INTERNAL = 8;
176
Alon Albert57286f92012-10-09 14:21:38 -0700177 private static final String[] SYNC_ERROR_NAMES = new String[] {
178 "already-in-progress",
179 "authentication-error",
180 "io-error",
181 "parse-error",
182 "conflict",
183 "too-many-deletions",
184 "too-many-retries",
185 "internal-error",
186 };
187
188 /** @hide */
Jeff Sharkey7a96c392012-11-15 14:01:46 -0800189 public static String syncErrorToString(int error) {
Alon Albert57286f92012-10-09 14:21:38 -0700190 if (error < 1 || error > SYNC_ERROR_NAMES.length) {
191 return String.valueOf(error);
192 }
193 return SYNC_ERROR_NAMES[error - 1];
194 }
195
Alon Albert5c113fa2013-02-07 08:07:32 -0800196 /** @hide */
197 public static int syncErrorStringToInt(String error) {
198 for (int i = 0, n = SYNC_ERROR_NAMES.length; i < n; i++) {
199 if (SYNC_ERROR_NAMES[i].equals(error)) {
200 return i + 1;
201 }
202 }
203 if (error != null) {
204 try {
205 return Integer.parseInt(error);
206 } catch (NumberFormatException e) {
207 Log.d(TAG, "error parsing sync error: " + error);
208 }
209 }
210 return 0;
211 }
212
Fred Quintanaac9385e2009-06-22 18:00:59 -0700213 public static final int SYNC_OBSERVER_TYPE_SETTINGS = 1<<0;
Fred Quintanaac9385e2009-06-22 18:00:59 -0700214 public static final int SYNC_OBSERVER_TYPE_PENDING = 1<<1;
Fred Quintanaac9385e2009-06-22 18:00:59 -0700215 public static final int SYNC_OBSERVER_TYPE_ACTIVE = 1<<2;
216 /** @hide */
217 public static final int SYNC_OBSERVER_TYPE_STATUS = 1<<3;
218 /** @hide */
219 public static final int SYNC_OBSERVER_TYPE_ALL = 0x7fffffff;
220
Brad Fitzpatrick25880962010-02-22 15:17:49 -0800221 // Always log queries which take 500ms+; shorter queries are
Brad Fitzpatricka63730d2010-02-07 22:25:34 -0800222 // sampled accordingly.
Brad Fitzpatrick25880962010-02-22 15:17:49 -0800223 private static final int SLOW_THRESHOLD_MILLIS = 500;
Brad Fitzpatricka63730d2010-02-07 22:25:34 -0800224 private final Random mRandom = new Random(); // guarded by itself
225
Dianne Hackborn231cc602009-04-27 17:10:36 -0700226 public ContentResolver(Context context) {
Jeff Sharkey66a017b2013-01-17 18:18:22 -0800227 mContext = context != null ? context : ActivityThread.currentApplication();
Jeff Sharkeye564a322013-01-28 15:52:43 -0800228 mPackageName = mContext.getBasePackageName();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800229 }
230
231 /** @hide */
232 protected abstract IContentProvider acquireProvider(Context c, String name);
Dianne Hackborncca1f0e2010-09-26 18:34:53 -0700233 /** Providing a default implementation of this, to avoid having to change
234 * a lot of other things, but implementations of ContentResolver should
235 * implement it. @hide */
236 protected IContentProvider acquireExistingProvider(Context c, String name) {
237 return acquireProvider(c, name);
238 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800239 /** @hide */
240 public abstract boolean releaseProvider(IContentProvider icp);
Dianne Hackborn652b6d12012-05-09 18:18:40 -0700241 /** @hide */
242 protected abstract IContentProvider acquireUnstableProvider(Context c, String name);
243 /** @hide */
244 public abstract boolean releaseUnstableProvider(IContentProvider icp);
Dianne Hackborn6ae8d182012-05-23 13:12:42 -0700245 /** @hide */
246 public abstract void unstableProviderDied(IContentProvider icp);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800247
248 /**
249 * Return the MIME type of the given content URL.
250 *
251 * @param url A Uri identifying content (either a list or specific type),
252 * using the content:// scheme.
253 * @return A MIME type for the content, or null if the URL is invalid or the type is unknown
254 */
Dianne Hackborn23fdaf62010-08-06 12:16:55 -0700255 public final String getType(Uri url) {
Dianne Hackborn6ae8d182012-05-23 13:12:42 -0700256 // XXX would like to have an acquireExistingUnstableProvider for this.
Dianne Hackborncca1f0e2010-09-26 18:34:53 -0700257 IContentProvider provider = acquireExistingProvider(url);
258 if (provider != null) {
259 try {
260 return provider.getType(url);
261 } catch (RemoteException e) {
262 return null;
263 } catch (java.lang.Exception e) {
Ola Olsson145e6c42010-12-20 16:45:35 +0100264 Log.w(TAG, "Failed to get type for: " + url + " (" + e.getMessage() + ")");
Dianne Hackborncca1f0e2010-09-26 18:34:53 -0700265 return null;
266 } finally {
267 releaseProvider(provider);
268 }
269 }
270
271 if (!SCHEME_CONTENT.equals(url.getScheme())) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800272 return null;
273 }
Dianne Hackborncca1f0e2010-09-26 18:34:53 -0700274
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800275 try {
Dianne Hackborn5e03e2c2012-09-06 14:21:19 -0700276 String type = ActivityManagerNative.getDefault().getProviderMimeType(
277 url, UserHandle.myUserId());
Dianne Hackborncca1f0e2010-09-26 18:34:53 -0700278 return type;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800279 } catch (RemoteException e) {
Brad Fitzpatrick534c84c2011-01-12 14:06:30 -0800280 // Arbitrary and not worth documenting, as Activity
281 // Manager will kill this process shortly anyway.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800282 return null;
Ola Olsson145e6c42010-12-20 16:45:35 +0100283 } catch (java.lang.Exception e) {
284 Log.w(TAG, "Failed to get type for: " + url + " (" + e.getMessage() + ")");
285 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800286 }
287 }
288
289 /**
Dianne Hackborn23fdaf62010-08-06 12:16:55 -0700290 * Query for the possible MIME types for the representations the given
291 * content URL can be returned when opened as as stream with
292 * {@link #openTypedAssetFileDescriptor}. Note that the types here are
293 * not necessarily a superset of the type returned by {@link #getType} --
294 * many content providers can not return a raw stream for the structured
295 * data that they contain.
296 *
297 * @param url A Uri identifying content (either a list or specific type),
298 * using the content:// scheme.
299 * @param mimeTypeFilter The desired MIME type. This may be a pattern,
300 * such as *\/*, to query for all available MIME types that match the
301 * pattern.
Dianne Hackbornacb69bb2012-04-13 15:36:06 -0700302 * @return Returns an array of MIME type strings for all available
Dianne Hackborn23fdaf62010-08-06 12:16:55 -0700303 * data streams that match the given mimeTypeFilter. If there are none,
304 * null is returned.
305 */
306 public String[] getStreamTypes(Uri url, String mimeTypeFilter) {
307 IContentProvider provider = acquireProvider(url);
308 if (provider == null) {
309 return null;
310 }
Dianne Hackborn64bbbb42010-09-27 20:25:20 -0700311
Dianne Hackborn23fdaf62010-08-06 12:16:55 -0700312 try {
313 return provider.getStreamTypes(url, mimeTypeFilter);
314 } catch (RemoteException e) {
Brad Fitzpatrick534c84c2011-01-12 14:06:30 -0800315 // Arbitrary and not worth documenting, as Activity
316 // Manager will kill this process shortly anyway.
Dianne Hackborn23fdaf62010-08-06 12:16:55 -0700317 return null;
Dianne Hackborn23fdaf62010-08-06 12:16:55 -0700318 } finally {
Brad Fitzpatrick534c84c2011-01-12 14:06:30 -0800319 releaseProvider(provider);
320 }
Dianne Hackborn23fdaf62010-08-06 12:16:55 -0700321 }
322
323 /**
Tom O'Neill0ba1cb02010-01-08 12:53:50 -0800324 * <p>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800325 * Query the given URI, returning a {@link Cursor} over the result set.
Tom O'Neill0ba1cb02010-01-08 12:53:50 -0800326 * </p>
327 * <p>
328 * For best performance, the caller should follow these guidelines:
329 * <ul>
330 * <li>Provide an explicit projection, to prevent
331 * reading data from storage that aren't going to be used.</li>
332 * <li>Use question mark parameter markers such as 'phone=?' instead of
333 * explicit values in the {@code selection} parameter, so that queries
334 * that differ only by those values will be recognized as the same
335 * for caching purposes.</li>
336 * </ul>
337 * </p>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800338 *
339 * @param uri The URI, using the content:// scheme, for the content to
340 * retrieve.
341 * @param projection A list of which columns to return. Passing null will
Tom O'Neill0ba1cb02010-01-08 12:53:50 -0800342 * return all columns, which is inefficient.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800343 * @param selection A filter declaring which rows to return, formatted as an
344 * SQL WHERE clause (excluding the WHERE itself). Passing null will
345 * return all rows for the given URI.
346 * @param selectionArgs You may include ?s in selection, which will be
347 * replaced by the values from selectionArgs, in the order that they
348 * appear in the selection. The values will be bound as Strings.
349 * @param sortOrder How to order the rows, formatted as an SQL ORDER BY
350 * clause (excluding the ORDER BY itself). Passing null will use the
351 * default sort order, which may be unordered.
352 * @return A Cursor object, which is positioned before the first entry, or null
353 * @see Cursor
354 */
355 public final Cursor query(Uri uri, String[] projection,
356 String selection, String[] selectionArgs, String sortOrder) {
Jeff Brown75ea64f2012-01-25 19:37:13 -0800357 return query(uri, projection, selection, selectionArgs, sortOrder, null);
358 }
359
360 /**
361 * <p>
362 * Query the given URI, returning a {@link Cursor} over the result set.
363 * </p>
364 * <p>
365 * For best performance, the caller should follow these guidelines:
366 * <ul>
367 * <li>Provide an explicit projection, to prevent
368 * reading data from storage that aren't going to be used.</li>
369 * <li>Use question mark parameter markers such as 'phone=?' instead of
370 * explicit values in the {@code selection} parameter, so that queries
371 * that differ only by those values will be recognized as the same
372 * for caching purposes.</li>
373 * </ul>
374 * </p>
375 *
376 * @param uri The URI, using the content:// scheme, for the content to
377 * retrieve.
378 * @param projection A list of which columns to return. Passing null will
379 * return all columns, which is inefficient.
380 * @param selection A filter declaring which rows to return, formatted as an
381 * SQL WHERE clause (excluding the WHERE itself). Passing null will
382 * return all rows for the given URI.
383 * @param selectionArgs You may include ?s in selection, which will be
384 * replaced by the values from selectionArgs, in the order that they
385 * appear in the selection. The values will be bound as Strings.
386 * @param sortOrder How to order the rows, formatted as an SQL ORDER BY
387 * clause (excluding the ORDER BY itself). Passing null will use the
388 * default sort order, which may be unordered.
Jeff Brown4c1241d2012-02-02 17:05:00 -0800389 * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
Jeff Brown75ea64f2012-01-25 19:37:13 -0800390 * If the operation is canceled, then {@link OperationCanceledException} will be thrown
391 * when the query is executed.
392 * @return A Cursor object, which is positioned before the first entry, or null
393 * @see Cursor
394 */
395 public final Cursor query(final Uri uri, String[] projection,
396 String selection, String[] selectionArgs, String sortOrder,
Jeff Brown4c1241d2012-02-02 17:05:00 -0800397 CancellationSignal cancellationSignal) {
Dianne Hackborn6ae8d182012-05-23 13:12:42 -0700398 IContentProvider unstableProvider = acquireUnstableProvider(uri);
399 if (unstableProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800400 return null;
401 }
Dianne Hackborn6ae8d182012-05-23 13:12:42 -0700402 IContentProvider stableProvider = null;
Jeff Brownc21b5a02013-01-07 17:15:12 -0800403 Cursor qCursor = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800404 try {
Brad Fitzpatrickd72f7182010-02-11 17:07:51 -0800405 long startTime = SystemClock.uptimeMillis();
Jeff Brown75ea64f2012-01-25 19:37:13 -0800406
Jeff Brown4c1241d2012-02-02 17:05:00 -0800407 ICancellationSignal remoteCancellationSignal = null;
408 if (cancellationSignal != null) {
409 cancellationSignal.throwIfCanceled();
Dianne Hackborn6ae8d182012-05-23 13:12:42 -0700410 remoteCancellationSignal = unstableProvider.createCancellationSignal();
Jeff Brown4c1241d2012-02-02 17:05:00 -0800411 cancellationSignal.setRemote(remoteCancellationSignal);
Jeff Brown75ea64f2012-01-25 19:37:13 -0800412 }
Dianne Hackborn6ae8d182012-05-23 13:12:42 -0700413 try {
Dianne Hackborn35654b62013-01-14 17:38:02 -0800414 qCursor = unstableProvider.query(mPackageName, uri, projection,
Dianne Hackborn6ae8d182012-05-23 13:12:42 -0700415 selection, selectionArgs, sortOrder, remoteCancellationSignal);
416 } catch (DeadObjectException e) {
417 // The remote process has died... but we only hold an unstable
418 // reference though, so we might recover!!! Let's try!!!!
419 // This is exciting!!1!!1!!!!1
420 unstableProviderDied(unstableProvider);
421 stableProvider = acquireProvider(uri);
422 if (stableProvider == null) {
423 return null;
424 }
Dianne Hackborn35654b62013-01-14 17:38:02 -0800425 qCursor = stableProvider.query(mPackageName, uri, projection,
Dianne Hackborn6ae8d182012-05-23 13:12:42 -0700426 selection, selectionArgs, sortOrder, remoteCancellationSignal);
427 }
Brad Fitzpatricka63730d2010-02-07 22:25:34 -0800428 if (qCursor == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800429 return null;
430 }
Jeff Brownc21b5a02013-01-07 17:15:12 -0800431
432 // Force query execution. Might fail and throw a runtime exception here.
Vasu Nori020e5342010-04-28 14:22:38 -0700433 qCursor.getCount();
Brad Fitzpatrickd72f7182010-02-11 17:07:51 -0800434 long durationMillis = SystemClock.uptimeMillis() - startTime;
Brad Fitzpatricka63730d2010-02-07 22:25:34 -0800435 maybeLogQueryToEventLog(durationMillis, uri, projection, selection, sortOrder);
Jeff Brownc21b5a02013-01-07 17:15:12 -0800436
437 // Wrap the cursor object into CursorWrapperInner object.
Dianne Hackborn6ae8d182012-05-23 13:12:42 -0700438 CursorWrapperInner wrapper = new CursorWrapperInner(qCursor,
439 stableProvider != null ? stableProvider : acquireProvider(uri));
440 stableProvider = null;
Jeff Brownc21b5a02013-01-07 17:15:12 -0800441 qCursor = null;
Dianne Hackborn6ae8d182012-05-23 13:12:42 -0700442 return wrapper;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800443 } catch (RemoteException e) {
Brad Fitzpatrick534c84c2011-01-12 14:06:30 -0800444 // Arbitrary and not worth documenting, as Activity
445 // Manager will kill this process shortly anyway.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800446 return null;
Dianne Hackborn6ae8d182012-05-23 13:12:42 -0700447 } finally {
Jeff Brownc21b5a02013-01-07 17:15:12 -0800448 if (qCursor != null) {
449 qCursor.close();
450 }
Dianne Hackborn6ae8d182012-05-23 13:12:42 -0700451 if (unstableProvider != null) {
452 releaseUnstableProvider(unstableProvider);
453 }
454 if (stableProvider != null) {
455 releaseProvider(stableProvider);
456 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800457 }
458 }
459
Fred Quintana89437372009-05-15 15:10:40 -0700460 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800461 * Open a stream on to the content associated with a content URI. If there
462 * is no data associated with the URI, FileNotFoundException is thrown.
463 *
464 * <h5>Accepts the following URI schemes:</h5>
465 * <ul>
466 * <li>content ({@link #SCHEME_CONTENT})</li>
467 * <li>android.resource ({@link #SCHEME_ANDROID_RESOURCE})</li>
468 * <li>file ({@link #SCHEME_FILE})</li>
469 * </ul>
Tom O'Neill0ba1cb02010-01-08 12:53:50 -0800470 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800471 * <p>See {@link #openAssetFileDescriptor(Uri, String)} for more information
472 * on these schemes.
Tom O'Neill0ba1cb02010-01-08 12:53:50 -0800473 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800474 * @param uri The desired URI.
475 * @return InputStream
476 * @throws FileNotFoundException if the provided URI could not be opened.
477 * @see #openAssetFileDescriptor(Uri, String)
478 */
479 public final InputStream openInputStream(Uri uri)
480 throws FileNotFoundException {
481 String scheme = uri.getScheme();
482 if (SCHEME_ANDROID_RESOURCE.equals(scheme)) {
483 // Note: left here to avoid breaking compatibility. May be removed
484 // with sufficient testing.
485 OpenResourceIdResult r = getResourceId(uri);
486 try {
487 InputStream stream = r.r.openRawResource(r.id);
488 return stream;
489 } catch (Resources.NotFoundException ex) {
490 throw new FileNotFoundException("Resource does not exist: " + uri);
491 }
492 } else if (SCHEME_FILE.equals(scheme)) {
493 // Note: left here to avoid breaking compatibility. May be removed
494 // with sufficient testing.
495 return new FileInputStream(uri.getPath());
496 } else {
497 AssetFileDescriptor fd = openAssetFileDescriptor(uri, "r");
498 try {
499 return fd != null ? fd.createInputStream() : null;
500 } catch (IOException e) {
501 throw new FileNotFoundException("Unable to create stream");
502 }
503 }
504 }
505
506 /**
507 * Synonym for {@link #openOutputStream(Uri, String)
508 * openOutputStream(uri, "w")}.
509 * @throws FileNotFoundException if the provided URI could not be opened.
510 */
511 public final OutputStream openOutputStream(Uri uri)
512 throws FileNotFoundException {
513 return openOutputStream(uri, "w");
514 }
515
516 /**
517 * Open a stream on to the content associated with a content URI. If there
518 * is no data associated with the URI, FileNotFoundException is thrown.
519 *
520 * <h5>Accepts the following URI schemes:</h5>
521 * <ul>
522 * <li>content ({@link #SCHEME_CONTENT})</li>
523 * <li>file ({@link #SCHEME_FILE})</li>
524 * </ul>
525 *
526 * <p>See {@link #openAssetFileDescriptor(Uri, String)} for more information
527 * on these schemes.
Tom O'Neill0ba1cb02010-01-08 12:53:50 -0800528 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800529 * @param uri The desired URI.
530 * @param mode May be "w", "wa", "rw", or "rwt".
531 * @return OutputStream
532 * @throws FileNotFoundException if the provided URI could not be opened.
533 * @see #openAssetFileDescriptor(Uri, String)
534 */
535 public final OutputStream openOutputStream(Uri uri, String mode)
536 throws FileNotFoundException {
537 AssetFileDescriptor fd = openAssetFileDescriptor(uri, mode);
538 try {
539 return fd != null ? fd.createOutputStream() : null;
540 } catch (IOException e) {
541 throw new FileNotFoundException("Unable to create stream");
542 }
543 }
544
545 /**
Dianne Hackborn23fdaf62010-08-06 12:16:55 -0700546 * Open a raw file descriptor to access data under a URI. This
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800547 * is like {@link #openAssetFileDescriptor(Uri, String)}, but uses the
548 * underlying {@link ContentProvider#openFile}
549 * ContentProvider.openFile()} method, so will <em>not</em> work with
550 * providers that return sub-sections of files. If at all possible,
551 * you should use {@link #openAssetFileDescriptor(Uri, String)}. You
552 * will receive a FileNotFoundException exception if the provider returns a
553 * sub-section of a file.
554 *
555 * <h5>Accepts the following URI schemes:</h5>
556 * <ul>
557 * <li>content ({@link #SCHEME_CONTENT})</li>
558 * <li>file ({@link #SCHEME_FILE})</li>
559 * </ul>
560 *
561 * <p>See {@link #openAssetFileDescriptor(Uri, String)} for more information
562 * on these schemes.
Tom O'Neill0ba1cb02010-01-08 12:53:50 -0800563 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800564 * @param uri The desired URI to open.
565 * @param mode The file mode to use, as per {@link ContentProvider#openFile
566 * ContentProvider.openFile}.
567 * @return Returns a new ParcelFileDescriptor pointing to the file. You
568 * own this descriptor and are responsible for closing it when done.
Yury Zhauniarovichf9c51762012-05-12 18:39:25 +0200569 * @throws FileNotFoundException Throws FileNotFoundException if no
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800570 * file exists under the URI or the mode is invalid.
571 * @see #openAssetFileDescriptor(Uri, String)
572 */
573 public final ParcelFileDescriptor openFileDescriptor(Uri uri,
574 String mode) throws FileNotFoundException {
575 AssetFileDescriptor afd = openAssetFileDescriptor(uri, mode);
576 if (afd == null) {
577 return null;
578 }
Tom O'Neill0ba1cb02010-01-08 12:53:50 -0800579
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800580 if (afd.getDeclaredLength() < 0) {
581 // This is a full file!
582 return afd.getParcelFileDescriptor();
583 }
Tom O'Neill0ba1cb02010-01-08 12:53:50 -0800584
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800585 // Client can't handle a sub-section of a file, so close what
586 // we got and bail with an exception.
587 try {
588 afd.close();
589 } catch (IOException e) {
590 }
Tom O'Neill0ba1cb02010-01-08 12:53:50 -0800591
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800592 throw new FileNotFoundException("Not a whole file");
593 }
594
595 /**
Dianne Hackborn23fdaf62010-08-06 12:16:55 -0700596 * Open a raw file descriptor to access data under a URI. This
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800597 * interacts with the underlying {@link ContentProvider#openAssetFile}
Gilles Debunne03f02922010-06-09 14:11:45 -0700598 * method of the provider associated with the given URI, to retrieve any file stored there.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800599 *
600 * <h5>Accepts the following URI schemes:</h5>
601 * <ul>
602 * <li>content ({@link #SCHEME_CONTENT})</li>
603 * <li>android.resource ({@link #SCHEME_ANDROID_RESOURCE})</li>
604 * <li>file ({@link #SCHEME_FILE})</li>
605 * </ul>
606 * <h5>The android.resource ({@link #SCHEME_ANDROID_RESOURCE}) Scheme</h5>
607 * <p>
608 * A Uri object can be used to reference a resource in an APK file. The
609 * Uri should be one of the following formats:
610 * <ul>
611 * <li><code>android.resource://package_name/id_number</code><br/>
612 * <code>package_name</code> is your package name as listed in your AndroidManifest.xml.
613 * For example <code>com.example.myapp</code><br/>
614 * <code>id_number</code> is the int form of the ID.<br/>
615 * The easiest way to construct this form is
616 * <pre>Uri uri = Uri.parse("android.resource://com.example.myapp/" + R.raw.my_resource");</pre>
617 * </li>
618 * <li><code>android.resource://package_name/type/name</code><br/>
619 * <code>package_name</code> is your package name as listed in your AndroidManifest.xml.
620 * For example <code>com.example.myapp</code><br/>
621 * <code>type</code> is the string form of the resource type. For example, <code>raw</code>
622 * or <code>drawable</code>.
623 * <code>name</code> is the string form of the resource name. That is, whatever the file
624 * name was in your res directory, without the type extension.
625 * The easiest way to construct this form is
626 * <pre>Uri uri = Uri.parse("android.resource://com.example.myapp/raw/my_resource");</pre>
627 * </li>
628 * </ul>
629 *
Dianne Hackborn23fdaf62010-08-06 12:16:55 -0700630 * <p>Note that if this function is called for read-only input (mode is "r")
631 * on a content: URI, it will instead call {@link #openTypedAssetFileDescriptor}
632 * for you with a MIME type of "*\/*". This allows such callers to benefit
633 * from any built-in data conversion that a provider implements.
634 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800635 * @param uri The desired URI to open.
636 * @param mode The file mode to use, as per {@link ContentProvider#openAssetFile
637 * ContentProvider.openAssetFile}.
638 * @return Returns a new ParcelFileDescriptor pointing to the file. You
639 * own this descriptor and are responsible for closing it when done.
640 * @throws FileNotFoundException Throws FileNotFoundException of no
641 * file exists under the URI or the mode is invalid.
642 */
643 public final AssetFileDescriptor openAssetFileDescriptor(Uri uri,
644 String mode) throws FileNotFoundException {
645 String scheme = uri.getScheme();
646 if (SCHEME_ANDROID_RESOURCE.equals(scheme)) {
647 if (!"r".equals(mode)) {
648 throw new FileNotFoundException("Can't write resources: " + uri);
649 }
650 OpenResourceIdResult r = getResourceId(uri);
651 try {
652 return r.r.openRawResourceFd(r.id);
653 } catch (Resources.NotFoundException ex) {
654 throw new FileNotFoundException("Resource does not exist: " + uri);
655 }
656 } else if (SCHEME_FILE.equals(scheme)) {
657 ParcelFileDescriptor pfd = ParcelFileDescriptor.open(
658 new File(uri.getPath()), modeToMode(uri, mode));
659 return new AssetFileDescriptor(pfd, 0, -1);
660 } else {
Dianne Hackborn23fdaf62010-08-06 12:16:55 -0700661 if ("r".equals(mode)) {
662 return openTypedAssetFileDescriptor(uri, "*/*", null);
663 } else {
Dianne Hackborn6ae8d182012-05-23 13:12:42 -0700664 IContentProvider unstableProvider = acquireUnstableProvider(uri);
665 if (unstableProvider == null) {
666 throw new FileNotFoundException("No content provider: " + uri);
667 }
668 IContentProvider stableProvider = null;
669 AssetFileDescriptor fd = null;
670
671 try {
Dianne Hackborn652b6d12012-05-09 18:18:40 -0700672 try {
Dianne Hackborn35654b62013-01-14 17:38:02 -0800673 fd = unstableProvider.openAssetFile(mPackageName, uri, mode);
Dianne Hackborn652b6d12012-05-09 18:18:40 -0700674 if (fd == null) {
675 // The provider will be released by the finally{} clause
676 return null;
677 }
Dianne Hackborn6ae8d182012-05-23 13:12:42 -0700678 } catch (DeadObjectException e) {
679 // The remote process has died... but we only hold an unstable
680 // reference though, so we might recover!!! Let's try!!!!
681 // This is exciting!!1!!1!!!!1
682 unstableProviderDied(unstableProvider);
683 stableProvider = acquireProvider(uri);
684 if (stableProvider == null) {
685 throw new FileNotFoundException("No content provider: " + uri);
Dianne Hackborn652b6d12012-05-09 18:18:40 -0700686 }
Dianne Hackborn35654b62013-01-14 17:38:02 -0800687 fd = stableProvider.openAssetFile(mPackageName, uri, mode);
Dianne Hackborn6ae8d182012-05-23 13:12:42 -0700688 if (fd == null) {
689 // The provider will be released by the finally{} clause
690 return null;
Dianne Hackborn652b6d12012-05-09 18:18:40 -0700691 }
Dianne Hackborn23fdaf62010-08-06 12:16:55 -0700692 }
Dianne Hackborn6ae8d182012-05-23 13:12:42 -0700693
694 if (stableProvider == null) {
695 stableProvider = acquireProvider(uri);
696 }
697 releaseUnstableProvider(unstableProvider);
698 ParcelFileDescriptor pfd = new ParcelFileDescriptorInner(
699 fd.getParcelFileDescriptor(), stableProvider);
700
701 // Success! Don't release the provider when exiting, let
702 // ParcelFileDescriptorInner do that when it is closed.
703 stableProvider = null;
704
705 return new AssetFileDescriptor(pfd, fd.getStartOffset(),
706 fd.getDeclaredLength());
707
708 } catch (RemoteException e) {
709 // Whatever, whatever, we'll go away.
710 throw new FileNotFoundException(
711 "Failed opening content provider: " + uri);
712 } catch (FileNotFoundException e) {
713 throw e;
714 } finally {
715 if (stableProvider != null) {
716 releaseProvider(stableProvider);
717 }
718 if (unstableProvider != null) {
719 releaseUnstableProvider(unstableProvider);
720 }
Dianne Hackborn23fdaf62010-08-06 12:16:55 -0700721 }
722 }
723 }
724 }
725
726 /**
727 * Open a raw file descriptor to access (potentially type transformed)
728 * data from a "content:" URI. This interacts with the underlying
729 * {@link ContentProvider#openTypedAssetFile} method of the provider
730 * associated with the given URI, to retrieve retrieve any appropriate
731 * data stream for the data stored there.
732 *
733 * <p>Unlike {@link #openAssetFileDescriptor}, this function only works
734 * with "content:" URIs, because content providers are the only facility
735 * with an associated MIME type to ensure that the returned data stream
736 * is of the desired type.
737 *
738 * <p>All text/* streams are encoded in UTF-8.
739 *
740 * @param uri The desired URI to open.
741 * @param mimeType The desired MIME type of the returned data. This can
742 * be a pattern such as *\/*, which will allow the content provider to
743 * select a type, though there is no way for you to determine what type
744 * it is returning.
745 * @param opts Additional provider-dependent options.
746 * @return Returns a new ParcelFileDescriptor from which you can read the
747 * data stream from the provider. Note that this may be a pipe, meaning
748 * you can't seek in it. The only seek you should do is if the
749 * AssetFileDescriptor contains an offset, to move to that offset before
750 * reading. You own this descriptor and are responsible for closing it when done.
751 * @throws FileNotFoundException Throws FileNotFoundException of no
752 * data of the desired type exists under the URI.
753 */
754 public final AssetFileDescriptor openTypedAssetFileDescriptor(Uri uri,
755 String mimeType, Bundle opts) throws FileNotFoundException {
Dianne Hackborn6ae8d182012-05-23 13:12:42 -0700756 IContentProvider unstableProvider = acquireUnstableProvider(uri);
757 if (unstableProvider == null) {
758 throw new FileNotFoundException("No content provider: " + uri);
759 }
760 IContentProvider stableProvider = null;
761 AssetFileDescriptor fd = null;
762
763 try {
Dianne Hackborn652b6d12012-05-09 18:18:40 -0700764 try {
Dianne Hackborn35654b62013-01-14 17:38:02 -0800765 fd = unstableProvider.openTypedAssetFile(mPackageName, uri, mimeType, opts);
Dianne Hackborn652b6d12012-05-09 18:18:40 -0700766 if (fd == null) {
767 // The provider will be released by the finally{} clause
768 return null;
769 }
Dianne Hackborn6ae8d182012-05-23 13:12:42 -0700770 } catch (DeadObjectException e) {
771 // The remote process has died... but we only hold an unstable
772 // reference though, so we might recover!!! Let's try!!!!
773 // This is exciting!!1!!1!!!!1
774 unstableProviderDied(unstableProvider);
775 stableProvider = acquireProvider(uri);
776 if (stableProvider == null) {
777 throw new FileNotFoundException("No content provider: " + uri);
Dianne Hackborn652b6d12012-05-09 18:18:40 -0700778 }
Dianne Hackborn35654b62013-01-14 17:38:02 -0800779 fd = stableProvider.openTypedAssetFile(mPackageName, uri, mimeType, opts);
Dianne Hackborn6ae8d182012-05-23 13:12:42 -0700780 if (fd == null) {
781 // The provider will be released by the finally{} clause
782 return null;
Dianne Hackborn652b6d12012-05-09 18:18:40 -0700783 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800784 }
Dianne Hackborn6ae8d182012-05-23 13:12:42 -0700785
786 if (stableProvider == null) {
787 stableProvider = acquireProvider(uri);
788 }
789 releaseUnstableProvider(unstableProvider);
790 ParcelFileDescriptor pfd = new ParcelFileDescriptorInner(
791 fd.getParcelFileDescriptor(), stableProvider);
792
793 // Success! Don't release the provider when exiting, let
794 // ParcelFileDescriptorInner do that when it is closed.
795 stableProvider = null;
796
797 return new AssetFileDescriptor(pfd, fd.getStartOffset(),
798 fd.getDeclaredLength());
799
800 } catch (RemoteException e) {
801 // Whatever, whatever, we'll go away.
802 throw new FileNotFoundException(
803 "Failed opening content provider: " + uri);
804 } catch (FileNotFoundException e) {
805 throw e;
806 } finally {
807 if (stableProvider != null) {
808 releaseProvider(stableProvider);
809 }
810 if (unstableProvider != null) {
811 releaseUnstableProvider(unstableProvider);
812 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800813 }
814 }
815
Bjorn Bringert4c87a3f2009-09-16 15:59:37 +0100816 /**
817 * A resource identified by the {@link Resources} that contains it, and a resource id.
818 *
819 * @hide
820 */
821 public class OpenResourceIdResult {
822 public Resources r;
823 public int id;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800824 }
Bjorn Bringert4c87a3f2009-09-16 15:59:37 +0100825
826 /**
827 * Resolves an android.resource URI to a {@link Resources} and a resource id.
828 *
829 * @hide
830 */
831 public OpenResourceIdResult getResourceId(Uri uri) throws FileNotFoundException {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800832 String authority = uri.getAuthority();
833 Resources r;
834 if (TextUtils.isEmpty(authority)) {
835 throw new FileNotFoundException("No authority: " + uri);
836 } else {
837 try {
838 r = mContext.getPackageManager().getResourcesForApplication(authority);
839 } catch (NameNotFoundException ex) {
840 throw new FileNotFoundException("No package found for authority: " + uri);
841 }
842 }
843 List<String> path = uri.getPathSegments();
844 if (path == null) {
845 throw new FileNotFoundException("No path: " + uri);
846 }
847 int len = path.size();
848 int id;
849 if (len == 1) {
850 try {
851 id = Integer.parseInt(path.get(0));
852 } catch (NumberFormatException e) {
853 throw new FileNotFoundException("Single path segment is not a resource ID: " + uri);
854 }
855 } else if (len == 2) {
856 id = r.getIdentifier(path.get(1), path.get(0), authority);
857 } else {
858 throw new FileNotFoundException("More than two path segments: " + uri);
859 }
860 if (id == 0) {
861 throw new FileNotFoundException("No resource found for: " + uri);
862 }
863 OpenResourceIdResult res = new OpenResourceIdResult();
864 res.r = r;
865 res.id = id;
866 return res;
867 }
Tom O'Neill0ba1cb02010-01-08 12:53:50 -0800868
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800869 /** @hide */
870 static public int modeToMode(Uri uri, String mode) throws FileNotFoundException {
871 int modeBits;
872 if ("r".equals(mode)) {
873 modeBits = ParcelFileDescriptor.MODE_READ_ONLY;
874 } else if ("w".equals(mode) || "wt".equals(mode)) {
875 modeBits = ParcelFileDescriptor.MODE_WRITE_ONLY
876 | ParcelFileDescriptor.MODE_CREATE
877 | ParcelFileDescriptor.MODE_TRUNCATE;
878 } else if ("wa".equals(mode)) {
879 modeBits = ParcelFileDescriptor.MODE_WRITE_ONLY
880 | ParcelFileDescriptor.MODE_CREATE
881 | ParcelFileDescriptor.MODE_APPEND;
882 } else if ("rw".equals(mode)) {
883 modeBits = ParcelFileDescriptor.MODE_READ_WRITE
884 | ParcelFileDescriptor.MODE_CREATE;
885 } else if ("rwt".equals(mode)) {
886 modeBits = ParcelFileDescriptor.MODE_READ_WRITE
887 | ParcelFileDescriptor.MODE_CREATE
888 | ParcelFileDescriptor.MODE_TRUNCATE;
889 } else {
890 throw new FileNotFoundException("Bad mode for " + uri + ": "
891 + mode);
892 }
893 return modeBits;
894 }
Tom O'Neill0ba1cb02010-01-08 12:53:50 -0800895
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800896 /**
897 * Inserts a row into a table at the given URL.
898 *
899 * If the content provider supports transactions the insertion will be atomic.
900 *
901 * @param url The URL of the table to insert into.
902 * @param values The initial values for the newly inserted row. The key is the column name for
903 * the field. Passing an empty ContentValues will create an empty row.
904 * @return the URL of the newly created row.
905 */
906 public final Uri insert(Uri url, ContentValues values)
907 {
908 IContentProvider provider = acquireProvider(url);
909 if (provider == null) {
910 throw new IllegalArgumentException("Unknown URL " + url);
911 }
912 try {
Brad Fitzpatrickd72f7182010-02-11 17:07:51 -0800913 long startTime = SystemClock.uptimeMillis();
Dianne Hackborn35654b62013-01-14 17:38:02 -0800914 Uri createdRow = provider.insert(mPackageName, url, values);
Brad Fitzpatrickd72f7182010-02-11 17:07:51 -0800915 long durationMillis = SystemClock.uptimeMillis() - startTime;
Brad Fitzpatricka63730d2010-02-07 22:25:34 -0800916 maybeLogUpdateToEventLog(durationMillis, url, "insert", null /* where */);
917 return createdRow;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800918 } catch (RemoteException e) {
Brad Fitzpatrick534c84c2011-01-12 14:06:30 -0800919 // Arbitrary and not worth documenting, as Activity
920 // Manager will kill this process shortly anyway.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800921 return null;
922 } finally {
923 releaseProvider(provider);
924 }
925 }
926
Fred Quintana89437372009-05-15 15:10:40 -0700927 /**
Fred Quintana89437372009-05-15 15:10:40 -0700928 * Applies each of the {@link ContentProviderOperation} objects and returns an array
929 * of their results. Passes through OperationApplicationException, which may be thrown
930 * by the call to {@link ContentProviderOperation#apply}.
931 * If all the applications succeed then a {@link ContentProviderResult} array with the
932 * same number of elements as the operations will be returned. It is implementation-specific
933 * how many, if any, operations will have been successfully applied if a call to
934 * apply results in a {@link OperationApplicationException}.
935 * @param authority the authority of the ContentProvider to which this batch should be applied
936 * @param operations the operations to apply
937 * @return the results of the applications
938 * @throws OperationApplicationException thrown if an application fails.
939 * See {@link ContentProviderOperation#apply} for more information.
940 * @throws RemoteException thrown if a RemoteException is encountered while attempting
941 * to communicate with a remote provider.
942 */
943 public ContentProviderResult[] applyBatch(String authority,
Fred Quintana03d94902009-05-22 14:23:31 -0700944 ArrayList<ContentProviderOperation> operations)
Fred Quintana89437372009-05-15 15:10:40 -0700945 throws RemoteException, OperationApplicationException {
946 ContentProviderClient provider = acquireContentProviderClient(authority);
Fred Quintana6a8d5332009-05-07 17:35:38 -0700947 if (provider == null) {
Fred Quintana89437372009-05-15 15:10:40 -0700948 throw new IllegalArgumentException("Unknown authority " + authority);
Fred Quintana6a8d5332009-05-07 17:35:38 -0700949 }
950 try {
Fred Quintana89437372009-05-15 15:10:40 -0700951 return provider.applyBatch(operations);
Fred Quintana6a8d5332009-05-07 17:35:38 -0700952 } finally {
953 provider.release();
954 }
955 }
956
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800957 /**
958 * Inserts multiple rows into a table at the given URL.
959 *
960 * This function make no guarantees about the atomicity of the insertions.
961 *
962 * @param url The URL of the table to insert into.
963 * @param values The initial values for the newly inserted rows. The key is the column name for
964 * the field. Passing null will create an empty row.
965 * @return the number of newly created rows.
966 */
967 public final int bulkInsert(Uri url, ContentValues[] values)
968 {
969 IContentProvider provider = acquireProvider(url);
970 if (provider == null) {
971 throw new IllegalArgumentException("Unknown URL " + url);
972 }
973 try {
Brad Fitzpatrickd72f7182010-02-11 17:07:51 -0800974 long startTime = SystemClock.uptimeMillis();
Dianne Hackborn35654b62013-01-14 17:38:02 -0800975 int rowsCreated = provider.bulkInsert(mPackageName, url, values);
Brad Fitzpatrickd72f7182010-02-11 17:07:51 -0800976 long durationMillis = SystemClock.uptimeMillis() - startTime;
Brad Fitzpatricka63730d2010-02-07 22:25:34 -0800977 maybeLogUpdateToEventLog(durationMillis, url, "bulkinsert", null /* where */);
978 return rowsCreated;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800979 } catch (RemoteException e) {
Brad Fitzpatrick534c84c2011-01-12 14:06:30 -0800980 // Arbitrary and not worth documenting, as Activity
981 // Manager will kill this process shortly anyway.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800982 return 0;
983 } finally {
984 releaseProvider(provider);
985 }
986 }
987
988 /**
989 * Deletes row(s) specified by a content URI.
990 *
991 * If the content provider supports transactions, the deletion will be atomic.
992 *
993 * @param url The URL of the row to delete.
994 * @param where A filter to apply to rows before deleting, formatted as an SQL WHERE clause
995 (excluding the WHERE itself).
996 * @return The number of rows deleted.
997 */
998 public final int delete(Uri url, String where, String[] selectionArgs)
999 {
1000 IContentProvider provider = acquireProvider(url);
1001 if (provider == null) {
1002 throw new IllegalArgumentException("Unknown URL " + url);
1003 }
1004 try {
Brad Fitzpatrickd72f7182010-02-11 17:07:51 -08001005 long startTime = SystemClock.uptimeMillis();
Dianne Hackborn35654b62013-01-14 17:38:02 -08001006 int rowsDeleted = provider.delete(mPackageName, url, where, selectionArgs);
Brad Fitzpatrickd72f7182010-02-11 17:07:51 -08001007 long durationMillis = SystemClock.uptimeMillis() - startTime;
Brad Fitzpatricka63730d2010-02-07 22:25:34 -08001008 maybeLogUpdateToEventLog(durationMillis, url, "delete", where);
1009 return rowsDeleted;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001010 } catch (RemoteException e) {
Brad Fitzpatrick534c84c2011-01-12 14:06:30 -08001011 // Arbitrary and not worth documenting, as Activity
1012 // Manager will kill this process shortly anyway.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001013 return -1;
1014 } finally {
1015 releaseProvider(provider);
1016 }
1017 }
1018
1019 /**
1020 * Update row(s) in a content URI.
1021 *
1022 * If the content provider supports transactions the update will be atomic.
1023 *
1024 * @param uri The URI to modify.
1025 * @param values The new field values. The key is the column name for the field.
1026 A null value will remove an existing field value.
Omari Stephensd2a2daa2010-03-10 18:53:54 -08001027 * @param where A filter to apply to rows before updating, formatted as an SQL WHERE clause
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001028 (excluding the WHERE itself).
Brad Fitzpatrick534c84c2011-01-12 14:06:30 -08001029 * @return the number of rows updated.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001030 * @throws NullPointerException if uri or values are null
1031 */
1032 public final int update(Uri uri, ContentValues values, String where,
1033 String[] selectionArgs) {
1034 IContentProvider provider = acquireProvider(uri);
1035 if (provider == null) {
1036 throw new IllegalArgumentException("Unknown URI " + uri);
1037 }
1038 try {
Brad Fitzpatrickd72f7182010-02-11 17:07:51 -08001039 long startTime = SystemClock.uptimeMillis();
Dianne Hackborn35654b62013-01-14 17:38:02 -08001040 int rowsUpdated = provider.update(mPackageName, uri, values, where, selectionArgs);
Brad Fitzpatrickd72f7182010-02-11 17:07:51 -08001041 long durationMillis = SystemClock.uptimeMillis() - startTime;
Brad Fitzpatricka63730d2010-02-07 22:25:34 -08001042 maybeLogUpdateToEventLog(durationMillis, uri, "update", where);
1043 return rowsUpdated;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001044 } catch (RemoteException e) {
Brad Fitzpatrick534c84c2011-01-12 14:06:30 -08001045 // Arbitrary and not worth documenting, as Activity
1046 // Manager will kill this process shortly anyway.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001047 return -1;
1048 } finally {
1049 releaseProvider(provider);
1050 }
1051 }
1052
1053 /**
Ken Wakasaf76a50c2012-03-09 19:56:35 +09001054 * Call a provider-defined method. This can be used to implement
Brad Fitzpatrick534c84c2011-01-12 14:06:30 -08001055 * read or write interfaces which are cheaper than using a Cursor and/or
1056 * do not fit into the traditional table model.
1057 *
1058 * @param method provider-defined method name to call. Opaque to
1059 * framework, but must be non-null.
1060 * @param arg provider-defined String argument. May be null.
1061 * @param extras provider-defined Bundle argument. May be null.
1062 * @return a result Bundle, possibly null. Will be null if the ContentProvider
1063 * does not implement call.
1064 * @throws NullPointerException if uri or method is null
1065 * @throws IllegalArgumentException if uri is not known
1066 */
1067 public final Bundle call(Uri uri, String method, String arg, Bundle extras) {
1068 if (uri == null) {
1069 throw new NullPointerException("uri == null");
1070 }
1071 if (method == null) {
1072 throw new NullPointerException("method == null");
1073 }
1074 IContentProvider provider = acquireProvider(uri);
1075 if (provider == null) {
1076 throw new IllegalArgumentException("Unknown URI " + uri);
1077 }
1078 try {
Dianne Hackborn35654b62013-01-14 17:38:02 -08001079 return provider.call(mPackageName, method, arg, extras);
Brad Fitzpatrick534c84c2011-01-12 14:06:30 -08001080 } catch (RemoteException e) {
1081 // Arbitrary and not worth documenting, as Activity
1082 // Manager will kill this process shortly anyway.
1083 return null;
1084 } finally {
1085 releaseProvider(provider);
1086 }
1087 }
1088
1089 /**
Dianne Hackborncca1f0e2010-09-26 18:34:53 -07001090 * Returns the content provider for the given content URI.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001091 *
1092 * @param uri The URI to a content provider
1093 * @return The ContentProvider for the given URI, or null if no content provider is found.
1094 * @hide
1095 */
Dianne Hackborncca1f0e2010-09-26 18:34:53 -07001096 public final IContentProvider acquireProvider(Uri uri) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001097 if (!SCHEME_CONTENT.equals(uri.getScheme())) {
1098 return null;
1099 }
Yury Zhauniarovichf9c51762012-05-12 18:39:25 +02001100 final String auth = uri.getAuthority();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001101 if (auth != null) {
Yury Zhauniarovichf9c51762012-05-12 18:39:25 +02001102 return acquireProvider(mContext, auth);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001103 }
1104 return null;
1105 }
1106
1107 /**
Dianne Hackborncca1f0e2010-09-26 18:34:53 -07001108 * Returns the content provider for the given content URI if the process
1109 * already has a reference on it.
1110 *
1111 * @param uri The URI to a content provider
1112 * @return The ContentProvider for the given URI, or null if no content provider is found.
1113 * @hide
1114 */
1115 public final IContentProvider acquireExistingProvider(Uri uri) {
1116 if (!SCHEME_CONTENT.equals(uri.getScheme())) {
1117 return null;
1118 }
Yury Zhauniarovichf9c51762012-05-12 18:39:25 +02001119 final String auth = uri.getAuthority();
Dianne Hackborncca1f0e2010-09-26 18:34:53 -07001120 if (auth != null) {
Yury Zhauniarovichf9c51762012-05-12 18:39:25 +02001121 return acquireExistingProvider(mContext, auth);
Dianne Hackborncca1f0e2010-09-26 18:34:53 -07001122 }
1123 return null;
1124 }
1125
1126 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001127 * @hide
1128 */
1129 public final IContentProvider acquireProvider(String name) {
Brad Fitzpatrick1877d012010-03-04 17:48:13 -08001130 if (name == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001131 return null;
1132 }
1133 return acquireProvider(mContext, name);
1134 }
1135
1136 /**
Dianne Hackborn652b6d12012-05-09 18:18:40 -07001137 * Returns the content provider for the given content URI.
1138 *
1139 * @param uri The URI to a content provider
1140 * @return The ContentProvider for the given URI, or null if no content provider is found.
1141 * @hide
1142 */
1143 public final IContentProvider acquireUnstableProvider(Uri uri) {
1144 if (!SCHEME_CONTENT.equals(uri.getScheme())) {
1145 return null;
1146 }
1147 String auth = uri.getAuthority();
1148 if (auth != null) {
1149 return acquireUnstableProvider(mContext, uri.getAuthority());
1150 }
1151 return null;
1152 }
1153
1154 /**
1155 * @hide
1156 */
1157 public final IContentProvider acquireUnstableProvider(String name) {
1158 if (name == null) {
1159 return null;
1160 }
Dianne Hackborn6ae8d182012-05-23 13:12:42 -07001161 return acquireUnstableProvider(mContext, name);
Dianne Hackborn652b6d12012-05-09 18:18:40 -07001162 }
1163
1164 /**
Fred Quintana718d8a22009-04-29 17:53:20 -07001165 * Returns a {@link ContentProviderClient} that is associated with the {@link ContentProvider}
1166 * that services the content at uri, starting the provider if necessary. Returns
1167 * null if there is no provider associated wih the uri. The caller must indicate that they are
1168 * done with the provider by calling {@link ContentProviderClient#release} which will allow
1169 * the system to release the provider it it determines that there is no other reason for
1170 * keeping it active.
1171 * @param uri specifies which provider should be acquired
1172 * @return a {@link ContentProviderClient} that is associated with the {@link ContentProvider}
1173 * that services the content at uri or null if there isn't one.
1174 */
1175 public final ContentProviderClient acquireContentProviderClient(Uri uri) {
1176 IContentProvider provider = acquireProvider(uri);
1177 if (provider != null) {
Dianne Hackborn652b6d12012-05-09 18:18:40 -07001178 return new ContentProviderClient(this, provider, true);
Fred Quintana718d8a22009-04-29 17:53:20 -07001179 }
1180
1181 return null;
1182 }
1183
1184 /**
1185 * Returns a {@link ContentProviderClient} that is associated with the {@link ContentProvider}
1186 * with the authority of name, starting the provider if necessary. Returns
1187 * null if there is no provider associated wih the uri. The caller must indicate that they are
1188 * done with the provider by calling {@link ContentProviderClient#release} which will allow
1189 * the system to release the provider it it determines that there is no other reason for
1190 * keeping it active.
1191 * @param name specifies which provider should be acquired
1192 * @return a {@link ContentProviderClient} that is associated with the {@link ContentProvider}
1193 * with the authority of name or null if there isn't one.
1194 */
1195 public final ContentProviderClient acquireContentProviderClient(String name) {
1196 IContentProvider provider = acquireProvider(name);
1197 if (provider != null) {
Dianne Hackborn652b6d12012-05-09 18:18:40 -07001198 return new ContentProviderClient(this, provider, true);
1199 }
1200
1201 return null;
1202 }
1203
1204 /**
1205 * Like {@link #acquireContentProviderClient(Uri)}, but for use when you do
1206 * not trust the stability of the target content provider. This turns off
1207 * the mechanism in the platform clean up processes that are dependent on
1208 * a content provider if that content provider's process goes away. Normally
1209 * you can safely assume that once you have acquired a provider, you can freely
1210 * use it as needed and it won't disappear, even if your process is in the
1211 * background. If using this method, you need to take care to deal with any
1212 * failures when communicating with the provider, and be sure to close it
Dianne Hackborn6ae8d182012-05-23 13:12:42 -07001213 * so that it can be re-opened later. In particular, catching a
1214 * {@link android.os.DeadObjectException} from the calls there will let you
1215 * know that the content provider has gone away; at that point the current
1216 * ContentProviderClient object is invalid, and you should release it. You
1217 * can acquire a new one if you would like to try to restart the provider
1218 * and perform new operations on it.
Dianne Hackborn652b6d12012-05-09 18:18:40 -07001219 */
1220 public final ContentProviderClient acquireUnstableContentProviderClient(Uri uri) {
Dianne Hackborn6ae8d182012-05-23 13:12:42 -07001221 IContentProvider provider = acquireUnstableProvider(uri);
Dianne Hackborn652b6d12012-05-09 18:18:40 -07001222 if (provider != null) {
1223 return new ContentProviderClient(this, provider, false);
1224 }
1225
1226 return null;
1227 }
1228
1229 /**
1230 * Like {@link #acquireContentProviderClient(String)}, but for use when you do
1231 * not trust the stability of the target content provider. This turns off
1232 * the mechanism in the platform clean up processes that are dependent on
1233 * a content provider if that content provider's process goes away. Normally
1234 * you can safely assume that once you have acquired a provider, you can freely
1235 * use it as needed and it won't disappear, even if your process is in the
1236 * background. If using this method, you need to take care to deal with any
1237 * failures when communicating with the provider, and be sure to close it
Dianne Hackborn6ae8d182012-05-23 13:12:42 -07001238 * so that it can be re-opened later. In particular, catching a
1239 * {@link android.os.DeadObjectException} from the calls there will let you
1240 * know that the content provider has gone away; at that point the current
1241 * ContentProviderClient object is invalid, and you should release it. You
1242 * can acquire a new one if you would like to try to restart the provider
1243 * and perform new operations on it.
Dianne Hackborn652b6d12012-05-09 18:18:40 -07001244 */
1245 public final ContentProviderClient acquireUnstableContentProviderClient(String name) {
Dianne Hackborn6ae8d182012-05-23 13:12:42 -07001246 IContentProvider provider = acquireUnstableProvider(name);
Dianne Hackborn652b6d12012-05-09 18:18:40 -07001247 if (provider != null) {
1248 return new ContentProviderClient(this, provider, false);
Fred Quintana718d8a22009-04-29 17:53:20 -07001249 }
1250
1251 return null;
1252 }
1253
1254 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001255 * Register an observer class that gets callbacks when data identified by a
1256 * given content URI changes.
1257 *
1258 * @param uri The URI to watch for changes. This can be a specific row URI, or a base URI
1259 * for a whole class of content.
1260 * @param notifyForDescendents If <code>true</code> changes to URIs beginning with <code>uri</code>
1261 * will also cause notifications to be sent. If <code>false</code> only changes to the exact URI
1262 * specified by <em>uri</em> will cause notifications to be sent. If true, than any URI values
1263 * at or below the specified URI will also trigger a match.
1264 * @param observer The object that receives callbacks when changes occur.
1265 * @see #unregisterContentObserver
1266 */
1267 public final void registerContentObserver(Uri uri, boolean notifyForDescendents,
1268 ContentObserver observer)
1269 {
Christopher Tateafccaa82012-10-03 17:41:51 -07001270 registerContentObserver(uri, notifyForDescendents, observer, UserHandle.myUserId());
Christopher Tate16aa9732012-09-17 16:23:44 -07001271 }
1272
1273 /** @hide - designated user version */
1274 public final void registerContentObserver(Uri uri, boolean notifyForDescendents,
1275 ContentObserver observer, int userHandle)
1276 {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001277 try {
Dianne Hackborn231cc602009-04-27 17:10:36 -07001278 getContentService().registerContentObserver(uri, notifyForDescendents,
Christopher Tate16aa9732012-09-17 16:23:44 -07001279 observer.getContentObserver(), userHandle);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001280 } catch (RemoteException e) {
1281 }
1282 }
1283
1284 /**
1285 * Unregisters a change observer.
1286 *
1287 * @param observer The previously registered observer that is no longer needed.
1288 * @see #registerContentObserver
1289 */
1290 public final void unregisterContentObserver(ContentObserver observer) {
1291 try {
1292 IContentObserver contentObserver = observer.releaseContentObserver();
1293 if (contentObserver != null) {
Dianne Hackborn231cc602009-04-27 17:10:36 -07001294 getContentService().unregisterContentObserver(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001295 contentObserver);
1296 }
1297 } catch (RemoteException e) {
1298 }
1299 }
1300
1301 /**
Steve Pomeroyd7a1aad2012-01-18 16:15:59 -05001302 * Notify registered observers that a row was updated and attempt to sync changes
1303 * to the network.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001304 * To register, call {@link #registerContentObserver(android.net.Uri , boolean, android.database.ContentObserver) registerContentObserver()}.
1305 * By default, CursorAdapter objects will get this notification.
1306 *
Jeff Brown86de0592012-01-23 13:01:18 -08001307 * @param uri The uri of the content that was changed.
1308 * @param observer The observer that originated the change, may be <code>null</null>.
1309 * The observer that originated the change will only receive the notification if it
1310 * has requested to receive self-change notifications by implementing
1311 * {@link ContentObserver#deliverSelfNotifications()} to return true.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001312 */
1313 public void notifyChange(Uri uri, ContentObserver observer) {
1314 notifyChange(uri, observer, true /* sync to network */);
1315 }
1316
1317 /**
1318 * Notify registered observers that a row was updated.
1319 * To register, call {@link #registerContentObserver(android.net.Uri , boolean, android.database.ContentObserver) registerContentObserver()}.
1320 * By default, CursorAdapter objects will get this notification.
Steve Pomeroyd7a1aad2012-01-18 16:15:59 -05001321 * If syncToNetwork is true, this will attempt to schedule a local sync using the sync
1322 * adapter that's registered for the authority of the provided uri. No account will be
1323 * passed to the sync adapter, so all matching accounts will be synchronized.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001324 *
Jeff Brown86de0592012-01-23 13:01:18 -08001325 * @param uri The uri of the content that was changed.
1326 * @param observer The observer that originated the change, may be <code>null</null>.
1327 * The observer that originated the change will only receive the notification if it
1328 * has requested to receive self-change notifications by implementing
1329 * {@link ContentObserver#deliverSelfNotifications()} to return true.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001330 * @param syncToNetwork If true, attempt to sync the change to the network.
Steve Pomeroyd7a1aad2012-01-18 16:15:59 -05001331 * @see #requestSync(android.accounts.Account, String, android.os.Bundle)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001332 */
1333 public void notifyChange(Uri uri, ContentObserver observer, boolean syncToNetwork) {
Christopher Tateb7564452012-09-19 16:21:18 -07001334 notifyChange(uri, observer, syncToNetwork, UserHandle.getCallingUserId());
Christopher Tate16aa9732012-09-17 16:23:44 -07001335 }
1336
1337 /**
1338 * Notify registered observers within the designated user(s) that a row was updated.
1339 *
1340 * @hide
1341 */
1342 public void notifyChange(Uri uri, ContentObserver observer, boolean syncToNetwork,
1343 int userHandle) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001344 try {
Dianne Hackborn231cc602009-04-27 17:10:36 -07001345 getContentService().notifyChange(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001346 uri, observer == null ? null : observer.getContentObserver(),
Christopher Tate16aa9732012-09-17 16:23:44 -07001347 observer != null && observer.deliverSelfNotifications(), syncToNetwork,
1348 userHandle);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001349 } catch (RemoteException e) {
1350 }
1351 }
1352
1353 /**
1354 * Start an asynchronous sync operation. If you want to monitor the progress
1355 * of the sync you may register a SyncObserver. Only values of the following
1356 * types may be used in the extras bundle:
1357 * <ul>
1358 * <li>Integer</li>
1359 * <li>Long</li>
1360 * <li>Boolean</li>
1361 * <li>Float</li>
1362 * <li>Double</li>
1363 * <li>String</li>
1364 * </ul>
1365 *
1366 * @param uri the uri of the provider to sync or null to sync all providers.
1367 * @param extras any extras to pass to the SyncAdapter.
Fred Quintanaac9385e2009-06-22 18:00:59 -07001368 * @deprecated instead use
1369 * {@link #requestSync(android.accounts.Account, String, android.os.Bundle)}
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001370 */
Dianne Hackborn4a51c202009-08-21 15:14:02 -07001371 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001372 public void startSync(Uri uri, Bundle extras) {
Fred Quintanaac9385e2009-06-22 18:00:59 -07001373 Account account = null;
1374 if (extras != null) {
1375 String accountName = extras.getString(SYNC_EXTRAS_ACCOUNT);
1376 if (!TextUtils.isEmpty(accountName)) {
Costin Manolache3348f142009-09-29 18:58:36 -07001377 account = new Account(accountName, "com.google");
Fred Quintanaac9385e2009-06-22 18:00:59 -07001378 }
1379 extras.remove(SYNC_EXTRAS_ACCOUNT);
1380 }
1381 requestSync(account, uri != null ? uri.getAuthority() : null, extras);
1382 }
1383
1384 /**
1385 * Start an asynchronous sync operation. If you want to monitor the progress
1386 * of the sync you may register a SyncObserver. Only values of the following
1387 * types may be used in the extras bundle:
1388 * <ul>
1389 * <li>Integer</li>
1390 * <li>Long</li>
1391 * <li>Boolean</li>
1392 * <li>Float</li>
1393 * <li>Double</li>
1394 * <li>String</li>
1395 * </ul>
1396 *
1397 * @param account which account should be synced
1398 * @param authority which authority should be synced
1399 * @param extras any extras to pass to the SyncAdapter.
1400 */
1401 public static void requestSync(Account account, String authority, Bundle extras) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001402 validateSyncExtrasBundle(extras);
1403 try {
Fred Quintanaac9385e2009-06-22 18:00:59 -07001404 getContentService().requestSync(account, authority, extras);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001405 } catch (RemoteException e) {
1406 }
1407 }
1408
1409 /**
1410 * Check that only values of the following types are in the Bundle:
1411 * <ul>
1412 * <li>Integer</li>
1413 * <li>Long</li>
1414 * <li>Boolean</li>
1415 * <li>Float</li>
1416 * <li>Double</li>
1417 * <li>String</li>
Fred Quintanad9d2f112009-04-23 13:36:27 -07001418 * <li>Account</li>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001419 * <li>null</li>
1420 * </ul>
1421 * @param extras the Bundle to check
1422 */
1423 public static void validateSyncExtrasBundle(Bundle extras) {
1424 try {
1425 for (String key : extras.keySet()) {
1426 Object value = extras.get(key);
1427 if (value == null) continue;
1428 if (value instanceof Long) continue;
1429 if (value instanceof Integer) continue;
1430 if (value instanceof Boolean) continue;
1431 if (value instanceof Float) continue;
1432 if (value instanceof Double) continue;
1433 if (value instanceof String) continue;
Fred Quintanad9d2f112009-04-23 13:36:27 -07001434 if (value instanceof Account) continue;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001435 throw new IllegalArgumentException("unexpected value type: "
1436 + value.getClass().getName());
1437 }
1438 } catch (IllegalArgumentException e) {
1439 throw e;
1440 } catch (RuntimeException exc) {
1441 throw new IllegalArgumentException("error unparceling Bundle", exc);
1442 }
1443 }
1444
Fred Quintanaac9385e2009-06-22 18:00:59 -07001445 /**
1446 * Cancel any active or pending syncs that match the Uri. If the uri is null then
1447 * all syncs will be canceled.
1448 *
1449 * @param uri the uri of the provider to sync or null to sync all providers.
1450 * @deprecated instead use {@link #cancelSync(android.accounts.Account, String)}
1451 */
Dianne Hackborn4a51c202009-08-21 15:14:02 -07001452 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001453 public void cancelSync(Uri uri) {
Fred Quintanaac9385e2009-06-22 18:00:59 -07001454 cancelSync(null /* all accounts */, uri != null ? uri.getAuthority() : null);
1455 }
1456
1457 /**
1458 * Cancel any active or pending syncs that match account and authority. The account and
1459 * authority can each independently be set to null, which means that syncs with any account
1460 * or authority, respectively, will match.
1461 *
1462 * @param account filters the syncs that match by this account
1463 * @param authority filters the syncs that match by this authority
1464 */
1465 public static void cancelSync(Account account, String authority) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001466 try {
Fred Quintanaac9385e2009-06-22 18:00:59 -07001467 getContentService().cancelSync(account, authority);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001468 } catch (RemoteException e) {
1469 }
1470 }
1471
Fred Quintanaac9385e2009-06-22 18:00:59 -07001472 /**
1473 * Get information about the SyncAdapters that are known to the system.
1474 * @return an array of SyncAdapters that have registered with the system
1475 */
1476 public static SyncAdapterType[] getSyncAdapterTypes() {
1477 try {
1478 return getContentService().getSyncAdapterTypes();
1479 } catch (RemoteException e) {
1480 throw new RuntimeException("the ContentService should always be reachable", e);
1481 }
1482 }
1483
1484 /**
1485 * Check if the provider should be synced when a network tickle is received
Nicolas Falliere9530e3a2012-06-18 17:21:06 -07001486 * <p>This method requires the caller to hold the permission
1487 * {@link android.Manifest.permission#READ_SYNC_SETTINGS}.
Fred Quintanaac9385e2009-06-22 18:00:59 -07001488 *
1489 * @param account the account whose setting we are querying
1490 * @param authority the provider whose setting we are querying
1491 * @return true if the provider should be synced when a network tickle is received
1492 */
1493 public static boolean getSyncAutomatically(Account account, String authority) {
1494 try {
1495 return getContentService().getSyncAutomatically(account, authority);
1496 } catch (RemoteException e) {
1497 throw new RuntimeException("the ContentService should always be reachable", e);
1498 }
1499 }
1500
1501 /**
1502 * Set whether or not the provider is synced when it receives a network tickle.
Nicolas Falliere9530e3a2012-06-18 17:21:06 -07001503 * <p>This method requires the caller to hold the permission
1504 * {@link android.Manifest.permission#WRITE_SYNC_SETTINGS}.
Fred Quintanaac9385e2009-06-22 18:00:59 -07001505 *
1506 * @param account the account whose setting we are querying
1507 * @param authority the provider whose behavior is being controlled
1508 * @param sync true if the provider should be synced when tickles are received for it
1509 */
1510 public static void setSyncAutomatically(Account account, String authority, boolean sync) {
1511 try {
1512 getContentService().setSyncAutomatically(account, authority, sync);
1513 } catch (RemoteException e) {
1514 // exception ignored; if this is thrown then it means the runtime is in the midst of
1515 // being restarted
1516 }
1517 }
1518
1519 /**
Fred Quintanac5d1c6d2010-01-27 12:17:49 -08001520 * Specifies that a sync should be requested with the specified the account, authority,
1521 * and extras at the given frequency. If there is already another periodic sync scheduled
1522 * with the account, authority and extras then a new periodic sync won't be added, instead
1523 * the frequency of the previous one will be updated.
1524 * <p>
1525 * These periodic syncs honor the "syncAutomatically" and "masterSyncAutomatically" settings.
1526 * Although these sync are scheduled at the specified frequency, it may take longer for it to
1527 * actually be started if other syncs are ahead of it in the sync operation queue. This means
1528 * that the actual start time may drift.
Fred Quintana53bd2522010-02-05 15:28:12 -08001529 * <p>
1530 * Periodic syncs are not allowed to have any of {@link #SYNC_EXTRAS_DO_NOT_RETRY},
1531 * {@link #SYNC_EXTRAS_IGNORE_BACKOFF}, {@link #SYNC_EXTRAS_IGNORE_SETTINGS},
1532 * {@link #SYNC_EXTRAS_INITIALIZE}, {@link #SYNC_EXTRAS_FORCE},
1533 * {@link #SYNC_EXTRAS_EXPEDITED}, {@link #SYNC_EXTRAS_MANUAL} set to true.
1534 * If any are supplied then an {@link IllegalArgumentException} will be thrown.
Fred Quintanac5d1c6d2010-01-27 12:17:49 -08001535 *
Nicolas Falliere9530e3a2012-06-18 17:21:06 -07001536 * <p>This method requires the caller to hold the permission
1537 * {@link android.Manifest.permission#WRITE_SYNC_SETTINGS}.
1538 *
Fred Quintanac5d1c6d2010-01-27 12:17:49 -08001539 * @param account the account to specify in the sync
1540 * @param authority the provider to specify in the sync request
1541 * @param extras extra parameters to go along with the sync request
1542 * @param pollFrequency how frequently the sync should be performed, in seconds.
Fred Quintana53bd2522010-02-05 15:28:12 -08001543 * @throws IllegalArgumentException if an illegal extra was set or if any of the parameters
1544 * are null.
Fred Quintanac5d1c6d2010-01-27 12:17:49 -08001545 */
1546 public static void addPeriodicSync(Account account, String authority, Bundle extras,
1547 long pollFrequency) {
1548 validateSyncExtrasBundle(extras);
Fred Quintana53bd2522010-02-05 15:28:12 -08001549 if (account == null) {
1550 throw new IllegalArgumentException("account must not be null");
1551 }
1552 if (authority == null) {
1553 throw new IllegalArgumentException("authority must not be null");
1554 }
1555 if (extras.getBoolean(SYNC_EXTRAS_MANUAL, false)
1556 || extras.getBoolean(SYNC_EXTRAS_DO_NOT_RETRY, false)
1557 || extras.getBoolean(SYNC_EXTRAS_IGNORE_BACKOFF, false)
1558 || extras.getBoolean(SYNC_EXTRAS_IGNORE_SETTINGS, false)
1559 || extras.getBoolean(SYNC_EXTRAS_INITIALIZE, false)
1560 || extras.getBoolean(SYNC_EXTRAS_FORCE, false)
1561 || extras.getBoolean(SYNC_EXTRAS_EXPEDITED, false)) {
1562 throw new IllegalArgumentException("illegal extras were set");
1563 }
Fred Quintanac5d1c6d2010-01-27 12:17:49 -08001564 try {
1565 getContentService().addPeriodicSync(account, authority, extras, pollFrequency);
1566 } catch (RemoteException e) {
1567 // exception ignored; if this is thrown then it means the runtime is in the midst of
1568 // being restarted
1569 }
1570 }
1571
1572 /**
1573 * Remove a periodic sync. Has no affect if account, authority and extras don't match
1574 * an existing periodic sync.
Nicolas Falliere9530e3a2012-06-18 17:21:06 -07001575 * <p>This method requires the caller to hold the permission
1576 * {@link android.Manifest.permission#WRITE_SYNC_SETTINGS}.
Fred Quintanac5d1c6d2010-01-27 12:17:49 -08001577 *
1578 * @param account the account of the periodic sync to remove
1579 * @param authority the provider of the periodic sync to remove
1580 * @param extras the extras of the periodic sync to remove
1581 */
1582 public static void removePeriodicSync(Account account, String authority, Bundle extras) {
1583 validateSyncExtrasBundle(extras);
Fred Quintana53bd2522010-02-05 15:28:12 -08001584 if (account == null) {
1585 throw new IllegalArgumentException("account must not be null");
1586 }
1587 if (authority == null) {
1588 throw new IllegalArgumentException("authority must not be null");
1589 }
Fred Quintanac5d1c6d2010-01-27 12:17:49 -08001590 try {
1591 getContentService().removePeriodicSync(account, authority, extras);
1592 } catch (RemoteException e) {
1593 throw new RuntimeException("the ContentService should always be reachable", e);
1594 }
1595 }
1596
1597 /**
1598 * Get the list of information about the periodic syncs for the given account and authority.
Nicolas Falliere9530e3a2012-06-18 17:21:06 -07001599 * <p>This method requires the caller to hold the permission
1600 * {@link android.Manifest.permission#READ_SYNC_SETTINGS}.
Fred Quintanac5d1c6d2010-01-27 12:17:49 -08001601 *
1602 * @param account the account whose periodic syncs we are querying
1603 * @param authority the provider whose periodic syncs we are querying
1604 * @return a list of PeriodicSync objects. This list may be empty but will never be null.
1605 */
1606 public static List<PeriodicSync> getPeriodicSyncs(Account account, String authority) {
Fred Quintana53bd2522010-02-05 15:28:12 -08001607 if (account == null) {
1608 throw new IllegalArgumentException("account must not be null");
1609 }
1610 if (authority == null) {
1611 throw new IllegalArgumentException("authority must not be null");
1612 }
Fred Quintanac5d1c6d2010-01-27 12:17:49 -08001613 try {
1614 return getContentService().getPeriodicSyncs(account, authority);
1615 } catch (RemoteException e) {
1616 throw new RuntimeException("the ContentService should always be reachable", e);
1617 }
1618 }
1619
1620 /**
Fred Quintana5e787c42009-08-16 23:13:53 -07001621 * Check if this account/provider is syncable.
Nicolas Falliere9530e3a2012-06-18 17:21:06 -07001622 * <p>This method requires the caller to hold the permission
1623 * {@link android.Manifest.permission#READ_SYNC_SETTINGS}.
Fred Quintana5e787c42009-08-16 23:13:53 -07001624 * @return >0 if it is syncable, 0 if not, and <0 if the state isn't known yet.
1625 */
Jim Miller20ea6ce2009-08-17 15:47:14 -07001626 public static int getIsSyncable(Account account, String authority) {
Fred Quintana5e787c42009-08-16 23:13:53 -07001627 try {
1628 return getContentService().getIsSyncable(account, authority);
1629 } catch (RemoteException e) {
1630 throw new RuntimeException("the ContentService should always be reachable", e);
1631 }
1632 }
1633
1634 /**
1635 * Set whether this account/provider is syncable.
Nicolas Falliere9530e3a2012-06-18 17:21:06 -07001636 * <p>This method requires the caller to hold the permission
1637 * {@link android.Manifest.permission#WRITE_SYNC_SETTINGS}.
Fred Quintana718671b2009-08-17 14:08:37 -07001638 * @param syncable >0 denotes syncable, 0 means not syncable, <0 means unknown
Fred Quintana5e787c42009-08-16 23:13:53 -07001639 */
Jim Miller20ea6ce2009-08-17 15:47:14 -07001640 public static void setIsSyncable(Account account, String authority, int syncable) {
Fred Quintana5e787c42009-08-16 23:13:53 -07001641 try {
1642 getContentService().setIsSyncable(account, authority, syncable);
1643 } catch (RemoteException e) {
1644 // exception ignored; if this is thrown then it means the runtime is in the midst of
1645 // being restarted
1646 }
1647 }
1648
1649 /**
Fred Quintanaac9385e2009-06-22 18:00:59 -07001650 * Gets the master auto-sync setting that applies to all the providers and accounts.
1651 * If this is false then the per-provider auto-sync setting is ignored.
Nicolas Falliere9530e3a2012-06-18 17:21:06 -07001652 * <p>This method requires the caller to hold the permission
1653 * {@link android.Manifest.permission#READ_SYNC_SETTINGS}.
Fred Quintanaac9385e2009-06-22 18:00:59 -07001654 *
1655 * @return the master auto-sync setting that applies to all the providers and accounts
1656 */
1657 public static boolean getMasterSyncAutomatically() {
1658 try {
1659 return getContentService().getMasterSyncAutomatically();
1660 } catch (RemoteException e) {
1661 throw new RuntimeException("the ContentService should always be reachable", e);
1662 }
1663 }
1664
1665 /**
1666 * Sets the master auto-sync setting that applies to all the providers and accounts.
1667 * If this is false then the per-provider auto-sync setting is ignored.
Nicolas Falliere9530e3a2012-06-18 17:21:06 -07001668 * <p>This method requires the caller to hold the permission
1669 * {@link android.Manifest.permission#WRITE_SYNC_SETTINGS}.
Fred Quintanaac9385e2009-06-22 18:00:59 -07001670 *
1671 * @param sync the master auto-sync setting that applies to all the providers and accounts
1672 */
1673 public static void setMasterSyncAutomatically(boolean sync) {
1674 try {
1675 getContentService().setMasterSyncAutomatically(sync);
1676 } catch (RemoteException e) {
1677 // exception ignored; if this is thrown then it means the runtime is in the midst of
1678 // being restarted
1679 }
1680 }
1681
1682 /**
1683 * Returns true if there is currently a sync operation for the given
1684 * account or authority in the pending list, or actively being processed.
Nicolas Falliere9530e3a2012-06-18 17:21:06 -07001685 * <p>This method requires the caller to hold the permission
1686 * {@link android.Manifest.permission#READ_SYNC_STATS}.
Fred Quintanaac9385e2009-06-22 18:00:59 -07001687 * @param account the account whose setting we are querying
1688 * @param authority the provider whose behavior is being queried
1689 * @return true if a sync is active for the given account or authority.
1690 */
1691 public static boolean isSyncActive(Account account, String authority) {
1692 try {
1693 return getContentService().isSyncActive(account, authority);
1694 } catch (RemoteException e) {
1695 throw new RuntimeException("the ContentService should always be reachable", e);
1696 }
1697 }
1698
1699 /**
Fred Quintanac6a69552010-09-27 17:05:04 -07001700 * If a sync is active returns the information about it, otherwise returns null.
1701 * <p>
Nicolas Falliere9530e3a2012-06-18 17:21:06 -07001702 * This method requires the caller to hold the permission
1703 * {@link android.Manifest.permission#READ_SYNC_STATS}.
1704 * <p>
Fred Quintanad5e4fdc2010-03-30 15:16:21 -07001705 * @return the SyncInfo for the currently active sync or null if one is not active.
Fred Quintanac6a69552010-09-27 17:05:04 -07001706 * @deprecated
1707 * Since multiple concurrent syncs are now supported you should use
1708 * {@link #getCurrentSyncs()} to get the accurate list of current syncs.
1709 * This method returns the first item from the list of current syncs
1710 * or null if there are none.
Fred Quintanaac9385e2009-06-22 18:00:59 -07001711 */
Fred Quintanac6a69552010-09-27 17:05:04 -07001712 @Deprecated
Fred Quintanad5e4fdc2010-03-30 15:16:21 -07001713 public static SyncInfo getCurrentSync() {
Fred Quintanaac9385e2009-06-22 18:00:59 -07001714 try {
Fred Quintanac6a69552010-09-27 17:05:04 -07001715 final List<SyncInfo> syncs = getContentService().getCurrentSyncs();
1716 if (syncs.isEmpty()) {
1717 return null;
1718 }
1719 return syncs.get(0);
1720 } catch (RemoteException e) {
1721 throw new RuntimeException("the ContentService should always be reachable", e);
1722 }
1723 }
1724
1725 /**
1726 * Returns a list with information about all the active syncs. This list will be empty
1727 * if there are no active syncs.
Nicolas Falliere9530e3a2012-06-18 17:21:06 -07001728 * <p>
1729 * This method requires the caller to hold the permission
1730 * {@link android.Manifest.permission#READ_SYNC_STATS}.
1731 * <p>
Fred Quintanac6a69552010-09-27 17:05:04 -07001732 * @return a List of SyncInfo objects for the currently active syncs.
1733 */
1734 public static List<SyncInfo> getCurrentSyncs() {
1735 try {
1736 return getContentService().getCurrentSyncs();
Fred Quintanaac9385e2009-06-22 18:00:59 -07001737 } catch (RemoteException e) {
1738 throw new RuntimeException("the ContentService should always be reachable", e);
1739 }
1740 }
1741
1742 /**
Fred Quintana4a6679b2009-08-17 13:05:39 -07001743 * Returns the status that matches the authority.
Fred Quintanaac9385e2009-06-22 18:00:59 -07001744 * @param account the account whose setting we are querying
1745 * @param authority the provider whose behavior is being queried
1746 * @return the SyncStatusInfo for the authority, or null if none exists
1747 * @hide
1748 */
1749 public static SyncStatusInfo getSyncStatus(Account account, String authority) {
1750 try {
1751 return getContentService().getSyncStatus(account, authority);
1752 } catch (RemoteException e) {
1753 throw new RuntimeException("the ContentService should always be reachable", e);
1754 }
1755 }
1756
1757 /**
1758 * Return true if the pending status is true of any matching authorities.
Nicolas Falliere9530e3a2012-06-18 17:21:06 -07001759 * <p>This method requires the caller to hold the permission
1760 * {@link android.Manifest.permission#READ_SYNC_STATS}.
Fred Quintanaac9385e2009-06-22 18:00:59 -07001761 * @param account the account whose setting we are querying
1762 * @param authority the provider whose behavior is being queried
1763 * @return true if there is a pending sync with the matching account and authority
1764 */
1765 public static boolean isSyncPending(Account account, String authority) {
1766 try {
1767 return getContentService().isSyncPending(account, authority);
1768 } catch (RemoteException e) {
1769 throw new RuntimeException("the ContentService should always be reachable", e);
1770 }
1771 }
1772
Fred Quintana1b487ec2010-02-26 10:57:55 -08001773 /**
1774 * Request notifications when the different aspects of the SyncManager change. The
1775 * different items that can be requested are:
1776 * <ul>
1777 * <li> {@link #SYNC_OBSERVER_TYPE_PENDING}
1778 * <li> {@link #SYNC_OBSERVER_TYPE_ACTIVE}
1779 * <li> {@link #SYNC_OBSERVER_TYPE_SETTINGS}
1780 * </ul>
1781 * The caller can set one or more of the status types in the mask for any
1782 * given listener registration.
1783 * @param mask the status change types that will cause the callback to be invoked
1784 * @param callback observer to be invoked when the status changes
1785 * @return a handle that can be used to remove the listener at a later time
1786 */
Fred Quintanaac9385e2009-06-22 18:00:59 -07001787 public static Object addStatusChangeListener(int mask, final SyncStatusObserver callback) {
Fred Quintana1b487ec2010-02-26 10:57:55 -08001788 if (callback == null) {
1789 throw new IllegalArgumentException("you passed in a null callback");
1790 }
Fred Quintanaac9385e2009-06-22 18:00:59 -07001791 try {
1792 ISyncStatusObserver.Stub observer = new ISyncStatusObserver.Stub() {
1793 public void onStatusChanged(int which) throws RemoteException {
1794 callback.onStatusChanged(which);
1795 }
1796 };
1797 getContentService().addStatusChangeListener(mask, observer);
1798 return observer;
1799 } catch (RemoteException e) {
1800 throw new RuntimeException("the ContentService should always be reachable", e);
1801 }
1802 }
1803
Fred Quintana1b487ec2010-02-26 10:57:55 -08001804 /**
1805 * Remove a previously registered status change listener.
1806 * @param handle the handle that was returned by {@link #addStatusChangeListener}
1807 */
Fred Quintanaac9385e2009-06-22 18:00:59 -07001808 public static void removeStatusChangeListener(Object handle) {
Fred Quintana1b487ec2010-02-26 10:57:55 -08001809 if (handle == null) {
1810 throw new IllegalArgumentException("you passed in a null handle");
1811 }
Fred Quintanaac9385e2009-06-22 18:00:59 -07001812 try {
1813 getContentService().removeStatusChangeListener((ISyncStatusObserver.Stub) handle);
1814 } catch (RemoteException e) {
1815 // exception ignored; if this is thrown then it means the runtime is in the midst of
1816 // being restarted
1817 }
1818 }
1819
Brad Fitzpatricka63730d2010-02-07 22:25:34 -08001820 /**
1821 * Returns sampling percentage for a given duration.
1822 *
1823 * Always returns at least 1%.
1824 */
1825 private int samplePercentForDuration(long durationMillis) {
1826 if (durationMillis >= SLOW_THRESHOLD_MILLIS) {
1827 return 100;
1828 }
1829 return (int) (100 * durationMillis / SLOW_THRESHOLD_MILLIS) + 1;
1830 }
1831
1832 private void maybeLogQueryToEventLog(long durationMillis,
1833 Uri uri, String[] projection,
1834 String selection, String sortOrder) {
1835 int samplePercent = samplePercentForDuration(durationMillis);
1836 if (samplePercent < 100) {
1837 synchronized (mRandom) {
1838 if (mRandom.nextInt(100) >= samplePercent) {
1839 return;
1840 }
1841 }
1842 }
1843
1844 StringBuilder projectionBuffer = new StringBuilder(100);
1845 if (projection != null) {
1846 for (int i = 0; i < projection.length; ++i) {
1847 // Note: not using a comma delimiter here, as the
1848 // multiple arguments to EventLog.writeEvent later
1849 // stringify with a comma delimiter, which would make
1850 // parsing uglier later.
1851 if (i != 0) projectionBuffer.append('/');
1852 projectionBuffer.append(projection[i]);
1853 }
1854 }
1855
1856 // ActivityThread.currentPackageName() only returns non-null if the
1857 // current thread is an application main thread. This parameter tells
1858 // us whether an event loop is blocked, and if so, which app it is.
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -07001859 String blockingPackage = AppGlobals.getInitialPackage();
Brad Fitzpatricka63730d2010-02-07 22:25:34 -08001860
1861 EventLog.writeEvent(
Brad Fitzpatricka8fbedb2010-04-08 14:08:54 -07001862 EventLogTags.CONTENT_QUERY_SAMPLE,
Brad Fitzpatricka63730d2010-02-07 22:25:34 -08001863 uri.toString(),
1864 projectionBuffer.toString(),
1865 selection != null ? selection : "",
1866 sortOrder != null ? sortOrder : "",
1867 durationMillis,
1868 blockingPackage != null ? blockingPackage : "",
1869 samplePercent);
1870 }
1871
1872 private void maybeLogUpdateToEventLog(
1873 long durationMillis, Uri uri, String operation, String selection) {
1874 int samplePercent = samplePercentForDuration(durationMillis);
1875 if (samplePercent < 100) {
1876 synchronized (mRandom) {
1877 if (mRandom.nextInt(100) >= samplePercent) {
1878 return;
1879 }
1880 }
1881 }
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -07001882 String blockingPackage = AppGlobals.getInitialPackage();
Brad Fitzpatricka63730d2010-02-07 22:25:34 -08001883 EventLog.writeEvent(
Brad Fitzpatricka8fbedb2010-04-08 14:08:54 -07001884 EventLogTags.CONTENT_UPDATE_SAMPLE,
Brad Fitzpatricka63730d2010-02-07 22:25:34 -08001885 uri.toString(),
1886 operation,
1887 selection != null ? selection : "",
1888 durationMillis,
1889 blockingPackage != null ? blockingPackage : "",
1890 samplePercent);
1891 }
Fred Quintanaac9385e2009-06-22 18:00:59 -07001892
Jeff Brown825c5132011-10-12 16:11:30 -07001893 private final class CursorWrapperInner extends CrossProcessCursorWrapper {
Gilles Debunne03f02922010-06-09 14:11:45 -07001894 private final IContentProvider mContentProvider;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001895 public static final String TAG="CursorWrapperInner";
Jeff Brownbaaf8c32011-10-09 14:07:00 -07001896
1897 private final CloseGuard mCloseGuard = CloseGuard.get();
1898 private boolean mProviderReleased;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001899
1900 CursorWrapperInner(Cursor cursor, IContentProvider icp) {
1901 super(cursor);
1902 mContentProvider = icp;
Jeff Brownbaaf8c32011-10-09 14:07:00 -07001903 mCloseGuard.open("close");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001904 }
1905
1906 @Override
1907 public void close() {
1908 super.close();
1909 ContentResolver.this.releaseProvider(mContentProvider);
Jeff Brownbaaf8c32011-10-09 14:07:00 -07001910 mProviderReleased = true;
1911
1912 if (mCloseGuard != null) {
1913 mCloseGuard.close();
1914 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001915 }
1916
1917 @Override
1918 protected void finalize() throws Throwable {
1919 try {
Jeff Brownbaaf8c32011-10-09 14:07:00 -07001920 if (mCloseGuard != null) {
1921 mCloseGuard.warnIfOpen();
1922 }
1923
1924 if (!mProviderReleased && mContentProvider != null) {
1925 // Even though we are using CloseGuard, log this anyway so that
1926 // application developers always see the message in the log.
Johannes Carlsson872a52c2010-12-20 16:14:52 +01001927 Log.w(TAG, "Cursor finalized without prior close()");
Jeff Brownbaaf8c32011-10-09 14:07:00 -07001928 ContentResolver.this.releaseProvider(mContentProvider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001929 }
1930 } finally {
1931 super.finalize();
1932 }
1933 }
1934 }
1935
1936 private final class ParcelFileDescriptorInner extends ParcelFileDescriptor {
Gilles Debunne03f02922010-06-09 14:11:45 -07001937 private final IContentProvider mContentProvider;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001938 private boolean mReleaseProviderFlag = false;
1939
1940 ParcelFileDescriptorInner(ParcelFileDescriptor pfd, IContentProvider icp) {
1941 super(pfd);
1942 mContentProvider = icp;
1943 }
1944
1945 @Override
1946 public void close() throws IOException {
1947 if(!mReleaseProviderFlag) {
1948 super.close();
Dianne Hackborn6ae8d182012-05-23 13:12:42 -07001949 ContentResolver.this.releaseProvider(mContentProvider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001950 mReleaseProviderFlag = true;
1951 }
1952 }
1953
1954 @Override
1955 protected void finalize() throws Throwable {
1956 if (!mReleaseProviderFlag) {
1957 close();
1958 }
1959 }
1960 }
1961
Dianne Hackborn231cc602009-04-27 17:10:36 -07001962 /** @hide */
1963 public static final String CONTENT_SERVICE_NAME = "content";
Tom O'Neill0ba1cb02010-01-08 12:53:50 -08001964
Dianne Hackborn231cc602009-04-27 17:10:36 -07001965 /** @hide */
1966 public static IContentService getContentService() {
1967 if (sContentService != null) {
1968 return sContentService;
1969 }
1970 IBinder b = ServiceManager.getService(CONTENT_SERVICE_NAME);
Joe Onorato43a17652011-04-06 19:22:23 -07001971 if (false) Log.v("ContentService", "default service binder = " + b);
Dianne Hackborn231cc602009-04-27 17:10:36 -07001972 sContentService = IContentService.Stub.asInterface(b);
Joe Onorato43a17652011-04-06 19:22:23 -07001973 if (false) Log.v("ContentService", "default service = " + sContentService);
Dianne Hackborn231cc602009-04-27 17:10:36 -07001974 return sContentService;
1975 }
Tom O'Neill0ba1cb02010-01-08 12:53:50 -08001976
Dianne Hackborn35654b62013-01-14 17:38:02 -08001977 /** @hide */
1978 public String getPackageName() {
1979 return mPackageName;
1980 }
1981
Dianne Hackborn231cc602009-04-27 17:10:36 -07001982 private static IContentService sContentService;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001983 private final Context mContext;
Dianne Hackborn35654b62013-01-14 17:38:02 -08001984 final String mPackageName;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001985 private static final String TAG = "ContentResolver";
1986}