blob: 3fc933d1b4cd51f18a99d54f3deda8acfc2f7c04 [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
Brad Fitzpatricka63730d2010-02-07 22:25:34 -080019import android.accounts.Account;
Dianne Hackborncca1f0e2010-09-26 18:34:53 -070020import android.app.ActivityManagerNative;
Jeff Sharkey66a017b2013-01-17 18:18:22 -080021import android.app.ActivityThread;
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -070022import android.app.AppGlobals;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080023import android.content.pm.PackageManager.NameNotFoundException;
24import android.content.res.AssetFileDescriptor;
25import android.content.res.Resources;
26import android.database.ContentObserver;
Jeff Brown825c5132011-10-12 16:11:30 -070027import android.database.CrossProcessCursorWrapper;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080028import android.database.Cursor;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080029import android.database.IContentObserver;
30import android.net.Uri;
31import android.os.Bundle;
Jeff Browna7771df2012-05-07 20:06:46 -070032import android.os.CancellationSignal;
Dianne Hackborn6ae8d182012-05-23 13:12:42 -070033import android.os.DeadObjectException;
Dianne Hackborn231cc602009-04-27 17:10:36 -070034import android.os.IBinder;
Jeff Browna7771df2012-05-07 20:06:46 -070035import android.os.ICancellationSignal;
36import android.os.OperationCanceledException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080037import android.os.ParcelFileDescriptor;
38import android.os.RemoteException;
Dianne Hackborn231cc602009-04-27 17:10:36 -070039import android.os.ServiceManager;
Brad Fitzpatrickd72f7182010-02-11 17:07:51 -080040import android.os.SystemClock;
Dianne Hackborn5e03e2c2012-09-06 14:21:19 -070041import android.os.UserHandle;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080042import android.text.TextUtils;
Brad Fitzpatricka63730d2010-02-07 22:25:34 -080043import android.util.EventLog;
Dianne Hackborn231cc602009-04-27 17:10:36 -070044import android.util.Log;
Jeff Sharkey08da7a12013-08-11 20:53:18 -070045
46import dalvik.system.CloseGuard;
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
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080058/**
59 * This class provides applications access to the content model.
Joe Fernandez558459f2011-10-13 16:47:36 -070060 *
61 * <div class="special reference">
62 * <h3>Developer Guides</h3>
63 * <p>For more information about using a ContentResolver with content providers, read the
64 * <a href="{@docRoot}guide/topics/providers/content-providers.html">Content Providers</a>
65 * developer guide.</p>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080066 */
67public abstract class ContentResolver {
Fred Quintanaac9385e2009-06-22 18:00:59 -070068 /**
69 * @deprecated instead use
70 * {@link #requestSync(android.accounts.Account, String, android.os.Bundle)}
71 */
Fred Quintana4a6679b2009-08-17 13:05:39 -070072 @Deprecated
Fred Quintanaac9385e2009-06-22 18:00:59 -070073 public static final String SYNC_EXTRAS_ACCOUNT = "account";
Georgi Nikolovb3395572013-06-18 18:27:31 -070074
75 /**
76 * If this extra is set to true, the sync request will be scheduled
77 * at the front of the sync request queue and without any delay
78 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080079 public static final String SYNC_EXTRAS_EXPEDITED = "expedited";
Georgi Nikolovb3395572013-06-18 18:27:31 -070080
Fred Quintanaac9385e2009-06-22 18:00:59 -070081 /**
82 * @deprecated instead use
83 * {@link #SYNC_EXTRAS_MANUAL}
84 */
Fred Quintana4a6679b2009-08-17 13:05:39 -070085 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080086 public static final String SYNC_EXTRAS_FORCE = "force";
Fred Quintana53bd2522010-02-05 15:28:12 -080087
88 /**
89 * If this extra is set to true then the sync settings (like getSyncAutomatically())
90 * are ignored by the sync scheduler.
91 */
92 public static final String SYNC_EXTRAS_IGNORE_SETTINGS = "ignore_settings";
93
94 /**
95 * If this extra is set to true then any backoffs for the initial attempt (e.g. due to retries)
96 * are ignored by the sync scheduler. If this request fails and gets rescheduled then the
97 * retries will still honor the backoff.
98 */
99 public static final String SYNC_EXTRAS_IGNORE_BACKOFF = "ignore_backoff";
100
101 /**
102 * If this extra is set to true then the request will not be retried if it fails.
103 */
104 public static final String SYNC_EXTRAS_DO_NOT_RETRY = "do_not_retry";
105
106 /**
107 * Setting this extra is the equivalent of setting both {@link #SYNC_EXTRAS_IGNORE_SETTINGS}
108 * and {@link #SYNC_EXTRAS_IGNORE_BACKOFF}
109 */
Fred Quintanaac9385e2009-06-22 18:00:59 -0700110 public static final String SYNC_EXTRAS_MANUAL = "force";
Fred Quintana53bd2522010-02-05 15:28:12 -0800111
Georgi Nikolovb3395572013-06-18 18:27:31 -0700112 /**
113 * Indicates that this sync is intended to only upload local changes to the server.
114 * For example, this will be set to true if the sync is initiated by a call to
115 * {@link ContentResolver#notifyChange(android.net.Uri, android.database.ContentObserver, boolean)}
116 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800117 public static final String SYNC_EXTRAS_UPLOAD = "upload";
Georgi Nikolovb3395572013-06-18 18:27:31 -0700118
119 /**
120 * Indicates that the sync adapter should proceed with the delete operations,
121 * even if it determines that there are too many.
122 * See {@link SyncResult#tooManyDeletions}
123 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800124 public static final String SYNC_EXTRAS_OVERRIDE_TOO_MANY_DELETIONS = "deletions_override";
Georgi Nikolovb3395572013-06-18 18:27:31 -0700125
126 /**
127 * Indicates that the sync adapter should not proceed with the delete operations,
128 * if it determines that there are too many.
129 * See {@link SyncResult#tooManyDeletions}
130 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800131 public static final String SYNC_EXTRAS_DISCARD_LOCAL_DELETIONS = "discard_deletions";
132
Matthew Williamsfa774182013-06-18 15:44:11 -0700133 /* Extensions to API. TODO: Not clear if we will keep these as public flags. */
134 /** {@hide} User-specified flag for expected upload size. */
135 public static final String SYNC_EXTRAS_EXPECTED_UPLOAD = "expected_upload";
136
137 /** {@hide} User-specified flag for expected download size. */
138 public static final String SYNC_EXTRAS_EXPECTED_DOWNLOAD = "expected_download";
139
140 /** {@hide} Priority of this sync with respect to other syncs scheduled for this application. */
141 public static final String SYNC_EXTRAS_PRIORITY = "sync_priority";
142
143 /** {@hide} Flag to allow sync to occur on metered network. */
Matthew Williams56dbf8f2013-07-26 12:56:39 -0700144 public static final String SYNC_EXTRAS_DISALLOW_METERED = "allow_metered";
Matthew Williamsfa774182013-06-18 15:44:11 -0700145
Fred Quintana4a6679b2009-08-17 13:05:39 -0700146 /**
147 * Set by the SyncManager to request that the SyncAdapter initialize itself for
148 * the given account/authority pair. One required initialization step is to
149 * ensure that {@link #setIsSyncable(android.accounts.Account, String, int)} has been
150 * called with a >= 0 value. When this flag is set the SyncAdapter does not need to
151 * do a full sync, though it is allowed to do so.
152 */
153 public static final String SYNC_EXTRAS_INITIALIZE = "initialize";
154
Jeff Sharkey7a96c392012-11-15 14:01:46 -0800155 /** @hide */
156 public static final Intent ACTION_SYNC_CONN_STATUS_CHANGED =
157 new Intent("com.android.sync.SYNC_CONN_STATUS_CHANGED");
158
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800159 public static final String SCHEME_CONTENT = "content";
160 public static final String SCHEME_ANDROID_RESOURCE = "android.resource";
161 public static final String SCHEME_FILE = "file";
162
163 /**
164 * This is the Android platform's base MIME type for a content: URI
165 * containing a Cursor of a single item. Applications should use this
166 * as the base type along with their own sub-type of their content: URIs
167 * that represent a particular item. For example, hypothetical IMAP email
168 * client may have a URI
169 * <code>content://com.company.provider.imap/inbox/1</code> for a particular
170 * message in the inbox, whose MIME type would be reported as
171 * <code>CURSOR_ITEM_BASE_TYPE + "/vnd.company.imap-msg"</code>
Tom O'Neill0ba1cb02010-01-08 12:53:50 -0800172 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800173 * <p>Compare with {@link #CURSOR_DIR_BASE_TYPE}.
174 */
175 public static final String CURSOR_ITEM_BASE_TYPE = "vnd.android.cursor.item";
Tom O'Neill0ba1cb02010-01-08 12:53:50 -0800176
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800177 /**
178 * This is the Android platform's base MIME type for a content: URI
179 * containing a Cursor of zero or more items. Applications should use this
180 * as the base type along with their own sub-type of their content: URIs
181 * that represent a directory of items. For example, hypothetical IMAP email
182 * client may have a URI
183 * <code>content://com.company.provider.imap/inbox</code> for all of the
184 * messages in its inbox, whose MIME type would be reported as
185 * <code>CURSOR_DIR_BASE_TYPE + "/vnd.company.imap-msg"</code>
Tom O'Neill0ba1cb02010-01-08 12:53:50 -0800186 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800187 * <p>Note how the base MIME type varies between this and
188 * {@link #CURSOR_ITEM_BASE_TYPE} depending on whether there is
189 * one single item or multiple items in the data set, while the sub-type
190 * remains the same because in either case the data structure contained
191 * in the cursor is the same.
192 */
193 public static final String CURSOR_DIR_BASE_TYPE = "vnd.android.cursor.dir";
Fred Quintanaac9385e2009-06-22 18:00:59 -0700194
195 /** @hide */
196 public static final int SYNC_ERROR_SYNC_ALREADY_IN_PROGRESS = 1;
197 /** @hide */
198 public static final int SYNC_ERROR_AUTHENTICATION = 2;
199 /** @hide */
200 public static final int SYNC_ERROR_IO = 3;
201 /** @hide */
202 public static final int SYNC_ERROR_PARSE = 4;
203 /** @hide */
204 public static final int SYNC_ERROR_CONFLICT = 5;
205 /** @hide */
206 public static final int SYNC_ERROR_TOO_MANY_DELETIONS = 6;
207 /** @hide */
208 public static final int SYNC_ERROR_TOO_MANY_RETRIES = 7;
209 /** @hide */
210 public static final int SYNC_ERROR_INTERNAL = 8;
211
Alon Albert57286f92012-10-09 14:21:38 -0700212 private static final String[] SYNC_ERROR_NAMES = new String[] {
213 "already-in-progress",
214 "authentication-error",
215 "io-error",
216 "parse-error",
217 "conflict",
218 "too-many-deletions",
219 "too-many-retries",
220 "internal-error",
221 };
222
223 /** @hide */
Jeff Sharkey7a96c392012-11-15 14:01:46 -0800224 public static String syncErrorToString(int error) {
Alon Albert57286f92012-10-09 14:21:38 -0700225 if (error < 1 || error > SYNC_ERROR_NAMES.length) {
226 return String.valueOf(error);
227 }
228 return SYNC_ERROR_NAMES[error - 1];
229 }
230
Alon Albert5c113fa2013-02-07 08:07:32 -0800231 /** @hide */
232 public static int syncErrorStringToInt(String error) {
233 for (int i = 0, n = SYNC_ERROR_NAMES.length; i < n; i++) {
234 if (SYNC_ERROR_NAMES[i].equals(error)) {
235 return i + 1;
236 }
237 }
238 if (error != null) {
239 try {
240 return Integer.parseInt(error);
241 } catch (NumberFormatException e) {
242 Log.d(TAG, "error parsing sync error: " + error);
243 }
244 }
245 return 0;
246 }
247
Fred Quintanaac9385e2009-06-22 18:00:59 -0700248 public static final int SYNC_OBSERVER_TYPE_SETTINGS = 1<<0;
Fred Quintanaac9385e2009-06-22 18:00:59 -0700249 public static final int SYNC_OBSERVER_TYPE_PENDING = 1<<1;
Fred Quintanaac9385e2009-06-22 18:00:59 -0700250 public static final int SYNC_OBSERVER_TYPE_ACTIVE = 1<<2;
251 /** @hide */
252 public static final int SYNC_OBSERVER_TYPE_STATUS = 1<<3;
253 /** @hide */
254 public static final int SYNC_OBSERVER_TYPE_ALL = 0x7fffffff;
255
Brad Fitzpatrick25880962010-02-22 15:17:49 -0800256 // Always log queries which take 500ms+; shorter queries are
Brad Fitzpatricka63730d2010-02-07 22:25:34 -0800257 // sampled accordingly.
Jeff Sharkey2b4d22c2013-04-26 10:52:00 -0700258 private static final boolean ENABLE_CONTENT_SAMPLE = false;
Brad Fitzpatrick25880962010-02-22 15:17:49 -0800259 private static final int SLOW_THRESHOLD_MILLIS = 500;
Brad Fitzpatricka63730d2010-02-07 22:25:34 -0800260 private final Random mRandom = new Random(); // guarded by itself
261
Dianne Hackborn231cc602009-04-27 17:10:36 -0700262 public ContentResolver(Context context) {
Jeff Sharkey66a017b2013-01-17 18:18:22 -0800263 mContext = context != null ? context : ActivityThread.currentApplication();
Dianne Hackborn95d78532013-09-11 09:51:14 -0700264 mPackageName = mContext.getOpPackageName();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800265 }
266
267 /** @hide */
268 protected abstract IContentProvider acquireProvider(Context c, String name);
Jeff Sharkeye66c1772013-09-20 14:30:59 -0700269
270 /**
271 * Providing a default implementation of this, to avoid having to change a
272 * lot of other things, but implementations of ContentResolver should
273 * implement it.
274 *
275 * @hide
276 */
Dianne Hackborncca1f0e2010-09-26 18:34:53 -0700277 protected IContentProvider acquireExistingProvider(Context c, String name) {
278 return acquireProvider(c, name);
279 }
Jeff Sharkeye66c1772013-09-20 14:30:59 -0700280
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800281 /** @hide */
282 public abstract boolean releaseProvider(IContentProvider icp);
Dianne Hackborn652b6d12012-05-09 18:18:40 -0700283 /** @hide */
284 protected abstract IContentProvider acquireUnstableProvider(Context c, String name);
285 /** @hide */
286 public abstract boolean releaseUnstableProvider(IContentProvider icp);
Dianne Hackborn6ae8d182012-05-23 13:12:42 -0700287 /** @hide */
288 public abstract void unstableProviderDied(IContentProvider icp);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800289
Jeff Sharkey7aa76012013-09-30 14:26:27 -0700290 /** @hide */
291 public void appNotRespondingViaProvider(IContentProvider icp) {
292 throw new UnsupportedOperationException("appNotRespondingViaProvider");
293 }
294
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800295 /**
296 * Return the MIME type of the given content URL.
297 *
298 * @param url A Uri identifying content (either a list or specific type),
299 * using the content:// scheme.
300 * @return A MIME type for the content, or null if the URL is invalid or the type is unknown
301 */
Dianne Hackborn23fdaf62010-08-06 12:16:55 -0700302 public final String getType(Uri url) {
Dianne Hackborn6ae8d182012-05-23 13:12:42 -0700303 // XXX would like to have an acquireExistingUnstableProvider for this.
Dianne Hackborncca1f0e2010-09-26 18:34:53 -0700304 IContentProvider provider = acquireExistingProvider(url);
305 if (provider != null) {
306 try {
307 return provider.getType(url);
308 } catch (RemoteException e) {
309 return null;
310 } catch (java.lang.Exception e) {
Ola Olsson145e6c42010-12-20 16:45:35 +0100311 Log.w(TAG, "Failed to get type for: " + url + " (" + e.getMessage() + ")");
Dianne Hackborncca1f0e2010-09-26 18:34:53 -0700312 return null;
313 } finally {
314 releaseProvider(provider);
315 }
316 }
317
318 if (!SCHEME_CONTENT.equals(url.getScheme())) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800319 return null;
320 }
Dianne Hackborncca1f0e2010-09-26 18:34:53 -0700321
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800322 try {
Dianne Hackborn5e03e2c2012-09-06 14:21:19 -0700323 String type = ActivityManagerNative.getDefault().getProviderMimeType(
324 url, UserHandle.myUserId());
Dianne Hackborncca1f0e2010-09-26 18:34:53 -0700325 return type;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800326 } catch (RemoteException e) {
Brad Fitzpatrick534c84c2011-01-12 14:06:30 -0800327 // Arbitrary and not worth documenting, as Activity
328 // Manager will kill this process shortly anyway.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800329 return null;
Ola Olsson145e6c42010-12-20 16:45:35 +0100330 } catch (java.lang.Exception e) {
331 Log.w(TAG, "Failed to get type for: " + url + " (" + e.getMessage() + ")");
332 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800333 }
334 }
335
336 /**
Dianne Hackborn23fdaf62010-08-06 12:16:55 -0700337 * Query for the possible MIME types for the representations the given
338 * content URL can be returned when opened as as stream with
339 * {@link #openTypedAssetFileDescriptor}. Note that the types here are
340 * not necessarily a superset of the type returned by {@link #getType} --
Jeff Sharkeybd3b9022013-08-20 15:20:04 -0700341 * many content providers cannot return a raw stream for the structured
Dianne Hackborn23fdaf62010-08-06 12:16:55 -0700342 * data that they contain.
343 *
344 * @param url A Uri identifying content (either a list or specific type),
345 * using the content:// scheme.
346 * @param mimeTypeFilter The desired MIME type. This may be a pattern,
John Spurlock33900182014-01-02 11:04:18 -0500347 * such as *&#47;*, to query for all available MIME types that match the
Dianne Hackborn23fdaf62010-08-06 12:16:55 -0700348 * pattern.
Dianne Hackbornacb69bb2012-04-13 15:36:06 -0700349 * @return Returns an array of MIME type strings for all available
Dianne Hackborn23fdaf62010-08-06 12:16:55 -0700350 * data streams that match the given mimeTypeFilter. If there are none,
351 * null is returned.
352 */
353 public String[] getStreamTypes(Uri url, String mimeTypeFilter) {
354 IContentProvider provider = acquireProvider(url);
355 if (provider == null) {
356 return null;
357 }
Dianne Hackborn64bbbb42010-09-27 20:25:20 -0700358
Dianne Hackborn23fdaf62010-08-06 12:16:55 -0700359 try {
360 return provider.getStreamTypes(url, mimeTypeFilter);
361 } catch (RemoteException e) {
Brad Fitzpatrick534c84c2011-01-12 14:06:30 -0800362 // Arbitrary and not worth documenting, as Activity
363 // Manager will kill this process shortly anyway.
Dianne Hackborn23fdaf62010-08-06 12:16:55 -0700364 return null;
Dianne Hackborn23fdaf62010-08-06 12:16:55 -0700365 } finally {
Brad Fitzpatrick534c84c2011-01-12 14:06:30 -0800366 releaseProvider(provider);
367 }
Dianne Hackborn23fdaf62010-08-06 12:16:55 -0700368 }
369
370 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800371 * Query the given URI, returning a {@link Cursor} over the result set.
Tom O'Neill0ba1cb02010-01-08 12:53:50 -0800372 * <p>
373 * For best performance, the caller should follow these guidelines:
374 * <ul>
375 * <li>Provide an explicit projection, to prevent
376 * reading data from storage that aren't going to be used.</li>
377 * <li>Use question mark parameter markers such as 'phone=?' instead of
378 * explicit values in the {@code selection} parameter, so that queries
379 * that differ only by those values will be recognized as the same
380 * for caching purposes.</li>
381 * </ul>
382 * </p>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800383 *
384 * @param uri The URI, using the content:// scheme, for the content to
385 * retrieve.
386 * @param projection A list of which columns to return. Passing null will
Tom O'Neill0ba1cb02010-01-08 12:53:50 -0800387 * return all columns, which is inefficient.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800388 * @param selection A filter declaring which rows to return, formatted as an
389 * SQL WHERE clause (excluding the WHERE itself). Passing null will
390 * return all rows for the given URI.
391 * @param selectionArgs You may include ?s in selection, which will be
392 * replaced by the values from selectionArgs, in the order that they
393 * appear in the selection. The values will be bound as Strings.
394 * @param sortOrder How to order the rows, formatted as an SQL ORDER BY
395 * clause (excluding the ORDER BY itself). Passing null will use the
396 * default sort order, which may be unordered.
397 * @return A Cursor object, which is positioned before the first entry, or null
398 * @see Cursor
399 */
400 public final Cursor query(Uri uri, String[] projection,
401 String selection, String[] selectionArgs, String sortOrder) {
Jeff Brown75ea64f2012-01-25 19:37:13 -0800402 return query(uri, projection, selection, selectionArgs, sortOrder, null);
403 }
404
405 /**
Jeff Brownc64ff372013-10-09 18:50:56 -0700406 * Query the given URI, returning a {@link Cursor} over the result set
407 * with optional support for cancellation.
Jeff Brown75ea64f2012-01-25 19:37:13 -0800408 * <p>
409 * For best performance, the caller should follow these guidelines:
410 * <ul>
411 * <li>Provide an explicit projection, to prevent
412 * reading data from storage that aren't going to be used.</li>
413 * <li>Use question mark parameter markers such as 'phone=?' instead of
414 * explicit values in the {@code selection} parameter, so that queries
415 * that differ only by those values will be recognized as the same
416 * for caching purposes.</li>
417 * </ul>
418 * </p>
419 *
420 * @param uri The URI, using the content:// scheme, for the content to
421 * retrieve.
422 * @param projection A list of which columns to return. Passing null will
423 * return all columns, which is inefficient.
424 * @param selection A filter declaring which rows to return, formatted as an
425 * SQL WHERE clause (excluding the WHERE itself). Passing null will
426 * return all rows for the given URI.
427 * @param selectionArgs You may include ?s in selection, which will be
428 * replaced by the values from selectionArgs, in the order that they
429 * appear in the selection. The values will be bound as Strings.
430 * @param sortOrder How to order the rows, formatted as an SQL ORDER BY
431 * clause (excluding the ORDER BY itself). Passing null will use the
432 * default sort order, which may be unordered.
Jeff Brown4c1241d2012-02-02 17:05:00 -0800433 * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
Jeff Brown75ea64f2012-01-25 19:37:13 -0800434 * If the operation is canceled, then {@link OperationCanceledException} will be thrown
435 * when the query is executed.
436 * @return A Cursor object, which is positioned before the first entry, or null
437 * @see Cursor
438 */
439 public final Cursor query(final Uri uri, String[] projection,
440 String selection, String[] selectionArgs, String sortOrder,
Jeff Brown4c1241d2012-02-02 17:05:00 -0800441 CancellationSignal cancellationSignal) {
Dianne Hackborn6ae8d182012-05-23 13:12:42 -0700442 IContentProvider unstableProvider = acquireUnstableProvider(uri);
443 if (unstableProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800444 return null;
445 }
Dianne Hackborn6ae8d182012-05-23 13:12:42 -0700446 IContentProvider stableProvider = null;
Jeff Brownc21b5a02013-01-07 17:15:12 -0800447 Cursor qCursor = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800448 try {
Brad Fitzpatrickd72f7182010-02-11 17:07:51 -0800449 long startTime = SystemClock.uptimeMillis();
Jeff Brown75ea64f2012-01-25 19:37:13 -0800450
Jeff Brown4c1241d2012-02-02 17:05:00 -0800451 ICancellationSignal remoteCancellationSignal = null;
452 if (cancellationSignal != null) {
453 cancellationSignal.throwIfCanceled();
Dianne Hackborn6ae8d182012-05-23 13:12:42 -0700454 remoteCancellationSignal = unstableProvider.createCancellationSignal();
Jeff Brown4c1241d2012-02-02 17:05:00 -0800455 cancellationSignal.setRemote(remoteCancellationSignal);
Jeff Brown75ea64f2012-01-25 19:37:13 -0800456 }
Dianne Hackborn6ae8d182012-05-23 13:12:42 -0700457 try {
Dianne Hackborn35654b62013-01-14 17:38:02 -0800458 qCursor = unstableProvider.query(mPackageName, uri, projection,
Dianne Hackborn6ae8d182012-05-23 13:12:42 -0700459 selection, selectionArgs, sortOrder, remoteCancellationSignal);
460 } catch (DeadObjectException e) {
461 // The remote process has died... but we only hold an unstable
462 // reference though, so we might recover!!! Let's try!!!!
463 // This is exciting!!1!!1!!!!1
464 unstableProviderDied(unstableProvider);
465 stableProvider = acquireProvider(uri);
466 if (stableProvider == null) {
467 return null;
468 }
Dianne Hackborn35654b62013-01-14 17:38:02 -0800469 qCursor = stableProvider.query(mPackageName, uri, projection,
Dianne Hackborn6ae8d182012-05-23 13:12:42 -0700470 selection, selectionArgs, sortOrder, remoteCancellationSignal);
471 }
Brad Fitzpatricka63730d2010-02-07 22:25:34 -0800472 if (qCursor == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800473 return null;
474 }
Jeff Brownc21b5a02013-01-07 17:15:12 -0800475
476 // Force query execution. Might fail and throw a runtime exception here.
Vasu Nori020e5342010-04-28 14:22:38 -0700477 qCursor.getCount();
Brad Fitzpatrickd72f7182010-02-11 17:07:51 -0800478 long durationMillis = SystemClock.uptimeMillis() - startTime;
Brad Fitzpatricka63730d2010-02-07 22:25:34 -0800479 maybeLogQueryToEventLog(durationMillis, uri, projection, selection, sortOrder);
Jeff Brownc21b5a02013-01-07 17:15:12 -0800480
481 // Wrap the cursor object into CursorWrapperInner object.
Dianne Hackborn6ae8d182012-05-23 13:12:42 -0700482 CursorWrapperInner wrapper = new CursorWrapperInner(qCursor,
483 stableProvider != null ? stableProvider : acquireProvider(uri));
484 stableProvider = null;
Jeff Brownc21b5a02013-01-07 17:15:12 -0800485 qCursor = null;
Dianne Hackborn6ae8d182012-05-23 13:12:42 -0700486 return wrapper;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800487 } catch (RemoteException e) {
Brad Fitzpatrick534c84c2011-01-12 14:06:30 -0800488 // Arbitrary and not worth documenting, as Activity
489 // Manager will kill this process shortly anyway.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800490 return null;
Dianne Hackborn6ae8d182012-05-23 13:12:42 -0700491 } finally {
Jeff Brownc21b5a02013-01-07 17:15:12 -0800492 if (qCursor != null) {
493 qCursor.close();
494 }
Jeff Sharkeybd3b9022013-08-20 15:20:04 -0700495 if (cancellationSignal != null) {
496 cancellationSignal.setRemote(null);
497 }
Dianne Hackborn6ae8d182012-05-23 13:12:42 -0700498 if (unstableProvider != null) {
499 releaseUnstableProvider(unstableProvider);
500 }
501 if (stableProvider != null) {
502 releaseProvider(stableProvider);
503 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800504 }
505 }
506
Fred Quintana89437372009-05-15 15:10:40 -0700507 /**
Dianne Hackborn38ed2a42013-09-06 16:17:22 -0700508 * Transform the given <var>url</var> to a canonical representation of
509 * its referenced resource, which can be used across devices, persisted,
510 * backed up and restored, etc. The returned Uri is still a fully capable
511 * Uri for use with its content provider, allowing you to do all of the
512 * same content provider operations as with the original Uri --
513 * {@link #query}, {@link #openInputStream(android.net.Uri)}, etc. The
514 * only difference in behavior between the original and new Uris is that
515 * the content provider may need to do some additional work at each call
516 * using it to resolve it to the correct resource, especially if the
517 * canonical Uri has been moved to a different environment.
518 *
519 * <p>If you are moving a canonical Uri between environments, you should
520 * perform another call to {@link #canonicalize} with that original Uri to
521 * re-canonicalize it for the current environment. Alternatively, you may
522 * want to use {@link #uncanonicalize} to transform it to a non-canonical
523 * Uri that works only in the current environment but potentially more
524 * efficiently than the canonical representation.</p>
525 *
526 * @param url The {@link Uri} that is to be transformed to a canonical
527 * representation. Like all resolver calls, the input can be either
528 * a non-canonical or canonical Uri.
529 *
530 * @return Returns the official canonical representation of <var>url</var>,
531 * or null if the content provider does not support a canonical representation
532 * of the given Uri. Many providers may not support canonicalization of some
533 * or all of their Uris.
534 *
535 * @see #uncanonicalize
536 */
537 public final Uri canonicalize(Uri url) {
538 IContentProvider provider = acquireProvider(url);
539 if (provider == null) {
540 return null;
541 }
542
543 try {
544 return provider.canonicalize(mPackageName, url);
545 } catch (RemoteException e) {
546 // Arbitrary and not worth documenting, as Activity
547 // Manager will kill this process shortly anyway.
548 return null;
549 } finally {
550 releaseProvider(provider);
551 }
552 }
553
554 /**
555 * Given a canonical Uri previously generated by {@link #canonicalize}, convert
556 * it to its local non-canonical form. This can be useful in some cases where
557 * you know that you will only be using the Uri in the current environment and
558 * want to avoid any possible overhead when using it with the content
Dianne Hackbornb3ac67a2013-09-11 11:02:24 -0700559 * provider or want to verify that the referenced data exists at all in the
560 * new environment.
Dianne Hackborn38ed2a42013-09-06 16:17:22 -0700561 *
562 * @param url The canonical {@link Uri} that is to be convered back to its
563 * non-canonical form.
564 *
Dianne Hackbornb3ac67a2013-09-11 11:02:24 -0700565 * @return Returns the non-canonical representation of <var>url</var>. This will
566 * return null if data identified by the canonical Uri can not be found in
567 * the current environment; callers must always check for null and deal with
568 * that by appropriately falling back to an alternative.
Dianne Hackborn38ed2a42013-09-06 16:17:22 -0700569 *
570 * @see #canonicalize
571 */
572 public final Uri uncanonicalize(Uri url) {
573 IContentProvider provider = acquireProvider(url);
574 if (provider == null) {
575 return null;
576 }
577
578 try {
579 return provider.uncanonicalize(mPackageName, url);
580 } catch (RemoteException e) {
581 // Arbitrary and not worth documenting, as Activity
582 // Manager will kill this process shortly anyway.
583 return null;
584 } finally {
585 releaseProvider(provider);
586 }
587 }
588
589 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800590 * Open a stream on to the content associated with a content URI. If there
591 * is no data associated with the URI, FileNotFoundException is thrown.
592 *
593 * <h5>Accepts the following URI schemes:</h5>
594 * <ul>
595 * <li>content ({@link #SCHEME_CONTENT})</li>
596 * <li>android.resource ({@link #SCHEME_ANDROID_RESOURCE})</li>
597 * <li>file ({@link #SCHEME_FILE})</li>
598 * </ul>
Tom O'Neill0ba1cb02010-01-08 12:53:50 -0800599 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800600 * <p>See {@link #openAssetFileDescriptor(Uri, String)} for more information
601 * on these schemes.
Tom O'Neill0ba1cb02010-01-08 12:53:50 -0800602 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800603 * @param uri The desired URI.
604 * @return InputStream
605 * @throws FileNotFoundException if the provided URI could not be opened.
606 * @see #openAssetFileDescriptor(Uri, String)
607 */
608 public final InputStream openInputStream(Uri uri)
609 throws FileNotFoundException {
610 String scheme = uri.getScheme();
611 if (SCHEME_ANDROID_RESOURCE.equals(scheme)) {
612 // Note: left here to avoid breaking compatibility. May be removed
613 // with sufficient testing.
614 OpenResourceIdResult r = getResourceId(uri);
615 try {
616 InputStream stream = r.r.openRawResource(r.id);
617 return stream;
618 } catch (Resources.NotFoundException ex) {
619 throw new FileNotFoundException("Resource does not exist: " + uri);
620 }
621 } else if (SCHEME_FILE.equals(scheme)) {
622 // Note: left here to avoid breaking compatibility. May be removed
623 // with sufficient testing.
624 return new FileInputStream(uri.getPath());
625 } else {
Jeff Sharkeybd3b9022013-08-20 15:20:04 -0700626 AssetFileDescriptor fd = openAssetFileDescriptor(uri, "r", null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800627 try {
628 return fd != null ? fd.createInputStream() : null;
629 } catch (IOException e) {
630 throw new FileNotFoundException("Unable to create stream");
631 }
632 }
633 }
634
635 /**
636 * Synonym for {@link #openOutputStream(Uri, String)
637 * openOutputStream(uri, "w")}.
638 * @throws FileNotFoundException if the provided URI could not be opened.
639 */
640 public final OutputStream openOutputStream(Uri uri)
641 throws FileNotFoundException {
642 return openOutputStream(uri, "w");
643 }
644
645 /**
646 * Open a stream on to the content associated with a content URI. If there
647 * is no data associated with the URI, FileNotFoundException is thrown.
648 *
649 * <h5>Accepts the following URI schemes:</h5>
650 * <ul>
651 * <li>content ({@link #SCHEME_CONTENT})</li>
652 * <li>file ({@link #SCHEME_FILE})</li>
653 * </ul>
654 *
655 * <p>See {@link #openAssetFileDescriptor(Uri, String)} for more information
656 * on these schemes.
Tom O'Neill0ba1cb02010-01-08 12:53:50 -0800657 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800658 * @param uri The desired URI.
659 * @param mode May be "w", "wa", "rw", or "rwt".
660 * @return OutputStream
661 * @throws FileNotFoundException if the provided URI could not be opened.
662 * @see #openAssetFileDescriptor(Uri, String)
663 */
664 public final OutputStream openOutputStream(Uri uri, String mode)
665 throws FileNotFoundException {
Jeff Sharkeybd3b9022013-08-20 15:20:04 -0700666 AssetFileDescriptor fd = openAssetFileDescriptor(uri, mode, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800667 try {
668 return fd != null ? fd.createOutputStream() : null;
669 } catch (IOException e) {
670 throw new FileNotFoundException("Unable to create stream");
671 }
672 }
673
674 /**
Dianne Hackborn23fdaf62010-08-06 12:16:55 -0700675 * Open a raw file descriptor to access data under a URI. This
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800676 * is like {@link #openAssetFileDescriptor(Uri, String)}, but uses the
677 * underlying {@link ContentProvider#openFile}
678 * ContentProvider.openFile()} method, so will <em>not</em> work with
679 * providers that return sub-sections of files. If at all possible,
680 * you should use {@link #openAssetFileDescriptor(Uri, String)}. You
681 * will receive a FileNotFoundException exception if the provider returns a
682 * sub-section of a file.
683 *
684 * <h5>Accepts the following URI schemes:</h5>
685 * <ul>
686 * <li>content ({@link #SCHEME_CONTENT})</li>
687 * <li>file ({@link #SCHEME_FILE})</li>
688 * </ul>
689 *
690 * <p>See {@link #openAssetFileDescriptor(Uri, String)} for more information
691 * on these schemes.
Jeff Sharkeybd3b9022013-08-20 15:20:04 -0700692 * <p>
693 * If opening with the exclusive "r" or "w" modes, the returned
694 * ParcelFileDescriptor could be a pipe or socket pair to enable streaming
695 * of data. Opening with the "rw" mode implies a file on disk that supports
696 * seeking. If possible, always use an exclusive mode to give the underlying
697 * {@link ContentProvider} the most flexibility.
698 * <p>
699 * If you are writing a file, and need to communicate an error to the
700 * provider, use {@link ParcelFileDescriptor#closeWithError(String)}.
Tom O'Neill0ba1cb02010-01-08 12:53:50 -0800701 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800702 * @param uri The desired URI to open.
703 * @param mode The file mode to use, as per {@link ContentProvider#openFile
704 * ContentProvider.openFile}.
705 * @return Returns a new ParcelFileDescriptor pointing to the file. You
706 * own this descriptor and are responsible for closing it when done.
Yury Zhauniarovichf9c51762012-05-12 18:39:25 +0200707 * @throws FileNotFoundException Throws FileNotFoundException if no
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800708 * file exists under the URI or the mode is invalid.
709 * @see #openAssetFileDescriptor(Uri, String)
710 */
Jeff Sharkeybd3b9022013-08-20 15:20:04 -0700711 public final ParcelFileDescriptor openFileDescriptor(Uri uri, String mode)
712 throws FileNotFoundException {
713 return openFileDescriptor(uri, mode, null);
714 }
715
716 /**
717 * Open a raw file descriptor to access data under a URI. This
718 * is like {@link #openAssetFileDescriptor(Uri, String)}, but uses the
719 * underlying {@link ContentProvider#openFile}
720 * ContentProvider.openFile()} method, so will <em>not</em> work with
721 * providers that return sub-sections of files. If at all possible,
722 * you should use {@link #openAssetFileDescriptor(Uri, String)}. You
723 * will receive a FileNotFoundException exception if the provider returns a
724 * sub-section of a file.
725 *
726 * <h5>Accepts the following URI schemes:</h5>
727 * <ul>
728 * <li>content ({@link #SCHEME_CONTENT})</li>
729 * <li>file ({@link #SCHEME_FILE})</li>
730 * </ul>
731 *
732 * <p>See {@link #openAssetFileDescriptor(Uri, String)} for more information
733 * on these schemes.
734 * <p>
735 * If opening with the exclusive "r" or "w" modes, the returned
736 * ParcelFileDescriptor could be a pipe or socket pair to enable streaming
737 * of data. Opening with the "rw" mode implies a file on disk that supports
738 * seeking. If possible, always use an exclusive mode to give the underlying
739 * {@link ContentProvider} the most flexibility.
740 * <p>
741 * If you are writing a file, and need to communicate an error to the
742 * provider, use {@link ParcelFileDescriptor#closeWithError(String)}.
743 *
744 * @param uri The desired URI to open.
745 * @param mode The file mode to use, as per {@link ContentProvider#openFile
746 * ContentProvider.openFile}.
Ying Wang94366312013-08-23 22:20:03 -0700747 * @param cancellationSignal A signal to cancel the operation in progress,
748 * or null if none. If the operation is canceled, then
749 * {@link OperationCanceledException} will be thrown.
Jeff Sharkeybd3b9022013-08-20 15:20:04 -0700750 * @return Returns a new ParcelFileDescriptor pointing to the file. You
751 * own this descriptor and are responsible for closing it when done.
752 * @throws FileNotFoundException Throws FileNotFoundException if no
753 * file exists under the URI or the mode is invalid.
754 * @see #openAssetFileDescriptor(Uri, String)
755 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800756 public final ParcelFileDescriptor openFileDescriptor(Uri uri,
Jeff Sharkeybd3b9022013-08-20 15:20:04 -0700757 String mode, CancellationSignal cancellationSignal) throws FileNotFoundException {
758 AssetFileDescriptor afd = openAssetFileDescriptor(uri, mode, cancellationSignal);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800759 if (afd == null) {
760 return null;
761 }
Tom O'Neill0ba1cb02010-01-08 12:53:50 -0800762
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800763 if (afd.getDeclaredLength() < 0) {
764 // This is a full file!
765 return afd.getParcelFileDescriptor();
766 }
Tom O'Neill0ba1cb02010-01-08 12:53:50 -0800767
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800768 // Client can't handle a sub-section of a file, so close what
769 // we got and bail with an exception.
770 try {
771 afd.close();
772 } catch (IOException e) {
773 }
Tom O'Neill0ba1cb02010-01-08 12:53:50 -0800774
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800775 throw new FileNotFoundException("Not a whole file");
776 }
777
778 /**
Dianne Hackborn23fdaf62010-08-06 12:16:55 -0700779 * Open a raw file descriptor to access data under a URI. This
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800780 * interacts with the underlying {@link ContentProvider#openAssetFile}
Gilles Debunne03f02922010-06-09 14:11:45 -0700781 * 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 -0800782 *
783 * <h5>Accepts the following URI schemes:</h5>
784 * <ul>
785 * <li>content ({@link #SCHEME_CONTENT})</li>
786 * <li>android.resource ({@link #SCHEME_ANDROID_RESOURCE})</li>
787 * <li>file ({@link #SCHEME_FILE})</li>
788 * </ul>
789 * <h5>The android.resource ({@link #SCHEME_ANDROID_RESOURCE}) Scheme</h5>
790 * <p>
791 * A Uri object can be used to reference a resource in an APK file. The
792 * Uri should be one of the following formats:
793 * <ul>
794 * <li><code>android.resource://package_name/id_number</code><br/>
795 * <code>package_name</code> is your package name as listed in your AndroidManifest.xml.
796 * For example <code>com.example.myapp</code><br/>
797 * <code>id_number</code> is the int form of the ID.<br/>
798 * The easiest way to construct this form is
799 * <pre>Uri uri = Uri.parse("android.resource://com.example.myapp/" + R.raw.my_resource");</pre>
800 * </li>
801 * <li><code>android.resource://package_name/type/name</code><br/>
802 * <code>package_name</code> is your package name as listed in your AndroidManifest.xml.
803 * For example <code>com.example.myapp</code><br/>
804 * <code>type</code> is the string form of the resource type. For example, <code>raw</code>
805 * or <code>drawable</code>.
806 * <code>name</code> is the string form of the resource name. That is, whatever the file
807 * name was in your res directory, without the type extension.
808 * The easiest way to construct this form is
809 * <pre>Uri uri = Uri.parse("android.resource://com.example.myapp/raw/my_resource");</pre>
810 * </li>
811 * </ul>
812 *
Dianne Hackborn23fdaf62010-08-06 12:16:55 -0700813 * <p>Note that if this function is called for read-only input (mode is "r")
814 * on a content: URI, it will instead call {@link #openTypedAssetFileDescriptor}
John Spurlock33900182014-01-02 11:04:18 -0500815 * for you with a MIME type of "*&#47;*". This allows such callers to benefit
Dianne Hackborn23fdaf62010-08-06 12:16:55 -0700816 * from any built-in data conversion that a provider implements.
817 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800818 * @param uri The desired URI to open.
819 * @param mode The file mode to use, as per {@link ContentProvider#openAssetFile
820 * ContentProvider.openAssetFile}.
821 * @return Returns a new ParcelFileDescriptor pointing to the file. You
822 * own this descriptor and are responsible for closing it when done.
823 * @throws FileNotFoundException Throws FileNotFoundException of no
824 * file exists under the URI or the mode is invalid.
825 */
Jeff Sharkeybd3b9022013-08-20 15:20:04 -0700826 public final AssetFileDescriptor openAssetFileDescriptor(Uri uri, String mode)
827 throws FileNotFoundException {
828 return openAssetFileDescriptor(uri, mode, null);
829 }
830
831 /**
832 * Open a raw file descriptor to access data under a URI. This
833 * interacts with the underlying {@link ContentProvider#openAssetFile}
834 * method of the provider associated with the given URI, to retrieve any file stored there.
835 *
836 * <h5>Accepts the following URI schemes:</h5>
837 * <ul>
838 * <li>content ({@link #SCHEME_CONTENT})</li>
839 * <li>android.resource ({@link #SCHEME_ANDROID_RESOURCE})</li>
840 * <li>file ({@link #SCHEME_FILE})</li>
841 * </ul>
842 * <h5>The android.resource ({@link #SCHEME_ANDROID_RESOURCE}) Scheme</h5>
843 * <p>
844 * A Uri object can be used to reference a resource in an APK file. The
845 * Uri should be one of the following formats:
846 * <ul>
847 * <li><code>android.resource://package_name/id_number</code><br/>
848 * <code>package_name</code> is your package name as listed in your AndroidManifest.xml.
849 * For example <code>com.example.myapp</code><br/>
850 * <code>id_number</code> is the int form of the ID.<br/>
851 * The easiest way to construct this form is
852 * <pre>Uri uri = Uri.parse("android.resource://com.example.myapp/" + R.raw.my_resource");</pre>
853 * </li>
854 * <li><code>android.resource://package_name/type/name</code><br/>
855 * <code>package_name</code> is your package name as listed in your AndroidManifest.xml.
856 * For example <code>com.example.myapp</code><br/>
857 * <code>type</code> is the string form of the resource type. For example, <code>raw</code>
858 * or <code>drawable</code>.
859 * <code>name</code> is the string form of the resource name. That is, whatever the file
860 * name was in your res directory, without the type extension.
861 * The easiest way to construct this form is
862 * <pre>Uri uri = Uri.parse("android.resource://com.example.myapp/raw/my_resource");</pre>
863 * </li>
864 * </ul>
865 *
866 * <p>Note that if this function is called for read-only input (mode is "r")
867 * on a content: URI, it will instead call {@link #openTypedAssetFileDescriptor}
John Spurlock33900182014-01-02 11:04:18 -0500868 * for you with a MIME type of "*&#47;*". This allows such callers to benefit
Jeff Sharkeybd3b9022013-08-20 15:20:04 -0700869 * from any built-in data conversion that a provider implements.
870 *
871 * @param uri The desired URI to open.
872 * @param mode The file mode to use, as per {@link ContentProvider#openAssetFile
873 * ContentProvider.openAssetFile}.
Ying Wang94366312013-08-23 22:20:03 -0700874 * @param cancellationSignal A signal to cancel the operation in progress, or null if
Jeff Sharkeybd3b9022013-08-20 15:20:04 -0700875 * none. If the operation is canceled, then
876 * {@link OperationCanceledException} will be thrown.
877 * @return Returns a new ParcelFileDescriptor pointing to the file. You
878 * own this descriptor and are responsible for closing it when done.
879 * @throws FileNotFoundException Throws FileNotFoundException of no
880 * file exists under the URI or the mode is invalid.
881 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800882 public final AssetFileDescriptor openAssetFileDescriptor(Uri uri,
Jeff Sharkeybd3b9022013-08-20 15:20:04 -0700883 String mode, CancellationSignal cancellationSignal) throws FileNotFoundException {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800884 String scheme = uri.getScheme();
885 if (SCHEME_ANDROID_RESOURCE.equals(scheme)) {
886 if (!"r".equals(mode)) {
887 throw new FileNotFoundException("Can't write resources: " + uri);
888 }
889 OpenResourceIdResult r = getResourceId(uri);
890 try {
891 return r.r.openRawResourceFd(r.id);
892 } catch (Resources.NotFoundException ex) {
893 throw new FileNotFoundException("Resource does not exist: " + uri);
894 }
895 } else if (SCHEME_FILE.equals(scheme)) {
896 ParcelFileDescriptor pfd = ParcelFileDescriptor.open(
Adam Lesinskieb8c3f92013-09-20 14:08:25 -0700897 new File(uri.getPath()), ParcelFileDescriptor.parseMode(mode));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800898 return new AssetFileDescriptor(pfd, 0, -1);
899 } else {
Dianne Hackborn23fdaf62010-08-06 12:16:55 -0700900 if ("r".equals(mode)) {
Jeff Sharkeybd3b9022013-08-20 15:20:04 -0700901 return openTypedAssetFileDescriptor(uri, "*/*", null, cancellationSignal);
Dianne Hackborn23fdaf62010-08-06 12:16:55 -0700902 } else {
Dianne Hackborn6ae8d182012-05-23 13:12:42 -0700903 IContentProvider unstableProvider = acquireUnstableProvider(uri);
904 if (unstableProvider == null) {
905 throw new FileNotFoundException("No content provider: " + uri);
906 }
907 IContentProvider stableProvider = null;
908 AssetFileDescriptor fd = null;
909
910 try {
Jeff Sharkeybd3b9022013-08-20 15:20:04 -0700911 ICancellationSignal remoteCancellationSignal = null;
912 if (cancellationSignal != null) {
913 cancellationSignal.throwIfCanceled();
914 remoteCancellationSignal = unstableProvider.createCancellationSignal();
915 cancellationSignal.setRemote(remoteCancellationSignal);
916 }
917
Dianne Hackborn652b6d12012-05-09 18:18:40 -0700918 try {
Jeff Sharkeybd3b9022013-08-20 15:20:04 -0700919 fd = unstableProvider.openAssetFile(
920 mPackageName, uri, mode, remoteCancellationSignal);
Dianne Hackborn652b6d12012-05-09 18:18:40 -0700921 if (fd == null) {
922 // The provider will be released by the finally{} clause
923 return null;
924 }
Dianne Hackborn6ae8d182012-05-23 13:12:42 -0700925 } catch (DeadObjectException e) {
926 // The remote process has died... but we only hold an unstable
927 // reference though, so we might recover!!! Let's try!!!!
928 // This is exciting!!1!!1!!!!1
929 unstableProviderDied(unstableProvider);
930 stableProvider = acquireProvider(uri);
931 if (stableProvider == null) {
932 throw new FileNotFoundException("No content provider: " + uri);
Dianne Hackborn652b6d12012-05-09 18:18:40 -0700933 }
Jeff Sharkeybd3b9022013-08-20 15:20:04 -0700934 fd = stableProvider.openAssetFile(
935 mPackageName, uri, mode, remoteCancellationSignal);
Dianne Hackborn6ae8d182012-05-23 13:12:42 -0700936 if (fd == null) {
937 // The provider will be released by the finally{} clause
938 return null;
Dianne Hackborn652b6d12012-05-09 18:18:40 -0700939 }
Dianne Hackborn23fdaf62010-08-06 12:16:55 -0700940 }
Dianne Hackborn6ae8d182012-05-23 13:12:42 -0700941
942 if (stableProvider == null) {
943 stableProvider = acquireProvider(uri);
944 }
945 releaseUnstableProvider(unstableProvider);
946 ParcelFileDescriptor pfd = new ParcelFileDescriptorInner(
947 fd.getParcelFileDescriptor(), stableProvider);
948
949 // Success! Don't release the provider when exiting, let
950 // ParcelFileDescriptorInner do that when it is closed.
951 stableProvider = null;
952
953 return new AssetFileDescriptor(pfd, fd.getStartOffset(),
954 fd.getDeclaredLength());
955
956 } catch (RemoteException e) {
957 // Whatever, whatever, we'll go away.
958 throw new FileNotFoundException(
959 "Failed opening content provider: " + uri);
960 } catch (FileNotFoundException e) {
961 throw e;
962 } finally {
Jeff Sharkeybd3b9022013-08-20 15:20:04 -0700963 if (cancellationSignal != null) {
964 cancellationSignal.setRemote(null);
965 }
Dianne Hackborn6ae8d182012-05-23 13:12:42 -0700966 if (stableProvider != null) {
967 releaseProvider(stableProvider);
968 }
969 if (unstableProvider != null) {
970 releaseUnstableProvider(unstableProvider);
971 }
Dianne Hackborn23fdaf62010-08-06 12:16:55 -0700972 }
973 }
974 }
975 }
976
977 /**
978 * Open a raw file descriptor to access (potentially type transformed)
979 * data from a "content:" URI. This interacts with the underlying
980 * {@link ContentProvider#openTypedAssetFile} method of the provider
981 * associated with the given URI, to retrieve retrieve any appropriate
982 * data stream for the data stored there.
983 *
984 * <p>Unlike {@link #openAssetFileDescriptor}, this function only works
985 * with "content:" URIs, because content providers are the only facility
986 * with an associated MIME type to ensure that the returned data stream
987 * is of the desired type.
988 *
989 * <p>All text/* streams are encoded in UTF-8.
990 *
991 * @param uri The desired URI to open.
992 * @param mimeType The desired MIME type of the returned data. This can
John Spurlock33900182014-01-02 11:04:18 -0500993 * be a pattern such as *&#47;*, which will allow the content provider to
Dianne Hackborn23fdaf62010-08-06 12:16:55 -0700994 * select a type, though there is no way for you to determine what type
995 * it is returning.
996 * @param opts Additional provider-dependent options.
997 * @return Returns a new ParcelFileDescriptor from which you can read the
998 * data stream from the provider. Note that this may be a pipe, meaning
999 * you can't seek in it. The only seek you should do is if the
1000 * AssetFileDescriptor contains an offset, to move to that offset before
1001 * reading. You own this descriptor and are responsible for closing it when done.
1002 * @throws FileNotFoundException Throws FileNotFoundException of no
1003 * data of the desired type exists under the URI.
1004 */
Jeff Sharkeybd3b9022013-08-20 15:20:04 -07001005 public final AssetFileDescriptor openTypedAssetFileDescriptor(
1006 Uri uri, String mimeType, Bundle opts) throws FileNotFoundException {
1007 return openTypedAssetFileDescriptor(uri, mimeType, opts, null);
1008 }
1009
1010 /**
1011 * Open a raw file descriptor to access (potentially type transformed)
1012 * data from a "content:" URI. This interacts with the underlying
1013 * {@link ContentProvider#openTypedAssetFile} method of the provider
1014 * associated with the given URI, to retrieve retrieve any appropriate
1015 * data stream for the data stored there.
1016 *
1017 * <p>Unlike {@link #openAssetFileDescriptor}, this function only works
1018 * with "content:" URIs, because content providers are the only facility
1019 * with an associated MIME type to ensure that the returned data stream
1020 * is of the desired type.
1021 *
1022 * <p>All text/* streams are encoded in UTF-8.
1023 *
1024 * @param uri The desired URI to open.
1025 * @param mimeType The desired MIME type of the returned data. This can
John Spurlock33900182014-01-02 11:04:18 -05001026 * be a pattern such as *&#47;*, which will allow the content provider to
Jeff Sharkeybd3b9022013-08-20 15:20:04 -07001027 * select a type, though there is no way for you to determine what type
1028 * it is returning.
1029 * @param opts Additional provider-dependent options.
Ying Wang94366312013-08-23 22:20:03 -07001030 * @param cancellationSignal A signal to cancel the operation in progress,
1031 * or null if none. If the operation is canceled, then
1032 * {@link OperationCanceledException} will be thrown.
Jeff Sharkeybd3b9022013-08-20 15:20:04 -07001033 * @return Returns a new ParcelFileDescriptor from which you can read the
1034 * data stream from the provider. Note that this may be a pipe, meaning
1035 * you can't seek in it. The only seek you should do is if the
1036 * AssetFileDescriptor contains an offset, to move to that offset before
1037 * reading. You own this descriptor and are responsible for closing it when done.
1038 * @throws FileNotFoundException Throws FileNotFoundException of no
1039 * data of the desired type exists under the URI.
1040 */
Dianne Hackborn23fdaf62010-08-06 12:16:55 -07001041 public final AssetFileDescriptor openTypedAssetFileDescriptor(Uri uri,
Jeff Sharkeybd3b9022013-08-20 15:20:04 -07001042 String mimeType, Bundle opts, CancellationSignal cancellationSignal)
1043 throws FileNotFoundException {
Dianne Hackborn6ae8d182012-05-23 13:12:42 -07001044 IContentProvider unstableProvider = acquireUnstableProvider(uri);
1045 if (unstableProvider == null) {
1046 throw new FileNotFoundException("No content provider: " + uri);
1047 }
1048 IContentProvider stableProvider = null;
1049 AssetFileDescriptor fd = null;
1050
1051 try {
Jeff Sharkeybd3b9022013-08-20 15:20:04 -07001052 ICancellationSignal remoteCancellationSignal = null;
1053 if (cancellationSignal != null) {
1054 cancellationSignal.throwIfCanceled();
1055 remoteCancellationSignal = unstableProvider.createCancellationSignal();
1056 cancellationSignal.setRemote(remoteCancellationSignal);
1057 }
1058
Dianne Hackborn652b6d12012-05-09 18:18:40 -07001059 try {
Jeff Sharkeybd3b9022013-08-20 15:20:04 -07001060 fd = unstableProvider.openTypedAssetFile(
1061 mPackageName, uri, mimeType, opts, remoteCancellationSignal);
Dianne Hackborn652b6d12012-05-09 18:18:40 -07001062 if (fd == null) {
1063 // The provider will be released by the finally{} clause
1064 return null;
1065 }
Dianne Hackborn6ae8d182012-05-23 13:12:42 -07001066 } catch (DeadObjectException e) {
1067 // The remote process has died... but we only hold an unstable
1068 // reference though, so we might recover!!! Let's try!!!!
1069 // This is exciting!!1!!1!!!!1
1070 unstableProviderDied(unstableProvider);
1071 stableProvider = acquireProvider(uri);
1072 if (stableProvider == null) {
1073 throw new FileNotFoundException("No content provider: " + uri);
Dianne Hackborn652b6d12012-05-09 18:18:40 -07001074 }
Jeff Sharkeybd3b9022013-08-20 15:20:04 -07001075 fd = stableProvider.openTypedAssetFile(
1076 mPackageName, uri, mimeType, opts, remoteCancellationSignal);
Dianne Hackborn6ae8d182012-05-23 13:12:42 -07001077 if (fd == null) {
1078 // The provider will be released by the finally{} clause
1079 return null;
Dianne Hackborn652b6d12012-05-09 18:18:40 -07001080 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001081 }
Dianne Hackborn6ae8d182012-05-23 13:12:42 -07001082
1083 if (stableProvider == null) {
1084 stableProvider = acquireProvider(uri);
1085 }
1086 releaseUnstableProvider(unstableProvider);
1087 ParcelFileDescriptor pfd = new ParcelFileDescriptorInner(
1088 fd.getParcelFileDescriptor(), stableProvider);
1089
1090 // Success! Don't release the provider when exiting, let
1091 // ParcelFileDescriptorInner do that when it is closed.
1092 stableProvider = null;
1093
1094 return new AssetFileDescriptor(pfd, fd.getStartOffset(),
1095 fd.getDeclaredLength());
1096
1097 } catch (RemoteException e) {
1098 // Whatever, whatever, we'll go away.
1099 throw new FileNotFoundException(
1100 "Failed opening content provider: " + uri);
1101 } catch (FileNotFoundException e) {
1102 throw e;
1103 } finally {
Jeff Sharkeybd3b9022013-08-20 15:20:04 -07001104 if (cancellationSignal != null) {
1105 cancellationSignal.setRemote(null);
1106 }
Dianne Hackborn6ae8d182012-05-23 13:12:42 -07001107 if (stableProvider != null) {
1108 releaseProvider(stableProvider);
1109 }
1110 if (unstableProvider != null) {
1111 releaseUnstableProvider(unstableProvider);
1112 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001113 }
1114 }
1115
Bjorn Bringert4c87a3f2009-09-16 15:59:37 +01001116 /**
1117 * A resource identified by the {@link Resources} that contains it, and a resource id.
1118 *
1119 * @hide
1120 */
1121 public class OpenResourceIdResult {
1122 public Resources r;
1123 public int id;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001124 }
Bjorn Bringert4c87a3f2009-09-16 15:59:37 +01001125
1126 /**
1127 * Resolves an android.resource URI to a {@link Resources} and a resource id.
1128 *
1129 * @hide
1130 */
1131 public OpenResourceIdResult getResourceId(Uri uri) throws FileNotFoundException {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001132 String authority = uri.getAuthority();
1133 Resources r;
1134 if (TextUtils.isEmpty(authority)) {
1135 throw new FileNotFoundException("No authority: " + uri);
1136 } else {
1137 try {
1138 r = mContext.getPackageManager().getResourcesForApplication(authority);
1139 } catch (NameNotFoundException ex) {
1140 throw new FileNotFoundException("No package found for authority: " + uri);
1141 }
1142 }
1143 List<String> path = uri.getPathSegments();
1144 if (path == null) {
1145 throw new FileNotFoundException("No path: " + uri);
1146 }
1147 int len = path.size();
1148 int id;
1149 if (len == 1) {
1150 try {
1151 id = Integer.parseInt(path.get(0));
1152 } catch (NumberFormatException e) {
1153 throw new FileNotFoundException("Single path segment is not a resource ID: " + uri);
1154 }
1155 } else if (len == 2) {
1156 id = r.getIdentifier(path.get(1), path.get(0), authority);
1157 } else {
1158 throw new FileNotFoundException("More than two path segments: " + uri);
1159 }
1160 if (id == 0) {
1161 throw new FileNotFoundException("No resource found for: " + uri);
1162 }
1163 OpenResourceIdResult res = new OpenResourceIdResult();
1164 res.r = r;
1165 res.id = id;
1166 return res;
1167 }
Tom O'Neill0ba1cb02010-01-08 12:53:50 -08001168
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001169 /**
1170 * Inserts a row into a table at the given URL.
1171 *
1172 * If the content provider supports transactions the insertion will be atomic.
1173 *
1174 * @param url The URL of the table to insert into.
1175 * @param values The initial values for the newly inserted row. The key is the column name for
1176 * the field. Passing an empty ContentValues will create an empty row.
1177 * @return the URL of the newly created row.
1178 */
1179 public final Uri insert(Uri url, ContentValues values)
1180 {
1181 IContentProvider provider = acquireProvider(url);
1182 if (provider == null) {
1183 throw new IllegalArgumentException("Unknown URL " + url);
1184 }
1185 try {
Brad Fitzpatrickd72f7182010-02-11 17:07:51 -08001186 long startTime = SystemClock.uptimeMillis();
Dianne Hackborn35654b62013-01-14 17:38:02 -08001187 Uri createdRow = provider.insert(mPackageName, url, values);
Brad Fitzpatrickd72f7182010-02-11 17:07:51 -08001188 long durationMillis = SystemClock.uptimeMillis() - startTime;
Brad Fitzpatricka63730d2010-02-07 22:25:34 -08001189 maybeLogUpdateToEventLog(durationMillis, url, "insert", null /* where */);
1190 return createdRow;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001191 } catch (RemoteException e) {
Brad Fitzpatrick534c84c2011-01-12 14:06:30 -08001192 // Arbitrary and not worth documenting, as Activity
1193 // Manager will kill this process shortly anyway.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001194 return null;
1195 } finally {
1196 releaseProvider(provider);
1197 }
1198 }
1199
Fred Quintana89437372009-05-15 15:10:40 -07001200 /**
Fred Quintana89437372009-05-15 15:10:40 -07001201 * Applies each of the {@link ContentProviderOperation} objects and returns an array
1202 * of their results. Passes through OperationApplicationException, which may be thrown
1203 * by the call to {@link ContentProviderOperation#apply}.
1204 * If all the applications succeed then a {@link ContentProviderResult} array with the
1205 * same number of elements as the operations will be returned. It is implementation-specific
1206 * how many, if any, operations will have been successfully applied if a call to
1207 * apply results in a {@link OperationApplicationException}.
1208 * @param authority the authority of the ContentProvider to which this batch should be applied
1209 * @param operations the operations to apply
1210 * @return the results of the applications
1211 * @throws OperationApplicationException thrown if an application fails.
1212 * See {@link ContentProviderOperation#apply} for more information.
1213 * @throws RemoteException thrown if a RemoteException is encountered while attempting
1214 * to communicate with a remote provider.
1215 */
1216 public ContentProviderResult[] applyBatch(String authority,
Fred Quintana03d94902009-05-22 14:23:31 -07001217 ArrayList<ContentProviderOperation> operations)
Fred Quintana89437372009-05-15 15:10:40 -07001218 throws RemoteException, OperationApplicationException {
1219 ContentProviderClient provider = acquireContentProviderClient(authority);
Fred Quintana6a8d5332009-05-07 17:35:38 -07001220 if (provider == null) {
Fred Quintana89437372009-05-15 15:10:40 -07001221 throw new IllegalArgumentException("Unknown authority " + authority);
Fred Quintana6a8d5332009-05-07 17:35:38 -07001222 }
1223 try {
Fred Quintana89437372009-05-15 15:10:40 -07001224 return provider.applyBatch(operations);
Fred Quintana6a8d5332009-05-07 17:35:38 -07001225 } finally {
1226 provider.release();
1227 }
1228 }
1229
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001230 /**
1231 * Inserts multiple rows into a table at the given URL.
1232 *
1233 * This function make no guarantees about the atomicity of the insertions.
1234 *
1235 * @param url The URL of the table to insert into.
1236 * @param values The initial values for the newly inserted rows. The key is the column name for
1237 * the field. Passing null will create an empty row.
1238 * @return the number of newly created rows.
1239 */
1240 public final int bulkInsert(Uri url, ContentValues[] values)
1241 {
1242 IContentProvider provider = acquireProvider(url);
1243 if (provider == null) {
1244 throw new IllegalArgumentException("Unknown URL " + url);
1245 }
1246 try {
Brad Fitzpatrickd72f7182010-02-11 17:07:51 -08001247 long startTime = SystemClock.uptimeMillis();
Dianne Hackborn35654b62013-01-14 17:38:02 -08001248 int rowsCreated = provider.bulkInsert(mPackageName, url, values);
Brad Fitzpatrickd72f7182010-02-11 17:07:51 -08001249 long durationMillis = SystemClock.uptimeMillis() - startTime;
Brad Fitzpatricka63730d2010-02-07 22:25:34 -08001250 maybeLogUpdateToEventLog(durationMillis, url, "bulkinsert", null /* where */);
1251 return rowsCreated;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001252 } catch (RemoteException e) {
Brad Fitzpatrick534c84c2011-01-12 14:06:30 -08001253 // Arbitrary and not worth documenting, as Activity
1254 // Manager will kill this process shortly anyway.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001255 return 0;
1256 } finally {
1257 releaseProvider(provider);
1258 }
1259 }
1260
1261 /**
1262 * Deletes row(s) specified by a content URI.
1263 *
1264 * If the content provider supports transactions, the deletion will be atomic.
1265 *
1266 * @param url The URL of the row to delete.
1267 * @param where A filter to apply to rows before deleting, formatted as an SQL WHERE clause
1268 (excluding the WHERE itself).
1269 * @return The number of rows deleted.
1270 */
1271 public final int delete(Uri url, String where, String[] selectionArgs)
1272 {
1273 IContentProvider provider = acquireProvider(url);
1274 if (provider == null) {
1275 throw new IllegalArgumentException("Unknown URL " + url);
1276 }
1277 try {
Brad Fitzpatrickd72f7182010-02-11 17:07:51 -08001278 long startTime = SystemClock.uptimeMillis();
Dianne Hackborn35654b62013-01-14 17:38:02 -08001279 int rowsDeleted = provider.delete(mPackageName, url, where, selectionArgs);
Brad Fitzpatrickd72f7182010-02-11 17:07:51 -08001280 long durationMillis = SystemClock.uptimeMillis() - startTime;
Brad Fitzpatricka63730d2010-02-07 22:25:34 -08001281 maybeLogUpdateToEventLog(durationMillis, url, "delete", where);
1282 return rowsDeleted;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001283 } catch (RemoteException e) {
Brad Fitzpatrick534c84c2011-01-12 14:06:30 -08001284 // Arbitrary and not worth documenting, as Activity
1285 // Manager will kill this process shortly anyway.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001286 return -1;
1287 } finally {
1288 releaseProvider(provider);
1289 }
1290 }
1291
1292 /**
1293 * Update row(s) in a content URI.
1294 *
1295 * If the content provider supports transactions the update will be atomic.
1296 *
1297 * @param uri The URI to modify.
1298 * @param values The new field values. The key is the column name for the field.
1299 A null value will remove an existing field value.
Omari Stephensd2a2daa2010-03-10 18:53:54 -08001300 * @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 -08001301 (excluding the WHERE itself).
Brad Fitzpatrick534c84c2011-01-12 14:06:30 -08001302 * @return the number of rows updated.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001303 * @throws NullPointerException if uri or values are null
1304 */
1305 public final int update(Uri uri, ContentValues values, String where,
1306 String[] selectionArgs) {
1307 IContentProvider provider = acquireProvider(uri);
1308 if (provider == null) {
1309 throw new IllegalArgumentException("Unknown URI " + uri);
1310 }
1311 try {
Brad Fitzpatrickd72f7182010-02-11 17:07:51 -08001312 long startTime = SystemClock.uptimeMillis();
Dianne Hackborn35654b62013-01-14 17:38:02 -08001313 int rowsUpdated = provider.update(mPackageName, uri, values, where, selectionArgs);
Brad Fitzpatrickd72f7182010-02-11 17:07:51 -08001314 long durationMillis = SystemClock.uptimeMillis() - startTime;
Brad Fitzpatricka63730d2010-02-07 22:25:34 -08001315 maybeLogUpdateToEventLog(durationMillis, uri, "update", where);
1316 return rowsUpdated;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001317 } catch (RemoteException e) {
Brad Fitzpatrick534c84c2011-01-12 14:06:30 -08001318 // Arbitrary and not worth documenting, as Activity
1319 // Manager will kill this process shortly anyway.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001320 return -1;
1321 } finally {
1322 releaseProvider(provider);
1323 }
1324 }
1325
1326 /**
Ken Wakasaf76a50c2012-03-09 19:56:35 +09001327 * Call a provider-defined method. This can be used to implement
Brad Fitzpatrick534c84c2011-01-12 14:06:30 -08001328 * read or write interfaces which are cheaper than using a Cursor and/or
1329 * do not fit into the traditional table model.
1330 *
1331 * @param method provider-defined method name to call. Opaque to
1332 * framework, but must be non-null.
1333 * @param arg provider-defined String argument. May be null.
1334 * @param extras provider-defined Bundle argument. May be null.
1335 * @return a result Bundle, possibly null. Will be null if the ContentProvider
1336 * does not implement call.
1337 * @throws NullPointerException if uri or method is null
1338 * @throws IllegalArgumentException if uri is not known
1339 */
1340 public final Bundle call(Uri uri, String method, String arg, Bundle extras) {
1341 if (uri == null) {
1342 throw new NullPointerException("uri == null");
1343 }
1344 if (method == null) {
1345 throw new NullPointerException("method == null");
1346 }
1347 IContentProvider provider = acquireProvider(uri);
1348 if (provider == null) {
1349 throw new IllegalArgumentException("Unknown URI " + uri);
1350 }
1351 try {
Dianne Hackborn35654b62013-01-14 17:38:02 -08001352 return provider.call(mPackageName, method, arg, extras);
Brad Fitzpatrick534c84c2011-01-12 14:06:30 -08001353 } catch (RemoteException e) {
1354 // Arbitrary and not worth documenting, as Activity
1355 // Manager will kill this process shortly anyway.
1356 return null;
1357 } finally {
1358 releaseProvider(provider);
1359 }
1360 }
1361
1362 /**
Dianne Hackborncca1f0e2010-09-26 18:34:53 -07001363 * Returns the content provider for the given content URI.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001364 *
1365 * @param uri The URI to a content provider
1366 * @return The ContentProvider for the given URI, or null if no content provider is found.
1367 * @hide
1368 */
Dianne Hackborncca1f0e2010-09-26 18:34:53 -07001369 public final IContentProvider acquireProvider(Uri uri) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001370 if (!SCHEME_CONTENT.equals(uri.getScheme())) {
1371 return null;
1372 }
Yury Zhauniarovichf9c51762012-05-12 18:39:25 +02001373 final String auth = uri.getAuthority();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001374 if (auth != null) {
Yury Zhauniarovichf9c51762012-05-12 18:39:25 +02001375 return acquireProvider(mContext, auth);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001376 }
1377 return null;
1378 }
1379
1380 /**
Dianne Hackborncca1f0e2010-09-26 18:34:53 -07001381 * Returns the content provider for the given content URI if the process
1382 * already has a reference on it.
1383 *
1384 * @param uri The URI to a content provider
1385 * @return The ContentProvider for the given URI, or null if no content provider is found.
1386 * @hide
1387 */
1388 public final IContentProvider acquireExistingProvider(Uri uri) {
1389 if (!SCHEME_CONTENT.equals(uri.getScheme())) {
1390 return null;
1391 }
Yury Zhauniarovichf9c51762012-05-12 18:39:25 +02001392 final String auth = uri.getAuthority();
Dianne Hackborncca1f0e2010-09-26 18:34:53 -07001393 if (auth != null) {
Yury Zhauniarovichf9c51762012-05-12 18:39:25 +02001394 return acquireExistingProvider(mContext, auth);
Dianne Hackborncca1f0e2010-09-26 18:34:53 -07001395 }
1396 return null;
1397 }
1398
1399 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001400 * @hide
1401 */
1402 public final IContentProvider acquireProvider(String name) {
Brad Fitzpatrick1877d012010-03-04 17:48:13 -08001403 if (name == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001404 return null;
1405 }
1406 return acquireProvider(mContext, name);
1407 }
1408
1409 /**
Dianne Hackborn652b6d12012-05-09 18:18:40 -07001410 * Returns the content provider for the given content URI.
1411 *
1412 * @param uri The URI to a content provider
1413 * @return The ContentProvider for the given URI, or null if no content provider is found.
1414 * @hide
1415 */
1416 public final IContentProvider acquireUnstableProvider(Uri uri) {
1417 if (!SCHEME_CONTENT.equals(uri.getScheme())) {
1418 return null;
1419 }
1420 String auth = uri.getAuthority();
1421 if (auth != null) {
1422 return acquireUnstableProvider(mContext, uri.getAuthority());
1423 }
1424 return null;
1425 }
1426
1427 /**
1428 * @hide
1429 */
1430 public final IContentProvider acquireUnstableProvider(String name) {
1431 if (name == null) {
1432 return null;
1433 }
Dianne Hackborn6ae8d182012-05-23 13:12:42 -07001434 return acquireUnstableProvider(mContext, name);
Dianne Hackborn652b6d12012-05-09 18:18:40 -07001435 }
1436
1437 /**
Fred Quintana718d8a22009-04-29 17:53:20 -07001438 * Returns a {@link ContentProviderClient} that is associated with the {@link ContentProvider}
1439 * that services the content at uri, starting the provider if necessary. Returns
1440 * null if there is no provider associated wih the uri. The caller must indicate that they are
1441 * done with the provider by calling {@link ContentProviderClient#release} which will allow
1442 * the system to release the provider it it determines that there is no other reason for
1443 * keeping it active.
1444 * @param uri specifies which provider should be acquired
1445 * @return a {@link ContentProviderClient} that is associated with the {@link ContentProvider}
1446 * that services the content at uri or null if there isn't one.
1447 */
1448 public final ContentProviderClient acquireContentProviderClient(Uri uri) {
1449 IContentProvider provider = acquireProvider(uri);
1450 if (provider != null) {
Dianne Hackborn652b6d12012-05-09 18:18:40 -07001451 return new ContentProviderClient(this, provider, true);
Fred Quintana718d8a22009-04-29 17:53:20 -07001452 }
1453
1454 return null;
1455 }
1456
1457 /**
1458 * Returns a {@link ContentProviderClient} that is associated with the {@link ContentProvider}
1459 * with the authority of name, starting the provider if necessary. Returns
1460 * null if there is no provider associated wih the uri. The caller must indicate that they are
1461 * done with the provider by calling {@link ContentProviderClient#release} which will allow
1462 * the system to release the provider it it determines that there is no other reason for
1463 * keeping it active.
1464 * @param name specifies which provider should be acquired
1465 * @return a {@link ContentProviderClient} that is associated with the {@link ContentProvider}
1466 * with the authority of name or null if there isn't one.
1467 */
1468 public final ContentProviderClient acquireContentProviderClient(String name) {
1469 IContentProvider provider = acquireProvider(name);
1470 if (provider != null) {
Dianne Hackborn652b6d12012-05-09 18:18:40 -07001471 return new ContentProviderClient(this, provider, true);
1472 }
1473
1474 return null;
1475 }
1476
1477 /**
1478 * Like {@link #acquireContentProviderClient(Uri)}, but for use when you do
1479 * not trust the stability of the target content provider. This turns off
1480 * the mechanism in the platform clean up processes that are dependent on
1481 * a content provider if that content provider's process goes away. Normally
1482 * you can safely assume that once you have acquired a provider, you can freely
1483 * use it as needed and it won't disappear, even if your process is in the
1484 * background. If using this method, you need to take care to deal with any
1485 * failures when communicating with the provider, and be sure to close it
Dianne Hackborn6ae8d182012-05-23 13:12:42 -07001486 * so that it can be re-opened later. In particular, catching a
1487 * {@link android.os.DeadObjectException} from the calls there will let you
1488 * know that the content provider has gone away; at that point the current
1489 * ContentProviderClient object is invalid, and you should release it. You
1490 * can acquire a new one if you would like to try to restart the provider
1491 * and perform new operations on it.
Dianne Hackborn652b6d12012-05-09 18:18:40 -07001492 */
1493 public final ContentProviderClient acquireUnstableContentProviderClient(Uri uri) {
Dianne Hackborn6ae8d182012-05-23 13:12:42 -07001494 IContentProvider provider = acquireUnstableProvider(uri);
Dianne Hackborn652b6d12012-05-09 18:18:40 -07001495 if (provider != null) {
1496 return new ContentProviderClient(this, provider, false);
1497 }
1498
1499 return null;
1500 }
1501
1502 /**
1503 * Like {@link #acquireContentProviderClient(String)}, but for use when you do
1504 * not trust the stability of the target content provider. This turns off
1505 * the mechanism in the platform clean up processes that are dependent on
1506 * a content provider if that content provider's process goes away. Normally
1507 * you can safely assume that once you have acquired a provider, you can freely
1508 * use it as needed and it won't disappear, even if your process is in the
1509 * background. If using this method, you need to take care to deal with any
1510 * failures when communicating with the provider, and be sure to close it
Dianne Hackborn6ae8d182012-05-23 13:12:42 -07001511 * so that it can be re-opened later. In particular, catching a
1512 * {@link android.os.DeadObjectException} from the calls there will let you
1513 * know that the content provider has gone away; at that point the current
1514 * ContentProviderClient object is invalid, and you should release it. You
1515 * can acquire a new one if you would like to try to restart the provider
1516 * and perform new operations on it.
Dianne Hackborn652b6d12012-05-09 18:18:40 -07001517 */
1518 public final ContentProviderClient acquireUnstableContentProviderClient(String name) {
Dianne Hackborn6ae8d182012-05-23 13:12:42 -07001519 IContentProvider provider = acquireUnstableProvider(name);
Dianne Hackborn652b6d12012-05-09 18:18:40 -07001520 if (provider != null) {
1521 return new ContentProviderClient(this, provider, false);
Fred Quintana718d8a22009-04-29 17:53:20 -07001522 }
1523
1524 return null;
1525 }
1526
1527 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001528 * Register an observer class that gets callbacks when data identified by a
1529 * given content URI changes.
1530 *
1531 * @param uri The URI to watch for changes. This can be a specific row URI, or a base URI
1532 * for a whole class of content.
1533 * @param notifyForDescendents If <code>true</code> changes to URIs beginning with <code>uri</code>
1534 * will also cause notifications to be sent. If <code>false</code> only changes to the exact URI
1535 * specified by <em>uri</em> will cause notifications to be sent. If true, than any URI values
1536 * at or below the specified URI will also trigger a match.
1537 * @param observer The object that receives callbacks when changes occur.
1538 * @see #unregisterContentObserver
1539 */
1540 public final void registerContentObserver(Uri uri, boolean notifyForDescendents,
1541 ContentObserver observer)
1542 {
Christopher Tateafccaa82012-10-03 17:41:51 -07001543 registerContentObserver(uri, notifyForDescendents, observer, UserHandle.myUserId());
Christopher Tate16aa9732012-09-17 16:23:44 -07001544 }
1545
1546 /** @hide - designated user version */
1547 public final void registerContentObserver(Uri uri, boolean notifyForDescendents,
1548 ContentObserver observer, int userHandle)
1549 {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001550 try {
Dianne Hackborn231cc602009-04-27 17:10:36 -07001551 getContentService().registerContentObserver(uri, notifyForDescendents,
Christopher Tate16aa9732012-09-17 16:23:44 -07001552 observer.getContentObserver(), userHandle);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001553 } catch (RemoteException e) {
1554 }
1555 }
1556
1557 /**
1558 * Unregisters a change observer.
1559 *
1560 * @param observer The previously registered observer that is no longer needed.
1561 * @see #registerContentObserver
1562 */
1563 public final void unregisterContentObserver(ContentObserver observer) {
1564 try {
1565 IContentObserver contentObserver = observer.releaseContentObserver();
1566 if (contentObserver != null) {
Dianne Hackborn231cc602009-04-27 17:10:36 -07001567 getContentService().unregisterContentObserver(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001568 contentObserver);
1569 }
1570 } catch (RemoteException e) {
1571 }
1572 }
1573
1574 /**
Steve Pomeroyd7a1aad2012-01-18 16:15:59 -05001575 * Notify registered observers that a row was updated and attempt to sync changes
1576 * to the network.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001577 * To register, call {@link #registerContentObserver(android.net.Uri , boolean, android.database.ContentObserver) registerContentObserver()}.
1578 * By default, CursorAdapter objects will get this notification.
1579 *
Jeff Brown86de0592012-01-23 13:01:18 -08001580 * @param uri The uri of the content that was changed.
1581 * @param observer The observer that originated the change, may be <code>null</null>.
1582 * The observer that originated the change will only receive the notification if it
1583 * has requested to receive self-change notifications by implementing
1584 * {@link ContentObserver#deliverSelfNotifications()} to return true.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001585 */
1586 public void notifyChange(Uri uri, ContentObserver observer) {
1587 notifyChange(uri, observer, true /* sync to network */);
1588 }
1589
1590 /**
1591 * Notify registered observers that a row was updated.
1592 * To register, call {@link #registerContentObserver(android.net.Uri , boolean, android.database.ContentObserver) registerContentObserver()}.
1593 * By default, CursorAdapter objects will get this notification.
Steve Pomeroyd7a1aad2012-01-18 16:15:59 -05001594 * If syncToNetwork is true, this will attempt to schedule a local sync using the sync
1595 * adapter that's registered for the authority of the provided uri. No account will be
1596 * passed to the sync adapter, so all matching accounts will be synchronized.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001597 *
Jeff Brown86de0592012-01-23 13:01:18 -08001598 * @param uri The uri of the content that was changed.
1599 * @param observer The observer that originated the change, may be <code>null</null>.
1600 * The observer that originated the change will only receive the notification if it
1601 * has requested to receive self-change notifications by implementing
1602 * {@link ContentObserver#deliverSelfNotifications()} to return true.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001603 * @param syncToNetwork If true, attempt to sync the change to the network.
Steve Pomeroyd7a1aad2012-01-18 16:15:59 -05001604 * @see #requestSync(android.accounts.Account, String, android.os.Bundle)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001605 */
1606 public void notifyChange(Uri uri, ContentObserver observer, boolean syncToNetwork) {
Christopher Tateb7564452012-09-19 16:21:18 -07001607 notifyChange(uri, observer, syncToNetwork, UserHandle.getCallingUserId());
Christopher Tate16aa9732012-09-17 16:23:44 -07001608 }
1609
1610 /**
1611 * Notify registered observers within the designated user(s) that a row was updated.
1612 *
1613 * @hide
1614 */
1615 public void notifyChange(Uri uri, ContentObserver observer, boolean syncToNetwork,
1616 int userHandle) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001617 try {
Dianne Hackborn231cc602009-04-27 17:10:36 -07001618 getContentService().notifyChange(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001619 uri, observer == null ? null : observer.getContentObserver(),
Christopher Tate16aa9732012-09-17 16:23:44 -07001620 observer != null && observer.deliverSelfNotifications(), syncToNetwork,
1621 userHandle);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001622 } catch (RemoteException e) {
1623 }
1624 }
1625
1626 /**
Jeff Sharkeyadef88a2013-10-15 13:54:44 -07001627 * Take a persistable URI permission grant that has been offered. Once
Jeff Sharkeye66c1772013-09-20 14:30:59 -07001628 * taken, the permission grant will be remembered across device reboots.
Jeff Sharkeyadef88a2013-10-15 13:54:44 -07001629 * Only URI permissions granted with
Jeff Sharkeye66c1772013-09-20 14:30:59 -07001630 * {@link Intent#FLAG_GRANT_PERSISTABLE_URI_PERMISSION} can be persisted. If
1631 * the grant has already been persisted, taking it again will touch
1632 * {@link UriPermission#getPersistedTime()}.
Jeff Sharkey08da7a12013-08-11 20:53:18 -07001633 *
Jeff Sharkeye66c1772013-09-20 14:30:59 -07001634 * @see #getPersistedUriPermissions()
Jeff Sharkey08da7a12013-08-11 20:53:18 -07001635 */
Jeff Sharkeye66c1772013-09-20 14:30:59 -07001636 public void takePersistableUriPermission(Uri uri, int modeFlags) {
Jeff Sharkey08da7a12013-08-11 20:53:18 -07001637 try {
Jeff Sharkeye66c1772013-09-20 14:30:59 -07001638 ActivityManagerNative.getDefault().takePersistableUriPermission(uri, modeFlags);
Jeff Sharkey08da7a12013-08-11 20:53:18 -07001639 } catch (RemoteException e) {
Jeff Sharkey08da7a12013-08-11 20:53:18 -07001640 }
1641 }
1642
1643 /**
Jeff Sharkeyadef88a2013-10-15 13:54:44 -07001644 * Relinquish a persisted URI permission grant. The URI must have been
Jeff Sharkeye66c1772013-09-20 14:30:59 -07001645 * previously made persistent with
1646 * {@link #takePersistableUriPermission(Uri, int)}. Any non-persistent
1647 * grants to the calling package will remain intact.
Jeff Sharkey08da7a12013-08-11 20:53:18 -07001648 *
Jeff Sharkeye66c1772013-09-20 14:30:59 -07001649 * @see #getPersistedUriPermissions()
Jeff Sharkey08da7a12013-08-11 20:53:18 -07001650 */
Jeff Sharkeye66c1772013-09-20 14:30:59 -07001651 public void releasePersistableUriPermission(Uri uri, int modeFlags) {
Jeff Sharkey08da7a12013-08-11 20:53:18 -07001652 try {
Jeff Sharkeye66c1772013-09-20 14:30:59 -07001653 ActivityManagerNative.getDefault().releasePersistableUriPermission(uri, modeFlags);
Jeff Sharkey08da7a12013-08-11 20:53:18 -07001654 } catch (RemoteException e) {
Jeff Sharkeye66c1772013-09-20 14:30:59 -07001655 }
1656 }
1657
1658 /**
Jeff Sharkeyadef88a2013-10-15 13:54:44 -07001659 * Return list of all URI permission grants that have been persisted by the
Jeff Sharkeybcaac0a2013-10-09 14:21:08 -07001660 * calling app. That is, the returned permissions have been granted
1661 * <em>to</em> the calling app. Only persistable grants taken with
Jeff Sharkeye66c1772013-09-20 14:30:59 -07001662 * {@link #takePersistableUriPermission(Uri, int)} are returned.
1663 *
1664 * @see #takePersistableUriPermission(Uri, int)
1665 * @see #releasePersistableUriPermission(Uri, int)
1666 */
1667 public List<UriPermission> getPersistedUriPermissions() {
1668 try {
Jeff Sharkeybcaac0a2013-10-09 14:21:08 -07001669 return ActivityManagerNative.getDefault()
1670 .getPersistedUriPermissions(mPackageName, true).getList();
1671 } catch (RemoteException e) {
1672 throw new RuntimeException("Activity manager has died", e);
1673 }
1674 }
1675
1676 /**
Jeff Sharkeyadef88a2013-10-15 13:54:44 -07001677 * Return list of all persisted URI permission grants that are hosted by the
Jeff Sharkeybcaac0a2013-10-09 14:21:08 -07001678 * calling app. That is, the returned permissions have been granted
1679 * <em>from</em> the calling app. Only grants taken with
1680 * {@link #takePersistableUriPermission(Uri, int)} are returned.
1681 */
1682 public List<UriPermission> getOutgoingPersistedUriPermissions() {
1683 try {
1684 return ActivityManagerNative.getDefault()
1685 .getPersistedUriPermissions(mPackageName, false).getList();
Jeff Sharkeye66c1772013-09-20 14:30:59 -07001686 } catch (RemoteException e) {
1687 throw new RuntimeException("Activity manager has died", e);
Jeff Sharkey08da7a12013-08-11 20:53:18 -07001688 }
1689 }
1690
1691 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001692 * Start an asynchronous sync operation. If you want to monitor the progress
1693 * of the sync you may register a SyncObserver. Only values of the following
1694 * types may be used in the extras bundle:
1695 * <ul>
1696 * <li>Integer</li>
1697 * <li>Long</li>
1698 * <li>Boolean</li>
1699 * <li>Float</li>
1700 * <li>Double</li>
1701 * <li>String</li>
Matthew Williamsfa774182013-06-18 15:44:11 -07001702 * <li>Account</li>
1703 * <li>null</li>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001704 * </ul>
1705 *
1706 * @param uri the uri of the provider to sync or null to sync all providers.
1707 * @param extras any extras to pass to the SyncAdapter.
Fred Quintanaac9385e2009-06-22 18:00:59 -07001708 * @deprecated instead use
1709 * {@link #requestSync(android.accounts.Account, String, android.os.Bundle)}
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001710 */
Dianne Hackborn4a51c202009-08-21 15:14:02 -07001711 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001712 public void startSync(Uri uri, Bundle extras) {
Fred Quintanaac9385e2009-06-22 18:00:59 -07001713 Account account = null;
1714 if (extras != null) {
1715 String accountName = extras.getString(SYNC_EXTRAS_ACCOUNT);
1716 if (!TextUtils.isEmpty(accountName)) {
Costin Manolache3348f142009-09-29 18:58:36 -07001717 account = new Account(accountName, "com.google");
Fred Quintanaac9385e2009-06-22 18:00:59 -07001718 }
1719 extras.remove(SYNC_EXTRAS_ACCOUNT);
1720 }
1721 requestSync(account, uri != null ? uri.getAuthority() : null, extras);
1722 }
1723
1724 /**
1725 * Start an asynchronous sync operation. If you want to monitor the progress
1726 * of the sync you may register a SyncObserver. Only values of the following
1727 * types may be used in the extras bundle:
1728 * <ul>
1729 * <li>Integer</li>
1730 * <li>Long</li>
1731 * <li>Boolean</li>
1732 * <li>Float</li>
1733 * <li>Double</li>
1734 * <li>String</li>
Matthew Williamsfa774182013-06-18 15:44:11 -07001735 * <li>Account</li>
1736 * <li>null</li>
Fred Quintanaac9385e2009-06-22 18:00:59 -07001737 * </ul>
1738 *
1739 * @param account which account should be synced
1740 * @param authority which authority should be synced
1741 * @param extras any extras to pass to the SyncAdapter.
1742 */
1743 public static void requestSync(Account account, String authority, Bundle extras) {
Matthew Williamsd8abd6a2013-09-09 14:35:27 -07001744 if (extras == null) {
1745 throw new IllegalArgumentException("Must specify extras.");
1746 }
Matthew Williamsfa774182013-06-18 15:44:11 -07001747 SyncRequest request =
1748 new SyncRequest.Builder()
1749 .setSyncAdapter(account, authority)
1750 .setExtras(extras)
Nick Kralevich69002ae2013-10-19 08:43:08 -07001751 .syncOnce() // Immediate sync.
Matthew Williamsfa774182013-06-18 15:44:11 -07001752 .build();
1753 requestSync(request);
1754 }
1755
1756 /**
1757 * Register a sync with the SyncManager. These requests are built using the
1758 * {@link SyncRequest.Builder}.
1759 */
1760 public static void requestSync(SyncRequest request) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001761 try {
Matthew Williamsfa774182013-06-18 15:44:11 -07001762 getContentService().sync(request);
1763 } catch(RemoteException e) {
1764 // Shouldn't happen.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001765 }
1766 }
1767
1768 /**
1769 * Check that only values of the following types are in the Bundle:
1770 * <ul>
1771 * <li>Integer</li>
1772 * <li>Long</li>
1773 * <li>Boolean</li>
1774 * <li>Float</li>
1775 * <li>Double</li>
1776 * <li>String</li>
Fred Quintanad9d2f112009-04-23 13:36:27 -07001777 * <li>Account</li>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001778 * <li>null</li>
1779 * </ul>
1780 * @param extras the Bundle to check
1781 */
1782 public static void validateSyncExtrasBundle(Bundle extras) {
1783 try {
1784 for (String key : extras.keySet()) {
1785 Object value = extras.get(key);
1786 if (value == null) continue;
1787 if (value instanceof Long) continue;
1788 if (value instanceof Integer) continue;
1789 if (value instanceof Boolean) continue;
1790 if (value instanceof Float) continue;
1791 if (value instanceof Double) continue;
1792 if (value instanceof String) continue;
Fred Quintanad9d2f112009-04-23 13:36:27 -07001793 if (value instanceof Account) continue;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001794 throw new IllegalArgumentException("unexpected value type: "
1795 + value.getClass().getName());
1796 }
1797 } catch (IllegalArgumentException e) {
1798 throw e;
1799 } catch (RuntimeException exc) {
1800 throw new IllegalArgumentException("error unparceling Bundle", exc);
1801 }
1802 }
1803
Fred Quintanaac9385e2009-06-22 18:00:59 -07001804 /**
1805 * Cancel any active or pending syncs that match the Uri. If the uri is null then
1806 * all syncs will be canceled.
1807 *
1808 * @param uri the uri of the provider to sync or null to sync all providers.
1809 * @deprecated instead use {@link #cancelSync(android.accounts.Account, String)}
1810 */
Dianne Hackborn4a51c202009-08-21 15:14:02 -07001811 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001812 public void cancelSync(Uri uri) {
Fred Quintanaac9385e2009-06-22 18:00:59 -07001813 cancelSync(null /* all accounts */, uri != null ? uri.getAuthority() : null);
1814 }
1815
1816 /**
1817 * Cancel any active or pending syncs that match account and authority. The account and
1818 * authority can each independently be set to null, which means that syncs with any account
1819 * or authority, respectively, will match.
1820 *
1821 * @param account filters the syncs that match by this account
1822 * @param authority filters the syncs that match by this authority
1823 */
1824 public static void cancelSync(Account account, String authority) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001825 try {
Matthew Williams56dbf8f2013-07-26 12:56:39 -07001826 getContentService().cancelSync(account, authority, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001827 } catch (RemoteException e) {
1828 }
1829 }
1830
Fred Quintanaac9385e2009-06-22 18:00:59 -07001831 /**
Matthew Williams56dbf8f2013-07-26 12:56:39 -07001832 * Cancel any active or pending syncs that are running on this service.
1833 *
1834 * @param cname the service for which to cancel all active/pending operations.
1835 */
1836 public static void cancelSync(ComponentName cname) {
1837 try {
1838 getContentService().cancelSync(null, null, cname);
1839 } catch (RemoteException e) {
1840
1841 }
1842 }
1843
1844 /**
Fred Quintanaac9385e2009-06-22 18:00:59 -07001845 * Get information about the SyncAdapters that are known to the system.
1846 * @return an array of SyncAdapters that have registered with the system
1847 */
1848 public static SyncAdapterType[] getSyncAdapterTypes() {
1849 try {
1850 return getContentService().getSyncAdapterTypes();
1851 } catch (RemoteException e) {
1852 throw new RuntimeException("the ContentService should always be reachable", e);
1853 }
1854 }
1855
1856 /**
1857 * Check if the provider should be synced when a network tickle is received
Nicolas Falliere9530e3a2012-06-18 17:21:06 -07001858 * <p>This method requires the caller to hold the permission
1859 * {@link android.Manifest.permission#READ_SYNC_SETTINGS}.
Fred Quintanaac9385e2009-06-22 18:00:59 -07001860 *
1861 * @param account the account whose setting we are querying
1862 * @param authority the provider whose setting we are querying
1863 * @return true if the provider should be synced when a network tickle is received
1864 */
1865 public static boolean getSyncAutomatically(Account account, String authority) {
1866 try {
1867 return getContentService().getSyncAutomatically(account, authority);
1868 } catch (RemoteException e) {
1869 throw new RuntimeException("the ContentService should always be reachable", e);
1870 }
1871 }
1872
1873 /**
1874 * Set whether or not the provider is synced when it receives a network tickle.
Nicolas Falliere9530e3a2012-06-18 17:21:06 -07001875 * <p>This method requires the caller to hold the permission
1876 * {@link android.Manifest.permission#WRITE_SYNC_SETTINGS}.
Fred Quintanaac9385e2009-06-22 18:00:59 -07001877 *
1878 * @param account the account whose setting we are querying
1879 * @param authority the provider whose behavior is being controlled
1880 * @param sync true if the provider should be synced when tickles are received for it
1881 */
1882 public static void setSyncAutomatically(Account account, String authority, boolean sync) {
1883 try {
1884 getContentService().setSyncAutomatically(account, authority, sync);
1885 } catch (RemoteException e) {
1886 // exception ignored; if this is thrown then it means the runtime is in the midst of
1887 // being restarted
1888 }
1889 }
1890
1891 /**
Fred Quintanac5d1c6d2010-01-27 12:17:49 -08001892 * Specifies that a sync should be requested with the specified the account, authority,
1893 * and extras at the given frequency. If there is already another periodic sync scheduled
1894 * with the account, authority and extras then a new periodic sync won't be added, instead
1895 * the frequency of the previous one will be updated.
1896 * <p>
1897 * These periodic syncs honor the "syncAutomatically" and "masterSyncAutomatically" settings.
1898 * Although these sync are scheduled at the specified frequency, it may take longer for it to
1899 * actually be started if other syncs are ahead of it in the sync operation queue. This means
1900 * that the actual start time may drift.
Fred Quintana53bd2522010-02-05 15:28:12 -08001901 * <p>
1902 * Periodic syncs are not allowed to have any of {@link #SYNC_EXTRAS_DO_NOT_RETRY},
1903 * {@link #SYNC_EXTRAS_IGNORE_BACKOFF}, {@link #SYNC_EXTRAS_IGNORE_SETTINGS},
1904 * {@link #SYNC_EXTRAS_INITIALIZE}, {@link #SYNC_EXTRAS_FORCE},
1905 * {@link #SYNC_EXTRAS_EXPEDITED}, {@link #SYNC_EXTRAS_MANUAL} set to true.
1906 * If any are supplied then an {@link IllegalArgumentException} will be thrown.
Fred Quintanac5d1c6d2010-01-27 12:17:49 -08001907 *
Nicolas Falliere9530e3a2012-06-18 17:21:06 -07001908 * <p>This method requires the caller to hold the permission
1909 * {@link android.Manifest.permission#WRITE_SYNC_SETTINGS}.
Matthew Williams56dbf8f2013-07-26 12:56:39 -07001910 * <p>The bundle for a periodic sync can be queried by applications with the correct
1911 * permissions using
1912 * {@link ContentResolver#getPeriodicSyncs(Account account, String provider)}, so no
1913 * sensitive data should be transferred here.
Nicolas Falliere9530e3a2012-06-18 17:21:06 -07001914 *
Fred Quintanac5d1c6d2010-01-27 12:17:49 -08001915 * @param account the account to specify in the sync
1916 * @param authority the provider to specify in the sync request
1917 * @param extras extra parameters to go along with the sync request
1918 * @param pollFrequency how frequently the sync should be performed, in seconds.
Fred Quintana53bd2522010-02-05 15:28:12 -08001919 * @throws IllegalArgumentException if an illegal extra was set or if any of the parameters
1920 * are null.
Fred Quintanac5d1c6d2010-01-27 12:17:49 -08001921 */
1922 public static void addPeriodicSync(Account account, String authority, Bundle extras,
1923 long pollFrequency) {
1924 validateSyncExtrasBundle(extras);
Fred Quintana53bd2522010-02-05 15:28:12 -08001925 if (extras.getBoolean(SYNC_EXTRAS_MANUAL, false)
1926 || extras.getBoolean(SYNC_EXTRAS_DO_NOT_RETRY, false)
1927 || extras.getBoolean(SYNC_EXTRAS_IGNORE_BACKOFF, false)
1928 || extras.getBoolean(SYNC_EXTRAS_IGNORE_SETTINGS, false)
1929 || extras.getBoolean(SYNC_EXTRAS_INITIALIZE, false)
1930 || extras.getBoolean(SYNC_EXTRAS_FORCE, false)
1931 || extras.getBoolean(SYNC_EXTRAS_EXPEDITED, false)) {
1932 throw new IllegalArgumentException("illegal extras were set");
1933 }
Fred Quintanac5d1c6d2010-01-27 12:17:49 -08001934 try {
Matthew Williamsfa774182013-06-18 15:44:11 -07001935 getContentService().addPeriodicSync(account, authority, extras, pollFrequency);
Fred Quintanac5d1c6d2010-01-27 12:17:49 -08001936 } catch (RemoteException e) {
1937 // exception ignored; if this is thrown then it means the runtime is in the midst of
1938 // being restarted
1939 }
1940 }
1941
1942 /**
Matthew Williams56dbf8f2013-07-26 12:56:39 -07001943 * {@hide}
1944 * Helper function to throw an <code>IllegalArgumentException</code> if any illegal
1945 * extras were set for a periodic sync.
1946 *
1947 * @param extras bundle to validate.
1948 */
1949 public static boolean invalidPeriodicExtras(Bundle extras) {
1950 if (extras.getBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, false)
1951 || extras.getBoolean(ContentResolver.SYNC_EXTRAS_DO_NOT_RETRY, false)
1952 || extras.getBoolean(ContentResolver.SYNC_EXTRAS_IGNORE_BACKOFF, false)
1953 || extras.getBoolean(ContentResolver.SYNC_EXTRAS_IGNORE_SETTINGS, false)
1954 || extras.getBoolean(ContentResolver.SYNC_EXTRAS_INITIALIZE, false)
1955 || extras.getBoolean(ContentResolver.SYNC_EXTRAS_FORCE, false)
1956 || extras.getBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, false)) {
1957 return true;
1958 }
1959 return false;
1960 }
1961
1962 /**
Fred Quintanac5d1c6d2010-01-27 12:17:49 -08001963 * Remove a periodic sync. Has no affect if account, authority and extras don't match
1964 * an existing periodic sync.
Nicolas Falliere9530e3a2012-06-18 17:21:06 -07001965 * <p>This method requires the caller to hold the permission
1966 * {@link android.Manifest.permission#WRITE_SYNC_SETTINGS}.
Fred Quintanac5d1c6d2010-01-27 12:17:49 -08001967 *
1968 * @param account the account of the periodic sync to remove
1969 * @param authority the provider of the periodic sync to remove
1970 * @param extras the extras of the periodic sync to remove
1971 */
1972 public static void removePeriodicSync(Account account, String authority, Bundle extras) {
1973 validateSyncExtrasBundle(extras);
1974 try {
1975 getContentService().removePeriodicSync(account, authority, extras);
1976 } catch (RemoteException e) {
1977 throw new RuntimeException("the ContentService should always be reachable", e);
1978 }
1979 }
1980
1981 /**
Matthew Williams56dbf8f2013-07-26 12:56:39 -07001982 * Remove the specified sync. This will cancel any pending or active syncs. If the request is
1983 * for a periodic sync, this call will remove any future occurrences.
1984 * <p>If a periodic sync is specified, the caller must hold the permission
1985 * {@link android.Manifest.permission#WRITE_SYNC_SETTINGS}. If this SyncRequest targets a
1986 * SyncService adapter,the calling application must be signed with the same certificate as the
1987 * adapter.
1988 *</p>It is possible to cancel a sync using a SyncRequest object that is not the same object
1989 * with which you requested the sync. Do so by building a SyncRequest with the same
Matthew Williamsfa774182013-06-18 15:44:11 -07001990 * service/adapter, frequency, <b>and</b> extras bundle.
1991 *
1992 * @param request SyncRequest object containing information about sync to cancel.
1993 */
1994 public static void cancelSync(SyncRequest request) {
Matthew Williams56dbf8f2013-07-26 12:56:39 -07001995 if (request == null) {
1996 throw new IllegalArgumentException("request cannot be null");
1997 }
1998 try {
1999 getContentService().cancelRequest(request);
2000 } catch (RemoteException e) {
2001 // exception ignored; if this is thrown then it means the runtime is in the midst of
2002 // being restarted
2003 }
Matthew Williamsfa774182013-06-18 15:44:11 -07002004 }
2005
2006 /**
Fred Quintanac5d1c6d2010-01-27 12:17:49 -08002007 * Get the list of information about the periodic syncs for the given account and authority.
Nicolas Falliere9530e3a2012-06-18 17:21:06 -07002008 * <p>This method requires the caller to hold the permission
2009 * {@link android.Manifest.permission#READ_SYNC_SETTINGS}.
Fred Quintanac5d1c6d2010-01-27 12:17:49 -08002010 *
2011 * @param account the account whose periodic syncs we are querying
2012 * @param authority the provider whose periodic syncs we are querying
2013 * @return a list of PeriodicSync objects. This list may be empty but will never be null.
2014 */
2015 public static List<PeriodicSync> getPeriodicSyncs(Account account, String authority) {
2016 try {
Matthew Williams56dbf8f2013-07-26 12:56:39 -07002017 return getContentService().getPeriodicSyncs(account, authority, null);
2018 } catch (RemoteException e) {
2019 throw new RuntimeException("the ContentService should always be reachable", e);
2020 }
2021 }
2022
2023 /**
2024 * Return periodic syncs associated with the provided component.
2025 * <p>The calling application must be signed with the same certificate as the target component,
2026 * otherwise this call will fail.
2027 */
2028 public static List<PeriodicSync> getPeriodicSyncs(ComponentName cname) {
2029 if (cname == null) {
2030 throw new IllegalArgumentException("Component must not be null");
2031 }
2032 try {
2033 return getContentService().getPeriodicSyncs(null, null, cname);
Fred Quintanac5d1c6d2010-01-27 12:17:49 -08002034 } catch (RemoteException e) {
2035 throw new RuntimeException("the ContentService should always be reachable", e);
2036 }
2037 }
2038
2039 /**
Fred Quintana5e787c42009-08-16 23:13:53 -07002040 * Check if this account/provider is syncable.
Nicolas Falliere9530e3a2012-06-18 17:21:06 -07002041 * <p>This method requires the caller to hold the permission
2042 * {@link android.Manifest.permission#READ_SYNC_SETTINGS}.
Fred Quintana5e787c42009-08-16 23:13:53 -07002043 * @return >0 if it is syncable, 0 if not, and <0 if the state isn't known yet.
2044 */
Jim Miller20ea6ce2009-08-17 15:47:14 -07002045 public static int getIsSyncable(Account account, String authority) {
Fred Quintana5e787c42009-08-16 23:13:53 -07002046 try {
2047 return getContentService().getIsSyncable(account, authority);
2048 } catch (RemoteException e) {
2049 throw new RuntimeException("the ContentService should always be reachable", e);
2050 }
2051 }
2052
2053 /**
2054 * Set whether this account/provider is syncable.
Nicolas Falliere9530e3a2012-06-18 17:21:06 -07002055 * <p>This method requires the caller to hold the permission
2056 * {@link android.Manifest.permission#WRITE_SYNC_SETTINGS}.
Fred Quintana718671b2009-08-17 14:08:37 -07002057 * @param syncable >0 denotes syncable, 0 means not syncable, <0 means unknown
Fred Quintana5e787c42009-08-16 23:13:53 -07002058 */
Jim Miller20ea6ce2009-08-17 15:47:14 -07002059 public static void setIsSyncable(Account account, String authority, int syncable) {
Fred Quintana5e787c42009-08-16 23:13:53 -07002060 try {
2061 getContentService().setIsSyncable(account, authority, syncable);
2062 } catch (RemoteException e) {
2063 // exception ignored; if this is thrown then it means the runtime is in the midst of
2064 // being restarted
2065 }
2066 }
2067
2068 /**
Matthew Williams56dbf8f2013-07-26 12:56:39 -07002069 * Set whether the provided {@link SyncService} is available to process work.
2070 * <p>This method requires the caller to hold the permission
2071 * {@link android.Manifest.permission#WRITE_SYNC_SETTINGS}.
2072 * <p>The calling application must be signed with the same certificate as the target component,
2073 * otherwise this call will fail.
2074 */
2075 public static void setServiceActive(ComponentName cname, boolean active) {
2076 try {
2077 getContentService().setServiceActive(cname, active);
2078 } catch (RemoteException e) {
2079 // exception ignored; if this is thrown then it means the runtime is in the midst of
2080 // being restarted
2081 }
2082 }
2083
2084 /**
2085 * Query the state of this sync service.
2086 * <p>Set with {@link #setServiceActive(ComponentName cname, boolean active)}.
2087 * <p>The calling application must be signed with the same certificate as the target component,
2088 * otherwise this call will fail.
2089 * @param cname ComponentName referring to a {@link SyncService}
2090 * @return true if jobs will be run on this service, false otherwise.
2091 */
2092 public static boolean isServiceActive(ComponentName cname) {
2093 try {
2094 return getContentService().isServiceActive(cname);
2095 } catch (RemoteException e) {
2096 throw new RuntimeException("the ContentService should always be reachable", e);
2097 }
2098 }
2099
2100 /**
Fred Quintanaac9385e2009-06-22 18:00:59 -07002101 * Gets the master auto-sync setting that applies to all the providers and accounts.
2102 * If this is false then the per-provider auto-sync setting is ignored.
Nicolas Falliere9530e3a2012-06-18 17:21:06 -07002103 * <p>This method requires the caller to hold the permission
2104 * {@link android.Manifest.permission#READ_SYNC_SETTINGS}.
Fred Quintanaac9385e2009-06-22 18:00:59 -07002105 *
2106 * @return the master auto-sync setting that applies to all the providers and accounts
2107 */
2108 public static boolean getMasterSyncAutomatically() {
2109 try {
2110 return getContentService().getMasterSyncAutomatically();
2111 } catch (RemoteException e) {
2112 throw new RuntimeException("the ContentService should always be reachable", e);
2113 }
2114 }
2115
2116 /**
2117 * Sets the master auto-sync setting that applies to all the providers and accounts.
2118 * If this is false then the per-provider auto-sync setting is ignored.
Nicolas Falliere9530e3a2012-06-18 17:21:06 -07002119 * <p>This method requires the caller to hold the permission
2120 * {@link android.Manifest.permission#WRITE_SYNC_SETTINGS}.
Fred Quintanaac9385e2009-06-22 18:00:59 -07002121 *
2122 * @param sync the master auto-sync setting that applies to all the providers and accounts
2123 */
2124 public static void setMasterSyncAutomatically(boolean sync) {
2125 try {
2126 getContentService().setMasterSyncAutomatically(sync);
2127 } catch (RemoteException e) {
2128 // exception ignored; if this is thrown then it means the runtime is in the midst of
2129 // being restarted
2130 }
2131 }
2132
2133 /**
Matthew Williams56dbf8f2013-07-26 12:56:39 -07002134 * Returns true if there is currently a sync operation for the given account or authority
2135 * actively being processed.
Nicolas Falliere9530e3a2012-06-18 17:21:06 -07002136 * <p>This method requires the caller to hold the permission
2137 * {@link android.Manifest.permission#READ_SYNC_STATS}.
Fred Quintanaac9385e2009-06-22 18:00:59 -07002138 * @param account the account whose setting we are querying
2139 * @param authority the provider whose behavior is being queried
2140 * @return true if a sync is active for the given account or authority.
2141 */
2142 public static boolean isSyncActive(Account account, String authority) {
Matthew Williams56dbf8f2013-07-26 12:56:39 -07002143 if (account == null) {
2144 throw new IllegalArgumentException("account must not be null");
2145 }
2146 if (authority == null) {
2147 throw new IllegalArgumentException("authority must not be null");
2148 }
2149
Fred Quintanaac9385e2009-06-22 18:00:59 -07002150 try {
Matthew Williams56dbf8f2013-07-26 12:56:39 -07002151 return getContentService().isSyncActive(account, authority, null);
2152 } catch (RemoteException e) {
2153 throw new RuntimeException("the ContentService should always be reachable", e);
2154 }
2155 }
2156
2157 public static boolean isSyncActive(ComponentName cname) {
2158 if (cname == null) {
2159 throw new IllegalArgumentException("component name must not be null");
2160 }
2161 try {
2162 return getContentService().isSyncActive(null, null, cname);
Fred Quintanaac9385e2009-06-22 18:00:59 -07002163 } catch (RemoteException e) {
2164 throw new RuntimeException("the ContentService should always be reachable", e);
2165 }
2166 }
2167
2168 /**
Fred Quintanac6a69552010-09-27 17:05:04 -07002169 * If a sync is active returns the information about it, otherwise returns null.
2170 * <p>
Nicolas Falliere9530e3a2012-06-18 17:21:06 -07002171 * This method requires the caller to hold the permission
2172 * {@link android.Manifest.permission#READ_SYNC_STATS}.
2173 * <p>
Fred Quintanad5e4fdc2010-03-30 15:16:21 -07002174 * @return the SyncInfo for the currently active sync or null if one is not active.
Fred Quintanac6a69552010-09-27 17:05:04 -07002175 * @deprecated
2176 * Since multiple concurrent syncs are now supported you should use
2177 * {@link #getCurrentSyncs()} to get the accurate list of current syncs.
2178 * This method returns the first item from the list of current syncs
2179 * or null if there are none.
Fred Quintanaac9385e2009-06-22 18:00:59 -07002180 */
Fred Quintanac6a69552010-09-27 17:05:04 -07002181 @Deprecated
Fred Quintanad5e4fdc2010-03-30 15:16:21 -07002182 public static SyncInfo getCurrentSync() {
Fred Quintanaac9385e2009-06-22 18:00:59 -07002183 try {
Fred Quintanac6a69552010-09-27 17:05:04 -07002184 final List<SyncInfo> syncs = getContentService().getCurrentSyncs();
2185 if (syncs.isEmpty()) {
2186 return null;
2187 }
2188 return syncs.get(0);
2189 } catch (RemoteException e) {
2190 throw new RuntimeException("the ContentService should always be reachable", e);
2191 }
2192 }
2193
2194 /**
2195 * Returns a list with information about all the active syncs. This list will be empty
2196 * if there are no active syncs.
Nicolas Falliere9530e3a2012-06-18 17:21:06 -07002197 * <p>
2198 * This method requires the caller to hold the permission
2199 * {@link android.Manifest.permission#READ_SYNC_STATS}.
2200 * <p>
Fred Quintanac6a69552010-09-27 17:05:04 -07002201 * @return a List of SyncInfo objects for the currently active syncs.
2202 */
2203 public static List<SyncInfo> getCurrentSyncs() {
2204 try {
2205 return getContentService().getCurrentSyncs();
Fred Quintanaac9385e2009-06-22 18:00:59 -07002206 } catch (RemoteException e) {
2207 throw new RuntimeException("the ContentService should always be reachable", e);
2208 }
2209 }
2210
2211 /**
Fred Quintana4a6679b2009-08-17 13:05:39 -07002212 * Returns the status that matches the authority.
Fred Quintanaac9385e2009-06-22 18:00:59 -07002213 * @param account the account whose setting we are querying
2214 * @param authority the provider whose behavior is being queried
2215 * @return the SyncStatusInfo for the authority, or null if none exists
2216 * @hide
2217 */
2218 public static SyncStatusInfo getSyncStatus(Account account, String authority) {
2219 try {
Matthew Williams56dbf8f2013-07-26 12:56:39 -07002220 return getContentService().getSyncStatus(account, authority, null);
Fred Quintanaac9385e2009-06-22 18:00:59 -07002221 } catch (RemoteException e) {
2222 throw new RuntimeException("the ContentService should always be reachable", e);
2223 }
2224 }
2225
2226 /**
2227 * Return true if the pending status is true of any matching authorities.
Nicolas Falliere9530e3a2012-06-18 17:21:06 -07002228 * <p>This method requires the caller to hold the permission
2229 * {@link android.Manifest.permission#READ_SYNC_STATS}.
Fred Quintanaac9385e2009-06-22 18:00:59 -07002230 * @param account the account whose setting we are querying
2231 * @param authority the provider whose behavior is being queried
2232 * @return true if there is a pending sync with the matching account and authority
2233 */
2234 public static boolean isSyncPending(Account account, String authority) {
2235 try {
Matthew Williams56dbf8f2013-07-26 12:56:39 -07002236 return getContentService().isSyncPending(account, authority, null);
2237 } catch (RemoteException e) {
2238 throw new RuntimeException("the ContentService should always be reachable", e);
2239 }
2240 }
2241
2242 public static boolean isSyncPending(ComponentName cname) {
2243 try {
2244 return getContentService().isSyncPending(null, null, cname);
Fred Quintanaac9385e2009-06-22 18:00:59 -07002245 } catch (RemoteException e) {
2246 throw new RuntimeException("the ContentService should always be reachable", e);
2247 }
2248 }
2249
Fred Quintana1b487ec2010-02-26 10:57:55 -08002250 /**
2251 * Request notifications when the different aspects of the SyncManager change. The
2252 * different items that can be requested are:
2253 * <ul>
2254 * <li> {@link #SYNC_OBSERVER_TYPE_PENDING}
2255 * <li> {@link #SYNC_OBSERVER_TYPE_ACTIVE}
2256 * <li> {@link #SYNC_OBSERVER_TYPE_SETTINGS}
2257 * </ul>
2258 * The caller can set one or more of the status types in the mask for any
2259 * given listener registration.
2260 * @param mask the status change types that will cause the callback to be invoked
2261 * @param callback observer to be invoked when the status changes
2262 * @return a handle that can be used to remove the listener at a later time
2263 */
Fred Quintanaac9385e2009-06-22 18:00:59 -07002264 public static Object addStatusChangeListener(int mask, final SyncStatusObserver callback) {
Fred Quintana1b487ec2010-02-26 10:57:55 -08002265 if (callback == null) {
2266 throw new IllegalArgumentException("you passed in a null callback");
2267 }
Fred Quintanaac9385e2009-06-22 18:00:59 -07002268 try {
2269 ISyncStatusObserver.Stub observer = new ISyncStatusObserver.Stub() {
2270 public void onStatusChanged(int which) throws RemoteException {
2271 callback.onStatusChanged(which);
2272 }
2273 };
2274 getContentService().addStatusChangeListener(mask, observer);
2275 return observer;
2276 } catch (RemoteException e) {
2277 throw new RuntimeException("the ContentService should always be reachable", e);
2278 }
2279 }
2280
Fred Quintana1b487ec2010-02-26 10:57:55 -08002281 /**
2282 * Remove a previously registered status change listener.
2283 * @param handle the handle that was returned by {@link #addStatusChangeListener}
2284 */
Fred Quintanaac9385e2009-06-22 18:00:59 -07002285 public static void removeStatusChangeListener(Object handle) {
Fred Quintana1b487ec2010-02-26 10:57:55 -08002286 if (handle == null) {
2287 throw new IllegalArgumentException("you passed in a null handle");
2288 }
Fred Quintanaac9385e2009-06-22 18:00:59 -07002289 try {
2290 getContentService().removeStatusChangeListener((ISyncStatusObserver.Stub) handle);
2291 } catch (RemoteException e) {
2292 // exception ignored; if this is thrown then it means the runtime is in the midst of
2293 // being restarted
2294 }
2295 }
2296
Brad Fitzpatricka63730d2010-02-07 22:25:34 -08002297 /**
2298 * Returns sampling percentage for a given duration.
2299 *
2300 * Always returns at least 1%.
2301 */
2302 private int samplePercentForDuration(long durationMillis) {
2303 if (durationMillis >= SLOW_THRESHOLD_MILLIS) {
2304 return 100;
2305 }
2306 return (int) (100 * durationMillis / SLOW_THRESHOLD_MILLIS) + 1;
2307 }
2308
2309 private void maybeLogQueryToEventLog(long durationMillis,
2310 Uri uri, String[] projection,
2311 String selection, String sortOrder) {
Jeff Sharkey2b4d22c2013-04-26 10:52:00 -07002312 if (!ENABLE_CONTENT_SAMPLE) return;
Brad Fitzpatricka63730d2010-02-07 22:25:34 -08002313 int samplePercent = samplePercentForDuration(durationMillis);
2314 if (samplePercent < 100) {
2315 synchronized (mRandom) {
2316 if (mRandom.nextInt(100) >= samplePercent) {
2317 return;
2318 }
2319 }
2320 }
2321
2322 StringBuilder projectionBuffer = new StringBuilder(100);
2323 if (projection != null) {
2324 for (int i = 0; i < projection.length; ++i) {
2325 // Note: not using a comma delimiter here, as the
2326 // multiple arguments to EventLog.writeEvent later
2327 // stringify with a comma delimiter, which would make
2328 // parsing uglier later.
2329 if (i != 0) projectionBuffer.append('/');
2330 projectionBuffer.append(projection[i]);
2331 }
2332 }
2333
2334 // ActivityThread.currentPackageName() only returns non-null if the
2335 // current thread is an application main thread. This parameter tells
2336 // us whether an event loop is blocked, and if so, which app it is.
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -07002337 String blockingPackage = AppGlobals.getInitialPackage();
Brad Fitzpatricka63730d2010-02-07 22:25:34 -08002338
2339 EventLog.writeEvent(
Brad Fitzpatricka8fbedb2010-04-08 14:08:54 -07002340 EventLogTags.CONTENT_QUERY_SAMPLE,
Brad Fitzpatricka63730d2010-02-07 22:25:34 -08002341 uri.toString(),
2342 projectionBuffer.toString(),
2343 selection != null ? selection : "",
2344 sortOrder != null ? sortOrder : "",
2345 durationMillis,
2346 blockingPackage != null ? blockingPackage : "",
2347 samplePercent);
2348 }
2349
2350 private void maybeLogUpdateToEventLog(
2351 long durationMillis, Uri uri, String operation, String selection) {
Jeff Sharkey2b4d22c2013-04-26 10:52:00 -07002352 if (!ENABLE_CONTENT_SAMPLE) return;
Brad Fitzpatricka63730d2010-02-07 22:25:34 -08002353 int samplePercent = samplePercentForDuration(durationMillis);
2354 if (samplePercent < 100) {
2355 synchronized (mRandom) {
2356 if (mRandom.nextInt(100) >= samplePercent) {
2357 return;
2358 }
2359 }
2360 }
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -07002361 String blockingPackage = AppGlobals.getInitialPackage();
Brad Fitzpatricka63730d2010-02-07 22:25:34 -08002362 EventLog.writeEvent(
Brad Fitzpatricka8fbedb2010-04-08 14:08:54 -07002363 EventLogTags.CONTENT_UPDATE_SAMPLE,
Brad Fitzpatricka63730d2010-02-07 22:25:34 -08002364 uri.toString(),
2365 operation,
2366 selection != null ? selection : "",
2367 durationMillis,
2368 blockingPackage != null ? blockingPackage : "",
2369 samplePercent);
2370 }
Fred Quintanaac9385e2009-06-22 18:00:59 -07002371
Jeff Brown825c5132011-10-12 16:11:30 -07002372 private final class CursorWrapperInner extends CrossProcessCursorWrapper {
Gilles Debunne03f02922010-06-09 14:11:45 -07002373 private final IContentProvider mContentProvider;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002374 public static final String TAG="CursorWrapperInner";
Jeff Brownbaaf8c32011-10-09 14:07:00 -07002375
2376 private final CloseGuard mCloseGuard = CloseGuard.get();
2377 private boolean mProviderReleased;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002378
2379 CursorWrapperInner(Cursor cursor, IContentProvider icp) {
2380 super(cursor);
2381 mContentProvider = icp;
Jeff Brownbaaf8c32011-10-09 14:07:00 -07002382 mCloseGuard.open("close");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002383 }
2384
2385 @Override
2386 public void close() {
2387 super.close();
2388 ContentResolver.this.releaseProvider(mContentProvider);
Jeff Brownbaaf8c32011-10-09 14:07:00 -07002389 mProviderReleased = true;
2390
2391 if (mCloseGuard != null) {
2392 mCloseGuard.close();
2393 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002394 }
2395
2396 @Override
2397 protected void finalize() throws Throwable {
2398 try {
Jeff Brownbaaf8c32011-10-09 14:07:00 -07002399 if (mCloseGuard != null) {
2400 mCloseGuard.warnIfOpen();
2401 }
2402
2403 if (!mProviderReleased && mContentProvider != null) {
2404 // Even though we are using CloseGuard, log this anyway so that
2405 // application developers always see the message in the log.
Johannes Carlsson872a52c2010-12-20 16:14:52 +01002406 Log.w(TAG, "Cursor finalized without prior close()");
Jeff Brownbaaf8c32011-10-09 14:07:00 -07002407 ContentResolver.this.releaseProvider(mContentProvider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002408 }
2409 } finally {
2410 super.finalize();
2411 }
2412 }
2413 }
2414
2415 private final class ParcelFileDescriptorInner extends ParcelFileDescriptor {
Gilles Debunne03f02922010-06-09 14:11:45 -07002416 private final IContentProvider mContentProvider;
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -07002417 private boolean mProviderReleased;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002418
2419 ParcelFileDescriptorInner(ParcelFileDescriptor pfd, IContentProvider icp) {
2420 super(pfd);
2421 mContentProvider = icp;
2422 }
2423
2424 @Override
Amith Yamasani487c11a2013-09-18 09:16:15 -07002425 public void releaseResources() {
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -07002426 if (!mProviderReleased) {
Dianne Hackborn6ae8d182012-05-23 13:12:42 -07002427 ContentResolver.this.releaseProvider(mContentProvider);
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -07002428 mProviderReleased = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002429 }
2430 }
2431 }
2432
Dianne Hackborn231cc602009-04-27 17:10:36 -07002433 /** @hide */
2434 public static final String CONTENT_SERVICE_NAME = "content";
Tom O'Neill0ba1cb02010-01-08 12:53:50 -08002435
Dianne Hackborn231cc602009-04-27 17:10:36 -07002436 /** @hide */
2437 public static IContentService getContentService() {
2438 if (sContentService != null) {
2439 return sContentService;
2440 }
2441 IBinder b = ServiceManager.getService(CONTENT_SERVICE_NAME);
Joe Onorato43a17652011-04-06 19:22:23 -07002442 if (false) Log.v("ContentService", "default service binder = " + b);
Dianne Hackborn231cc602009-04-27 17:10:36 -07002443 sContentService = IContentService.Stub.asInterface(b);
Joe Onorato43a17652011-04-06 19:22:23 -07002444 if (false) Log.v("ContentService", "default service = " + sContentService);
Dianne Hackborn231cc602009-04-27 17:10:36 -07002445 return sContentService;
2446 }
Tom O'Neill0ba1cb02010-01-08 12:53:50 -08002447
Dianne Hackborn35654b62013-01-14 17:38:02 -08002448 /** @hide */
2449 public String getPackageName() {
2450 return mPackageName;
2451 }
2452
Dianne Hackborn231cc602009-04-27 17:10:36 -07002453 private static IContentService sContentService;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002454 private final Context mContext;
Dianne Hackborn35654b62013-01-14 17:38:02 -08002455 final String mPackageName;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002456 private static final String TAG = "ContentResolver";
2457}