blob: aeda7a24066d89448505c2ab19a11780d6b86bd2 [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 Hackborn141f11c2016-04-05 15:46:12 -070020import android.annotation.IntDef;
Jeff Sharkey673db442015-06-11 19:30:57 -070021import android.annotation.NonNull;
Scott Kennedy9f78f652015-03-01 15:29:25 -080022import android.annotation.Nullable;
Tor Norbye788fc2b2015-07-05 16:10:42 -070023import android.annotation.RequiresPermission;
Jeff Sharkeya73b8fd2016-01-06 17:02:08 -070024import android.annotation.TestApi;
Jeff Sharkey8588bc12016-01-06 16:47:42 -070025import android.annotation.UserIdInt;
Dianne Hackborncca1f0e2010-09-26 18:34:53 -070026import android.app.ActivityManagerNative;
Jeff Sharkey66a017b2013-01-17 18:18:22 -080027import android.app.ActivityThread;
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -070028import android.app.AppGlobals;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080029import android.content.pm.PackageManager.NameNotFoundException;
30import android.content.res.AssetFileDescriptor;
31import android.content.res.Resources;
32import android.database.ContentObserver;
Jeff Brown825c5132011-10-12 16:11:30 -070033import android.database.CrossProcessCursorWrapper;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080034import android.database.Cursor;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080035import android.database.IContentObserver;
Jeff Sharkey5b836f22014-08-27 14:46:32 -070036import android.graphics.Point;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080037import android.net.Uri;
38import android.os.Bundle;
Jeff Browna7771df2012-05-07 20:06:46 -070039import android.os.CancellationSignal;
Dianne Hackborn6ae8d182012-05-23 13:12:42 -070040import android.os.DeadObjectException;
Dianne Hackborn231cc602009-04-27 17:10:36 -070041import android.os.IBinder;
Jeff Browna7771df2012-05-07 20:06:46 -070042import android.os.ICancellationSignal;
43import android.os.OperationCanceledException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080044import android.os.ParcelFileDescriptor;
45import android.os.RemoteException;
Dianne Hackborn231cc602009-04-27 17:10:36 -070046import android.os.ServiceManager;
Brad Fitzpatrickd72f7182010-02-11 17:07:51 -080047import android.os.SystemClock;
Dianne Hackborn5e03e2c2012-09-06 14:21:19 -070048import android.os.UserHandle;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080049import android.text.TextUtils;
Brad Fitzpatricka63730d2010-02-07 22:25:34 -080050import android.util.EventLog;
Dianne Hackborn231cc602009-04-27 17:10:36 -070051import android.util.Log;
Jeff Sharkey08da7a12013-08-11 20:53:18 -070052
Amith Yamasani37a40c22015-06-17 13:25:42 -070053import com.android.internal.util.ArrayUtils;
Jeff Sharkey673db442015-06-11 19:30:57 -070054import com.android.internal.util.Preconditions;
55
Jeff Sharkey60cfad82016-01-05 17:30:57 -070056import dalvik.system.CloseGuard;
57
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080058import java.io.File;
59import java.io.FileInputStream;
60import java.io.FileNotFoundException;
61import java.io.IOException;
62import java.io.InputStream;
63import java.io.OutputStream;
Dianne Hackborn141f11c2016-04-05 15:46:12 -070064import java.lang.annotation.Retention;
65import java.lang.annotation.RetentionPolicy;
Gilles Debunne03f02922010-06-09 14:11:45 -070066import java.util.ArrayList;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080067import java.util.List;
Brad Fitzpatricka63730d2010-02-07 22:25:34 -080068import java.util.Random;
Jeff Sharkey60cfad82016-01-05 17:30:57 -070069import java.util.concurrent.atomic.AtomicBoolean;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080070
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080071/**
72 * This class provides applications access to the content model.
Joe Fernandez558459f2011-10-13 16:47:36 -070073 *
74 * <div class="special reference">
75 * <h3>Developer Guides</h3>
76 * <p>For more information about using a ContentResolver with content providers, read the
77 * <a href="{@docRoot}guide/topics/providers/content-providers.html">Content Providers</a>
78 * developer guide.</p>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080079 */
80public abstract class ContentResolver {
Fred Quintanaac9385e2009-06-22 18:00:59 -070081 /**
82 * @deprecated instead use
83 * {@link #requestSync(android.accounts.Account, String, android.os.Bundle)}
84 */
Fred Quintana4a6679b2009-08-17 13:05:39 -070085 @Deprecated
Fred Quintanaac9385e2009-06-22 18:00:59 -070086 public static final String SYNC_EXTRAS_ACCOUNT = "account";
Georgi Nikolovb3395572013-06-18 18:27:31 -070087
88 /**
89 * If this extra is set to true, the sync request will be scheduled
90 * at the front of the sync request queue and without any delay
91 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080092 public static final String SYNC_EXTRAS_EXPEDITED = "expedited";
Georgi Nikolovb3395572013-06-18 18:27:31 -070093
Fred Quintanaac9385e2009-06-22 18:00:59 -070094 /**
Shreyas Basarge8c834c02016-01-07 13:53:16 +000095 * If this extra is set to true, the sync request will be scheduled
96 * only when the device is plugged in. This is equivalent to calling
97 * setRequiresCharging(true) on {@link SyncRequest}.
98 */
99 public static final String SYNC_EXTRAS_REQUIRE_CHARGING = "require_charging";
100
101 /**
Fred Quintanaac9385e2009-06-22 18:00:59 -0700102 * @deprecated instead use
103 * {@link #SYNC_EXTRAS_MANUAL}
104 */
Fred Quintana4a6679b2009-08-17 13:05:39 -0700105 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800106 public static final String SYNC_EXTRAS_FORCE = "force";
Fred Quintana53bd2522010-02-05 15:28:12 -0800107
108 /**
109 * If this extra is set to true then the sync settings (like getSyncAutomatically())
110 * are ignored by the sync scheduler.
111 */
112 public static final String SYNC_EXTRAS_IGNORE_SETTINGS = "ignore_settings";
113
114 /**
115 * If this extra is set to true then any backoffs for the initial attempt (e.g. due to retries)
116 * are ignored by the sync scheduler. If this request fails and gets rescheduled then the
117 * retries will still honor the backoff.
118 */
119 public static final String SYNC_EXTRAS_IGNORE_BACKOFF = "ignore_backoff";
120
121 /**
122 * If this extra is set to true then the request will not be retried if it fails.
123 */
124 public static final String SYNC_EXTRAS_DO_NOT_RETRY = "do_not_retry";
125
126 /**
127 * Setting this extra is the equivalent of setting both {@link #SYNC_EXTRAS_IGNORE_SETTINGS}
128 * and {@link #SYNC_EXTRAS_IGNORE_BACKOFF}
129 */
Fred Quintanaac9385e2009-06-22 18:00:59 -0700130 public static final String SYNC_EXTRAS_MANUAL = "force";
Fred Quintana53bd2522010-02-05 15:28:12 -0800131
Georgi Nikolovb3395572013-06-18 18:27:31 -0700132 /**
133 * Indicates that this sync is intended to only upload local changes to the server.
134 * For example, this will be set to true if the sync is initiated by a call to
135 * {@link ContentResolver#notifyChange(android.net.Uri, android.database.ContentObserver, boolean)}
136 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800137 public static final String SYNC_EXTRAS_UPLOAD = "upload";
Georgi Nikolovb3395572013-06-18 18:27:31 -0700138
139 /**
140 * Indicates that the sync adapter should proceed with the delete operations,
141 * even if it determines that there are too many.
142 * See {@link SyncResult#tooManyDeletions}
143 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800144 public static final String SYNC_EXTRAS_OVERRIDE_TOO_MANY_DELETIONS = "deletions_override";
Georgi Nikolovb3395572013-06-18 18:27:31 -0700145
146 /**
147 * Indicates that the sync adapter should not proceed with the delete operations,
148 * if it determines that there are too many.
149 * See {@link SyncResult#tooManyDeletions}
150 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800151 public static final String SYNC_EXTRAS_DISCARD_LOCAL_DELETIONS = "discard_deletions";
152
Matthew Williamsfa774182013-06-18 15:44:11 -0700153 /* Extensions to API. TODO: Not clear if we will keep these as public flags. */
154 /** {@hide} User-specified flag for expected upload size. */
155 public static final String SYNC_EXTRAS_EXPECTED_UPLOAD = "expected_upload";
156
157 /** {@hide} User-specified flag for expected download size. */
158 public static final String SYNC_EXTRAS_EXPECTED_DOWNLOAD = "expected_download";
159
160 /** {@hide} Priority of this sync with respect to other syncs scheduled for this application. */
161 public static final String SYNC_EXTRAS_PRIORITY = "sync_priority";
162
163 /** {@hide} Flag to allow sync to occur on metered network. */
Matthew Williams56dbf8f2013-07-26 12:56:39 -0700164 public static final String SYNC_EXTRAS_DISALLOW_METERED = "allow_metered";
Matthew Williamsfa774182013-06-18 15:44:11 -0700165
Fred Quintana4a6679b2009-08-17 13:05:39 -0700166 /**
167 * Set by the SyncManager to request that the SyncAdapter initialize itself for
168 * the given account/authority pair. One required initialization step is to
169 * ensure that {@link #setIsSyncable(android.accounts.Account, String, int)} has been
170 * called with a >= 0 value. When this flag is set the SyncAdapter does not need to
171 * do a full sync, though it is allowed to do so.
172 */
173 public static final String SYNC_EXTRAS_INITIALIZE = "initialize";
174
Jeff Sharkey7a96c392012-11-15 14:01:46 -0800175 /** @hide */
176 public static final Intent ACTION_SYNC_CONN_STATUS_CHANGED =
177 new Intent("com.android.sync.SYNC_CONN_STATUS_CHANGED");
178
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800179 public static final String SCHEME_CONTENT = "content";
180 public static final String SCHEME_ANDROID_RESOURCE = "android.resource";
181 public static final String SCHEME_FILE = "file";
182
183 /**
Jeff Sharkey5b836f22014-08-27 14:46:32 -0700184 * An extra {@link Point} describing the optimal size for a requested image
185 * resource, in pixels. If a provider has multiple sizes of the image, it
186 * should return the image closest to this size.
187 *
188 * @see #openTypedAssetFileDescriptor(Uri, String, Bundle)
189 * @see #openTypedAssetFileDescriptor(Uri, String, Bundle,
190 * CancellationSignal)
191 */
192 public static final String EXTRA_SIZE = "android.content.extra.SIZE";
193
194 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800195 * This is the Android platform's base MIME type for a content: URI
196 * containing a Cursor of a single item. Applications should use this
197 * as the base type along with their own sub-type of their content: URIs
198 * that represent a particular item. For example, hypothetical IMAP email
199 * client may have a URI
200 * <code>content://com.company.provider.imap/inbox/1</code> for a particular
201 * message in the inbox, whose MIME type would be reported as
202 * <code>CURSOR_ITEM_BASE_TYPE + "/vnd.company.imap-msg"</code>
Tom O'Neill0ba1cb02010-01-08 12:53:50 -0800203 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800204 * <p>Compare with {@link #CURSOR_DIR_BASE_TYPE}.
205 */
206 public static final String CURSOR_ITEM_BASE_TYPE = "vnd.android.cursor.item";
Tom O'Neill0ba1cb02010-01-08 12:53:50 -0800207
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800208 /**
209 * This is the Android platform's base MIME type for a content: URI
210 * containing a Cursor of zero or more items. Applications should use this
211 * as the base type along with their own sub-type of their content: URIs
212 * that represent a directory of items. For example, hypothetical IMAP email
213 * client may have a URI
214 * <code>content://com.company.provider.imap/inbox</code> for all of the
215 * messages in its inbox, whose MIME type would be reported as
216 * <code>CURSOR_DIR_BASE_TYPE + "/vnd.company.imap-msg"</code>
Tom O'Neill0ba1cb02010-01-08 12:53:50 -0800217 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800218 * <p>Note how the base MIME type varies between this and
219 * {@link #CURSOR_ITEM_BASE_TYPE} depending on whether there is
220 * one single item or multiple items in the data set, while the sub-type
221 * remains the same because in either case the data structure contained
222 * in the cursor is the same.
223 */
224 public static final String CURSOR_DIR_BASE_TYPE = "vnd.android.cursor.dir";
Fred Quintanaac9385e2009-06-22 18:00:59 -0700225
Matt Caseybd7bcf02014-02-05 15:51:39 -0800226 /**
227 * This is the Android platform's generic MIME type to match any MIME
228 * type of the form "{@link #CURSOR_ITEM_BASE_TYPE}/{@code SUB_TYPE}".
229 * {@code SUB_TYPE} is the sub-type of the application-dependent
230 * content, e.g., "audio", "video", "playlist".
231 */
232 public static final String ANY_CURSOR_ITEM_TYPE = "vnd.android.cursor.item/*";
233
Fred Quintanaac9385e2009-06-22 18:00:59 -0700234 /** @hide */
235 public static final int SYNC_ERROR_SYNC_ALREADY_IN_PROGRESS = 1;
236 /** @hide */
237 public static final int SYNC_ERROR_AUTHENTICATION = 2;
238 /** @hide */
239 public static final int SYNC_ERROR_IO = 3;
240 /** @hide */
241 public static final int SYNC_ERROR_PARSE = 4;
242 /** @hide */
243 public static final int SYNC_ERROR_CONFLICT = 5;
244 /** @hide */
245 public static final int SYNC_ERROR_TOO_MANY_DELETIONS = 6;
246 /** @hide */
247 public static final int SYNC_ERROR_TOO_MANY_RETRIES = 7;
248 /** @hide */
249 public static final int SYNC_ERROR_INTERNAL = 8;
250
Alon Albert57286f92012-10-09 14:21:38 -0700251 private static final String[] SYNC_ERROR_NAMES = new String[] {
252 "already-in-progress",
253 "authentication-error",
254 "io-error",
255 "parse-error",
256 "conflict",
257 "too-many-deletions",
258 "too-many-retries",
259 "internal-error",
260 };
261
262 /** @hide */
Jeff Sharkey7a96c392012-11-15 14:01:46 -0800263 public static String syncErrorToString(int error) {
Alon Albert57286f92012-10-09 14:21:38 -0700264 if (error < 1 || error > SYNC_ERROR_NAMES.length) {
265 return String.valueOf(error);
266 }
267 return SYNC_ERROR_NAMES[error - 1];
268 }
269
Alon Albert5c113fa2013-02-07 08:07:32 -0800270 /** @hide */
271 public static int syncErrorStringToInt(String error) {
272 for (int i = 0, n = SYNC_ERROR_NAMES.length; i < n; i++) {
273 if (SYNC_ERROR_NAMES[i].equals(error)) {
274 return i + 1;
275 }
276 }
277 if (error != null) {
278 try {
279 return Integer.parseInt(error);
280 } catch (NumberFormatException e) {
281 Log.d(TAG, "error parsing sync error: " + error);
282 }
283 }
284 return 0;
285 }
286
Fred Quintanaac9385e2009-06-22 18:00:59 -0700287 public static final int SYNC_OBSERVER_TYPE_SETTINGS = 1<<0;
Fred Quintanaac9385e2009-06-22 18:00:59 -0700288 public static final int SYNC_OBSERVER_TYPE_PENDING = 1<<1;
Fred Quintanaac9385e2009-06-22 18:00:59 -0700289 public static final int SYNC_OBSERVER_TYPE_ACTIVE = 1<<2;
290 /** @hide */
291 public static final int SYNC_OBSERVER_TYPE_STATUS = 1<<3;
292 /** @hide */
293 public static final int SYNC_OBSERVER_TYPE_ALL = 0x7fffffff;
294
Dianne Hackborn141f11c2016-04-05 15:46:12 -0700295 /** @hide */
296 @IntDef(flag = true,
297 value = {
298 NOTIFY_SYNC_TO_NETWORK,
299 NOTIFY_SKIP_NOTIFY_FOR_DESCENDANTS
300 })
301 @Retention(RetentionPolicy.SOURCE)
302 public @interface NotifyFlags {}
303
304 /**
305 * Flag for {@link #notifyChange(Uri, ContentObserver, int)}: attempt to sync the change
306 * to the network.
307 */
308 public static final int NOTIFY_SYNC_TO_NETWORK = 1<<0;
309
310 /**
311 * Flag for {@link #notifyChange(Uri, ContentObserver, int)}: if set, this notification
312 * will be skipped if it is being delivered to the root URI of a ContentObserver that is
313 * using "notify for descendants." The purpose of this is to allow the provide to send
314 * a general notification of "something under X" changed that observers of that specific
315 * URI can receive, while also sending a specific URI under X. It would use this flag
316 * when sending the former, so that observers of "X and descendants" only see the latter.
317 */
318 public static final int NOTIFY_SKIP_NOTIFY_FOR_DESCENDANTS = 1<<1;
319
Brad Fitzpatrick25880962010-02-22 15:17:49 -0800320 // Always log queries which take 500ms+; shorter queries are
Brad Fitzpatricka63730d2010-02-07 22:25:34 -0800321 // sampled accordingly.
Jeff Sharkey2b4d22c2013-04-26 10:52:00 -0700322 private static final boolean ENABLE_CONTENT_SAMPLE = false;
Brad Fitzpatrick25880962010-02-22 15:17:49 -0800323 private static final int SLOW_THRESHOLD_MILLIS = 500;
Brad Fitzpatricka63730d2010-02-07 22:25:34 -0800324 private final Random mRandom = new Random(); // guarded by itself
325
Dianne Hackborn231cc602009-04-27 17:10:36 -0700326 public ContentResolver(Context context) {
Jeff Sharkey66a017b2013-01-17 18:18:22 -0800327 mContext = context != null ? context : ActivityThread.currentApplication();
Dianne Hackborn95d78532013-09-11 09:51:14 -0700328 mPackageName = mContext.getOpPackageName();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800329 }
330
331 /** @hide */
332 protected abstract IContentProvider acquireProvider(Context c, String name);
Jeff Sharkeye66c1772013-09-20 14:30:59 -0700333
334 /**
335 * Providing a default implementation of this, to avoid having to change a
336 * lot of other things, but implementations of ContentResolver should
337 * implement it.
338 *
339 * @hide
340 */
Dianne Hackborncca1f0e2010-09-26 18:34:53 -0700341 protected IContentProvider acquireExistingProvider(Context c, String name) {
342 return acquireProvider(c, name);
343 }
Jeff Sharkeye66c1772013-09-20 14:30:59 -0700344
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800345 /** @hide */
346 public abstract boolean releaseProvider(IContentProvider icp);
Dianne Hackborn652b6d12012-05-09 18:18:40 -0700347 /** @hide */
348 protected abstract IContentProvider acquireUnstableProvider(Context c, String name);
349 /** @hide */
350 public abstract boolean releaseUnstableProvider(IContentProvider icp);
Dianne Hackborn6ae8d182012-05-23 13:12:42 -0700351 /** @hide */
352 public abstract void unstableProviderDied(IContentProvider icp);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800353
Jeff Sharkey7aa76012013-09-30 14:26:27 -0700354 /** @hide */
355 public void appNotRespondingViaProvider(IContentProvider icp) {
356 throw new UnsupportedOperationException("appNotRespondingViaProvider");
357 }
358
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800359 /**
360 * Return the MIME type of the given content URL.
361 *
362 * @param url A Uri identifying content (either a list or specific type),
363 * using the content:// scheme.
364 * @return A MIME type for the content, or null if the URL is invalid or the type is unknown
365 */
Jeff Sharkey673db442015-06-11 19:30:57 -0700366 public final @Nullable String getType(@NonNull Uri url) {
367 Preconditions.checkNotNull(url, "url");
368
Dianne Hackborn6ae8d182012-05-23 13:12:42 -0700369 // XXX would like to have an acquireExistingUnstableProvider for this.
Dianne Hackborncca1f0e2010-09-26 18:34:53 -0700370 IContentProvider provider = acquireExistingProvider(url);
371 if (provider != null) {
372 try {
373 return provider.getType(url);
374 } catch (RemoteException e) {
375 return null;
376 } catch (java.lang.Exception e) {
Ola Olsson145e6c42010-12-20 16:45:35 +0100377 Log.w(TAG, "Failed to get type for: " + url + " (" + e.getMessage() + ")");
Dianne Hackborncca1f0e2010-09-26 18:34:53 -0700378 return null;
379 } finally {
380 releaseProvider(provider);
381 }
382 }
383
384 if (!SCHEME_CONTENT.equals(url.getScheme())) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800385 return null;
386 }
Dianne Hackborncca1f0e2010-09-26 18:34:53 -0700387
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800388 try {
Dianne Hackborn5e03e2c2012-09-06 14:21:19 -0700389 String type = ActivityManagerNative.getDefault().getProviderMimeType(
Nicolas Prevot1dddc7f2014-07-07 17:44:58 +0100390 ContentProvider.getUriWithoutUserId(url), resolveUserId(url));
Dianne Hackborncca1f0e2010-09-26 18:34:53 -0700391 return type;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800392 } catch (RemoteException e) {
Brad Fitzpatrick534c84c2011-01-12 14:06:30 -0800393 // Arbitrary and not worth documenting, as Activity
394 // Manager will kill this process shortly anyway.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800395 return null;
Ola Olsson145e6c42010-12-20 16:45:35 +0100396 } catch (java.lang.Exception e) {
397 Log.w(TAG, "Failed to get type for: " + url + " (" + e.getMessage() + ")");
398 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800399 }
400 }
401
402 /**
Dianne Hackborn23fdaf62010-08-06 12:16:55 -0700403 * Query for the possible MIME types for the representations the given
404 * content URL can be returned when opened as as stream with
405 * {@link #openTypedAssetFileDescriptor}. Note that the types here are
406 * not necessarily a superset of the type returned by {@link #getType} --
Jeff Sharkeybd3b9022013-08-20 15:20:04 -0700407 * many content providers cannot return a raw stream for the structured
Dianne Hackborn23fdaf62010-08-06 12:16:55 -0700408 * data that they contain.
409 *
410 * @param url A Uri identifying content (either a list or specific type),
411 * using the content:// scheme.
412 * @param mimeTypeFilter The desired MIME type. This may be a pattern,
John Spurlock33900182014-01-02 11:04:18 -0500413 * such as *&#47;*, to query for all available MIME types that match the
Dianne Hackborn23fdaf62010-08-06 12:16:55 -0700414 * pattern.
Dianne Hackbornacb69bb2012-04-13 15:36:06 -0700415 * @return Returns an array of MIME type strings for all available
Dianne Hackborn23fdaf62010-08-06 12:16:55 -0700416 * data streams that match the given mimeTypeFilter. If there are none,
417 * null is returned.
418 */
Jeff Sharkey673db442015-06-11 19:30:57 -0700419 public @Nullable String[] getStreamTypes(@NonNull Uri url, @NonNull String mimeTypeFilter) {
420 Preconditions.checkNotNull(url, "url");
421 Preconditions.checkNotNull(mimeTypeFilter, "mimeTypeFilter");
422
Dianne Hackborn23fdaf62010-08-06 12:16:55 -0700423 IContentProvider provider = acquireProvider(url);
424 if (provider == null) {
425 return null;
426 }
Dianne Hackborn64bbbb42010-09-27 20:25:20 -0700427
Dianne Hackborn23fdaf62010-08-06 12:16:55 -0700428 try {
429 return provider.getStreamTypes(url, mimeTypeFilter);
430 } catch (RemoteException e) {
Brad Fitzpatrick534c84c2011-01-12 14:06:30 -0800431 // Arbitrary and not worth documenting, as Activity
432 // Manager will kill this process shortly anyway.
Dianne Hackborn23fdaf62010-08-06 12:16:55 -0700433 return null;
Dianne Hackborn23fdaf62010-08-06 12:16:55 -0700434 } finally {
Brad Fitzpatrick534c84c2011-01-12 14:06:30 -0800435 releaseProvider(provider);
436 }
Dianne Hackborn23fdaf62010-08-06 12:16:55 -0700437 }
438
439 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800440 * Query the given URI, returning a {@link Cursor} over the result set.
Tom O'Neill0ba1cb02010-01-08 12:53:50 -0800441 * <p>
442 * For best performance, the caller should follow these guidelines:
443 * <ul>
444 * <li>Provide an explicit projection, to prevent
445 * reading data from storage that aren't going to be used.</li>
446 * <li>Use question mark parameter markers such as 'phone=?' instead of
447 * explicit values in the {@code selection} parameter, so that queries
448 * that differ only by those values will be recognized as the same
449 * for caching purposes.</li>
450 * </ul>
451 * </p>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800452 *
453 * @param uri The URI, using the content:// scheme, for the content to
454 * retrieve.
455 * @param projection A list of which columns to return. Passing null will
Tom O'Neill0ba1cb02010-01-08 12:53:50 -0800456 * return all columns, which is inefficient.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800457 * @param selection A filter declaring which rows to return, formatted as an
458 * SQL WHERE clause (excluding the WHERE itself). Passing null will
459 * return all rows for the given URI.
460 * @param selectionArgs You may include ?s in selection, which will be
461 * replaced by the values from selectionArgs, in the order that they
462 * appear in the selection. The values will be bound as Strings.
463 * @param sortOrder How to order the rows, formatted as an SQL ORDER BY
464 * clause (excluding the ORDER BY itself). Passing null will use the
465 * default sort order, which may be unordered.
466 * @return A Cursor object, which is positioned before the first entry, or null
467 * @see Cursor
468 */
Tor Norbye788fc2b2015-07-05 16:10:42 -0700469 public final @Nullable Cursor query(@RequiresPermission.Read @NonNull Uri uri,
470 @Nullable String[] projection, @Nullable String selection,
471 @Nullable String[] selectionArgs, @Nullable String sortOrder) {
Jeff Brown75ea64f2012-01-25 19:37:13 -0800472 return query(uri, projection, selection, selectionArgs, sortOrder, null);
473 }
474
475 /**
Jeff Brownc64ff372013-10-09 18:50:56 -0700476 * Query the given URI, returning a {@link Cursor} over the result set
477 * with optional support for cancellation.
Jeff Brown75ea64f2012-01-25 19:37:13 -0800478 * <p>
479 * For best performance, the caller should follow these guidelines:
480 * <ul>
481 * <li>Provide an explicit projection, to prevent
482 * reading data from storage that aren't going to be used.</li>
483 * <li>Use question mark parameter markers such as 'phone=?' instead of
484 * explicit values in the {@code selection} parameter, so that queries
485 * that differ only by those values will be recognized as the same
486 * for caching purposes.</li>
487 * </ul>
488 * </p>
489 *
490 * @param uri The URI, using the content:// scheme, for the content to
491 * retrieve.
492 * @param projection A list of which columns to return. Passing null will
493 * return all columns, which is inefficient.
494 * @param selection A filter declaring which rows to return, formatted as an
495 * SQL WHERE clause (excluding the WHERE itself). Passing null will
496 * return all rows for the given URI.
497 * @param selectionArgs You may include ?s in selection, which will be
498 * replaced by the values from selectionArgs, in the order that they
499 * appear in the selection. The values will be bound as Strings.
500 * @param sortOrder How to order the rows, formatted as an SQL ORDER BY
501 * clause (excluding the ORDER BY itself). Passing null will use the
502 * default sort order, which may be unordered.
Jeff Brown4c1241d2012-02-02 17:05:00 -0800503 * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
Jeff Brown75ea64f2012-01-25 19:37:13 -0800504 * If the operation is canceled, then {@link OperationCanceledException} will be thrown
505 * when the query is executed.
506 * @return A Cursor object, which is positioned before the first entry, or null
507 * @see Cursor
508 */
Tor Norbye788fc2b2015-07-05 16:10:42 -0700509 public final @Nullable Cursor query(final @RequiresPermission.Read @NonNull Uri uri,
510 @Nullable String[] projection, @Nullable String selection,
511 @Nullable String[] selectionArgs, @Nullable String sortOrder,
512 @Nullable CancellationSignal cancellationSignal) {
Jeff Sharkey673db442015-06-11 19:30:57 -0700513 Preconditions.checkNotNull(uri, "uri");
Dianne Hackborn6ae8d182012-05-23 13:12:42 -0700514 IContentProvider unstableProvider = acquireUnstableProvider(uri);
515 if (unstableProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800516 return null;
517 }
Dianne Hackborn6ae8d182012-05-23 13:12:42 -0700518 IContentProvider stableProvider = null;
Jeff Brownc21b5a02013-01-07 17:15:12 -0800519 Cursor qCursor = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800520 try {
Brad Fitzpatrickd72f7182010-02-11 17:07:51 -0800521 long startTime = SystemClock.uptimeMillis();
Jeff Brown75ea64f2012-01-25 19:37:13 -0800522
Jeff Brown4c1241d2012-02-02 17:05:00 -0800523 ICancellationSignal remoteCancellationSignal = null;
524 if (cancellationSignal != null) {
525 cancellationSignal.throwIfCanceled();
Dianne Hackborn6ae8d182012-05-23 13:12:42 -0700526 remoteCancellationSignal = unstableProvider.createCancellationSignal();
Jeff Brown4c1241d2012-02-02 17:05:00 -0800527 cancellationSignal.setRemote(remoteCancellationSignal);
Jeff Brown75ea64f2012-01-25 19:37:13 -0800528 }
Dianne Hackborn6ae8d182012-05-23 13:12:42 -0700529 try {
Dianne Hackborn35654b62013-01-14 17:38:02 -0800530 qCursor = unstableProvider.query(mPackageName, uri, projection,
Dianne Hackborn6ae8d182012-05-23 13:12:42 -0700531 selection, selectionArgs, sortOrder, remoteCancellationSignal);
532 } catch (DeadObjectException e) {
533 // The remote process has died... but we only hold an unstable
534 // reference though, so we might recover!!! Let's try!!!!
535 // This is exciting!!1!!1!!!!1
536 unstableProviderDied(unstableProvider);
537 stableProvider = acquireProvider(uri);
538 if (stableProvider == null) {
539 return null;
540 }
Dianne Hackborn35654b62013-01-14 17:38:02 -0800541 qCursor = stableProvider.query(mPackageName, uri, projection,
Dianne Hackborn6ae8d182012-05-23 13:12:42 -0700542 selection, selectionArgs, sortOrder, remoteCancellationSignal);
543 }
Brad Fitzpatricka63730d2010-02-07 22:25:34 -0800544 if (qCursor == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800545 return null;
546 }
Jeff Brownc21b5a02013-01-07 17:15:12 -0800547
548 // Force query execution. Might fail and throw a runtime exception here.
Vasu Nori020e5342010-04-28 14:22:38 -0700549 qCursor.getCount();
Brad Fitzpatrickd72f7182010-02-11 17:07:51 -0800550 long durationMillis = SystemClock.uptimeMillis() - startTime;
Brad Fitzpatricka63730d2010-02-07 22:25:34 -0800551 maybeLogQueryToEventLog(durationMillis, uri, projection, selection, sortOrder);
Jeff Brownc21b5a02013-01-07 17:15:12 -0800552
553 // Wrap the cursor object into CursorWrapperInner object.
Jeff Sharkey60cfad82016-01-05 17:30:57 -0700554 final IContentProvider provider = (stableProvider != null) ? stableProvider
555 : acquireProvider(uri);
556 final CursorWrapperInner wrapper = new CursorWrapperInner(qCursor, provider);
Dianne Hackborn6ae8d182012-05-23 13:12:42 -0700557 stableProvider = null;
Jeff Brownc21b5a02013-01-07 17:15:12 -0800558 qCursor = null;
Dianne Hackborn6ae8d182012-05-23 13:12:42 -0700559 return wrapper;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800560 } catch (RemoteException e) {
Brad Fitzpatrick534c84c2011-01-12 14:06:30 -0800561 // Arbitrary and not worth documenting, as Activity
562 // Manager will kill this process shortly anyway.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800563 return null;
Dianne Hackborn6ae8d182012-05-23 13:12:42 -0700564 } finally {
Jeff Brownc21b5a02013-01-07 17:15:12 -0800565 if (qCursor != null) {
566 qCursor.close();
567 }
Jeff Sharkeybd3b9022013-08-20 15:20:04 -0700568 if (cancellationSignal != null) {
569 cancellationSignal.setRemote(null);
570 }
Dianne Hackborn6ae8d182012-05-23 13:12:42 -0700571 if (unstableProvider != null) {
572 releaseUnstableProvider(unstableProvider);
573 }
574 if (stableProvider != null) {
575 releaseProvider(stableProvider);
576 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800577 }
578 }
579
Fred Quintana89437372009-05-15 15:10:40 -0700580 /**
Dianne Hackborn38ed2a42013-09-06 16:17:22 -0700581 * Transform the given <var>url</var> to a canonical representation of
582 * its referenced resource, which can be used across devices, persisted,
583 * backed up and restored, etc. The returned Uri is still a fully capable
584 * Uri for use with its content provider, allowing you to do all of the
585 * same content provider operations as with the original Uri --
586 * {@link #query}, {@link #openInputStream(android.net.Uri)}, etc. The
587 * only difference in behavior between the original and new Uris is that
588 * the content provider may need to do some additional work at each call
589 * using it to resolve it to the correct resource, especially if the
590 * canonical Uri has been moved to a different environment.
591 *
592 * <p>If you are moving a canonical Uri between environments, you should
593 * perform another call to {@link #canonicalize} with that original Uri to
594 * re-canonicalize it for the current environment. Alternatively, you may
595 * want to use {@link #uncanonicalize} to transform it to a non-canonical
596 * Uri that works only in the current environment but potentially more
597 * efficiently than the canonical representation.</p>
598 *
599 * @param url The {@link Uri} that is to be transformed to a canonical
600 * representation. Like all resolver calls, the input can be either
601 * a non-canonical or canonical Uri.
602 *
603 * @return Returns the official canonical representation of <var>url</var>,
604 * or null if the content provider does not support a canonical representation
605 * of the given Uri. Many providers may not support canonicalization of some
606 * or all of their Uris.
607 *
608 * @see #uncanonicalize
609 */
Jeff Sharkey673db442015-06-11 19:30:57 -0700610 public final @Nullable Uri canonicalize(@NonNull Uri url) {
611 Preconditions.checkNotNull(url, "url");
Dianne Hackborn38ed2a42013-09-06 16:17:22 -0700612 IContentProvider provider = acquireProvider(url);
613 if (provider == null) {
614 return null;
615 }
616
617 try {
618 return provider.canonicalize(mPackageName, url);
619 } catch (RemoteException e) {
620 // Arbitrary and not worth documenting, as Activity
621 // Manager will kill this process shortly anyway.
622 return null;
623 } finally {
624 releaseProvider(provider);
625 }
626 }
627
628 /**
629 * Given a canonical Uri previously generated by {@link #canonicalize}, convert
630 * it to its local non-canonical form. This can be useful in some cases where
631 * you know that you will only be using the Uri in the current environment and
632 * want to avoid any possible overhead when using it with the content
Dianne Hackbornb3ac67a2013-09-11 11:02:24 -0700633 * provider or want to verify that the referenced data exists at all in the
634 * new environment.
Dianne Hackborn38ed2a42013-09-06 16:17:22 -0700635 *
636 * @param url The canonical {@link Uri} that is to be convered back to its
637 * non-canonical form.
638 *
Dianne Hackbornb3ac67a2013-09-11 11:02:24 -0700639 * @return Returns the non-canonical representation of <var>url</var>. This will
640 * return null if data identified by the canonical Uri can not be found in
641 * the current environment; callers must always check for null and deal with
642 * that by appropriately falling back to an alternative.
Dianne Hackborn38ed2a42013-09-06 16:17:22 -0700643 *
644 * @see #canonicalize
645 */
Jeff Sharkey673db442015-06-11 19:30:57 -0700646 public final @Nullable Uri uncanonicalize(@NonNull Uri url) {
647 Preconditions.checkNotNull(url, "url");
Dianne Hackborn38ed2a42013-09-06 16:17:22 -0700648 IContentProvider provider = acquireProvider(url);
649 if (provider == null) {
650 return null;
651 }
652
653 try {
654 return provider.uncanonicalize(mPackageName, url);
655 } catch (RemoteException e) {
656 // Arbitrary and not worth documenting, as Activity
657 // Manager will kill this process shortly anyway.
658 return null;
659 } finally {
660 releaseProvider(provider);
661 }
662 }
663
664 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800665 * Open a stream on to the content associated with a content URI. If there
666 * is no data associated with the URI, FileNotFoundException is thrown.
667 *
668 * <h5>Accepts the following URI schemes:</h5>
669 * <ul>
670 * <li>content ({@link #SCHEME_CONTENT})</li>
671 * <li>android.resource ({@link #SCHEME_ANDROID_RESOURCE})</li>
672 * <li>file ({@link #SCHEME_FILE})</li>
673 * </ul>
Tom O'Neill0ba1cb02010-01-08 12:53:50 -0800674 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800675 * <p>See {@link #openAssetFileDescriptor(Uri, String)} for more information
676 * on these schemes.
Tom O'Neill0ba1cb02010-01-08 12:53:50 -0800677 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800678 * @param uri The desired URI.
679 * @return InputStream
680 * @throws FileNotFoundException if the provided URI could not be opened.
681 * @see #openAssetFileDescriptor(Uri, String)
682 */
Jeff Sharkey673db442015-06-11 19:30:57 -0700683 public final @Nullable InputStream openInputStream(@NonNull Uri uri)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800684 throws FileNotFoundException {
Jeff Sharkey673db442015-06-11 19:30:57 -0700685 Preconditions.checkNotNull(uri, "uri");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800686 String scheme = uri.getScheme();
687 if (SCHEME_ANDROID_RESOURCE.equals(scheme)) {
688 // Note: left here to avoid breaking compatibility. May be removed
689 // with sufficient testing.
690 OpenResourceIdResult r = getResourceId(uri);
691 try {
692 InputStream stream = r.r.openRawResource(r.id);
693 return stream;
694 } catch (Resources.NotFoundException ex) {
695 throw new FileNotFoundException("Resource does not exist: " + uri);
696 }
697 } else if (SCHEME_FILE.equals(scheme)) {
698 // Note: left here to avoid breaking compatibility. May be removed
699 // with sufficient testing.
700 return new FileInputStream(uri.getPath());
701 } else {
Jeff Sharkeybd3b9022013-08-20 15:20:04 -0700702 AssetFileDescriptor fd = openAssetFileDescriptor(uri, "r", null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800703 try {
704 return fd != null ? fd.createInputStream() : null;
705 } catch (IOException e) {
706 throw new FileNotFoundException("Unable to create stream");
707 }
708 }
709 }
710
711 /**
712 * Synonym for {@link #openOutputStream(Uri, String)
713 * openOutputStream(uri, "w")}.
714 * @throws FileNotFoundException if the provided URI could not be opened.
715 */
Jeff Sharkey673db442015-06-11 19:30:57 -0700716 public final @Nullable OutputStream openOutputStream(@NonNull Uri uri)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800717 throws FileNotFoundException {
718 return openOutputStream(uri, "w");
719 }
720
721 /**
722 * Open a stream on to the content associated with a content URI. If there
723 * is no data associated with the URI, FileNotFoundException is thrown.
724 *
725 * <h5>Accepts the following URI schemes:</h5>
726 * <ul>
727 * <li>content ({@link #SCHEME_CONTENT})</li>
728 * <li>file ({@link #SCHEME_FILE})</li>
729 * </ul>
730 *
731 * <p>See {@link #openAssetFileDescriptor(Uri, String)} for more information
732 * on these schemes.
Tom O'Neill0ba1cb02010-01-08 12:53:50 -0800733 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800734 * @param uri The desired URI.
735 * @param mode May be "w", "wa", "rw", or "rwt".
736 * @return OutputStream
737 * @throws FileNotFoundException if the provided URI could not be opened.
738 * @see #openAssetFileDescriptor(Uri, String)
739 */
Jeff Sharkey673db442015-06-11 19:30:57 -0700740 public final @Nullable OutputStream openOutputStream(@NonNull Uri uri, @NonNull String mode)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800741 throws FileNotFoundException {
Jeff Sharkeybd3b9022013-08-20 15:20:04 -0700742 AssetFileDescriptor fd = openAssetFileDescriptor(uri, mode, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800743 try {
744 return fd != null ? fd.createOutputStream() : null;
745 } catch (IOException e) {
746 throw new FileNotFoundException("Unable to create stream");
747 }
748 }
749
750 /**
Dianne Hackborn23fdaf62010-08-06 12:16:55 -0700751 * Open a raw file descriptor to access data under a URI. This
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800752 * is like {@link #openAssetFileDescriptor(Uri, String)}, but uses the
753 * underlying {@link ContentProvider#openFile}
754 * ContentProvider.openFile()} method, so will <em>not</em> work with
755 * providers that return sub-sections of files. If at all possible,
756 * you should use {@link #openAssetFileDescriptor(Uri, String)}. You
757 * will receive a FileNotFoundException exception if the provider returns a
758 * sub-section of a file.
759 *
760 * <h5>Accepts the following URI schemes:</h5>
761 * <ul>
762 * <li>content ({@link #SCHEME_CONTENT})</li>
763 * <li>file ({@link #SCHEME_FILE})</li>
764 * </ul>
765 *
766 * <p>See {@link #openAssetFileDescriptor(Uri, String)} for more information
767 * on these schemes.
Jeff Sharkeybd3b9022013-08-20 15:20:04 -0700768 * <p>
769 * If opening with the exclusive "r" or "w" modes, the returned
770 * ParcelFileDescriptor could be a pipe or socket pair to enable streaming
771 * of data. Opening with the "rw" mode implies a file on disk that supports
772 * seeking. If possible, always use an exclusive mode to give the underlying
773 * {@link ContentProvider} the most flexibility.
774 * <p>
775 * If you are writing a file, and need to communicate an error to the
776 * provider, use {@link ParcelFileDescriptor#closeWithError(String)}.
Tom O'Neill0ba1cb02010-01-08 12:53:50 -0800777 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800778 * @param uri The desired URI to open.
779 * @param mode The file mode to use, as per {@link ContentProvider#openFile
780 * ContentProvider.openFile}.
781 * @return Returns a new ParcelFileDescriptor pointing to the file. You
782 * own this descriptor and are responsible for closing it when done.
Yury Zhauniarovichf9c51762012-05-12 18:39:25 +0200783 * @throws FileNotFoundException Throws FileNotFoundException if no
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800784 * file exists under the URI or the mode is invalid.
785 * @see #openAssetFileDescriptor(Uri, String)
786 */
Jeff Sharkey673db442015-06-11 19:30:57 -0700787 public final @Nullable ParcelFileDescriptor openFileDescriptor(@NonNull Uri uri,
788 @NonNull String mode) throws FileNotFoundException {
Jeff Sharkeybd3b9022013-08-20 15:20:04 -0700789 return openFileDescriptor(uri, mode, null);
790 }
791
792 /**
793 * Open a raw file descriptor to access data under a URI. This
794 * is like {@link #openAssetFileDescriptor(Uri, String)}, but uses the
795 * underlying {@link ContentProvider#openFile}
796 * ContentProvider.openFile()} method, so will <em>not</em> work with
797 * providers that return sub-sections of files. If at all possible,
798 * you should use {@link #openAssetFileDescriptor(Uri, String)}. You
799 * will receive a FileNotFoundException exception if the provider returns a
800 * sub-section of a file.
801 *
802 * <h5>Accepts the following URI schemes:</h5>
803 * <ul>
804 * <li>content ({@link #SCHEME_CONTENT})</li>
805 * <li>file ({@link #SCHEME_FILE})</li>
806 * </ul>
807 *
808 * <p>See {@link #openAssetFileDescriptor(Uri, String)} for more information
809 * on these schemes.
810 * <p>
811 * If opening with the exclusive "r" or "w" modes, the returned
812 * ParcelFileDescriptor could be a pipe or socket pair to enable streaming
813 * of data. Opening with the "rw" mode implies a file on disk that supports
814 * seeking. If possible, always use an exclusive mode to give the underlying
815 * {@link ContentProvider} the most flexibility.
816 * <p>
817 * If you are writing a file, and need to communicate an error to the
818 * provider, use {@link ParcelFileDescriptor#closeWithError(String)}.
819 *
820 * @param uri The desired URI to open.
821 * @param mode The file mode to use, as per {@link ContentProvider#openFile
822 * ContentProvider.openFile}.
Ying Wang94366312013-08-23 22:20:03 -0700823 * @param cancellationSignal A signal to cancel the operation in progress,
824 * or null if none. If the operation is canceled, then
825 * {@link OperationCanceledException} will be thrown.
Jeff Sharkeybd3b9022013-08-20 15:20:04 -0700826 * @return Returns a new ParcelFileDescriptor pointing to the file. You
827 * own this descriptor and are responsible for closing it when done.
828 * @throws FileNotFoundException Throws FileNotFoundException if no
829 * file exists under the URI or the mode is invalid.
830 * @see #openAssetFileDescriptor(Uri, String)
831 */
Jeff Sharkey673db442015-06-11 19:30:57 -0700832 public final @Nullable ParcelFileDescriptor openFileDescriptor(@NonNull Uri uri,
833 @NonNull String mode, @Nullable CancellationSignal cancellationSignal)
834 throws FileNotFoundException {
Jeff Sharkeybd3b9022013-08-20 15:20:04 -0700835 AssetFileDescriptor afd = openAssetFileDescriptor(uri, mode, cancellationSignal);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800836 if (afd == null) {
837 return null;
838 }
Tom O'Neill0ba1cb02010-01-08 12:53:50 -0800839
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800840 if (afd.getDeclaredLength() < 0) {
841 // This is a full file!
842 return afd.getParcelFileDescriptor();
843 }
Tom O'Neill0ba1cb02010-01-08 12:53:50 -0800844
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800845 // Client can't handle a sub-section of a file, so close what
846 // we got and bail with an exception.
847 try {
848 afd.close();
849 } catch (IOException e) {
850 }
Tom O'Neill0ba1cb02010-01-08 12:53:50 -0800851
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800852 throw new FileNotFoundException("Not a whole file");
853 }
854
855 /**
Dianne Hackborn23fdaf62010-08-06 12:16:55 -0700856 * Open a raw file descriptor to access data under a URI. This
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800857 * interacts with the underlying {@link ContentProvider#openAssetFile}
Gilles Debunne03f02922010-06-09 14:11:45 -0700858 * 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 -0800859 *
860 * <h5>Accepts the following URI schemes:</h5>
861 * <ul>
862 * <li>content ({@link #SCHEME_CONTENT})</li>
863 * <li>android.resource ({@link #SCHEME_ANDROID_RESOURCE})</li>
864 * <li>file ({@link #SCHEME_FILE})</li>
865 * </ul>
866 * <h5>The android.resource ({@link #SCHEME_ANDROID_RESOURCE}) Scheme</h5>
867 * <p>
868 * A Uri object can be used to reference a resource in an APK file. The
869 * Uri should be one of the following formats:
870 * <ul>
871 * <li><code>android.resource://package_name/id_number</code><br/>
872 * <code>package_name</code> is your package name as listed in your AndroidManifest.xml.
873 * For example <code>com.example.myapp</code><br/>
874 * <code>id_number</code> is the int form of the ID.<br/>
875 * The easiest way to construct this form is
876 * <pre>Uri uri = Uri.parse("android.resource://com.example.myapp/" + R.raw.my_resource");</pre>
877 * </li>
878 * <li><code>android.resource://package_name/type/name</code><br/>
879 * <code>package_name</code> is your package name as listed in your AndroidManifest.xml.
880 * For example <code>com.example.myapp</code><br/>
881 * <code>type</code> is the string form of the resource type. For example, <code>raw</code>
882 * or <code>drawable</code>.
883 * <code>name</code> is the string form of the resource name. That is, whatever the file
884 * name was in your res directory, without the type extension.
885 * The easiest way to construct this form is
886 * <pre>Uri uri = Uri.parse("android.resource://com.example.myapp/raw/my_resource");</pre>
887 * </li>
888 * </ul>
889 *
Dianne Hackborn23fdaf62010-08-06 12:16:55 -0700890 * <p>Note that if this function is called for read-only input (mode is "r")
891 * on a content: URI, it will instead call {@link #openTypedAssetFileDescriptor}
John Spurlock33900182014-01-02 11:04:18 -0500892 * for you with a MIME type of "*&#47;*". This allows such callers to benefit
Dianne Hackborn23fdaf62010-08-06 12:16:55 -0700893 * from any built-in data conversion that a provider implements.
894 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800895 * @param uri The desired URI to open.
896 * @param mode The file mode to use, as per {@link ContentProvider#openAssetFile
897 * ContentProvider.openAssetFile}.
898 * @return Returns a new ParcelFileDescriptor pointing to the file. You
899 * own this descriptor and are responsible for closing it when done.
900 * @throws FileNotFoundException Throws FileNotFoundException of no
901 * file exists under the URI or the mode is invalid.
902 */
Jeff Sharkey673db442015-06-11 19:30:57 -0700903 public final @Nullable AssetFileDescriptor openAssetFileDescriptor(@NonNull Uri uri,
904 @NonNull String mode) throws FileNotFoundException {
Jeff Sharkeybd3b9022013-08-20 15:20:04 -0700905 return openAssetFileDescriptor(uri, mode, null);
906 }
907
908 /**
909 * Open a raw file descriptor to access data under a URI. This
910 * interacts with the underlying {@link ContentProvider#openAssetFile}
911 * method of the provider associated with the given URI, to retrieve any file stored there.
912 *
913 * <h5>Accepts the following URI schemes:</h5>
914 * <ul>
915 * <li>content ({@link #SCHEME_CONTENT})</li>
916 * <li>android.resource ({@link #SCHEME_ANDROID_RESOURCE})</li>
917 * <li>file ({@link #SCHEME_FILE})</li>
918 * </ul>
919 * <h5>The android.resource ({@link #SCHEME_ANDROID_RESOURCE}) Scheme</h5>
920 * <p>
921 * A Uri object can be used to reference a resource in an APK file. The
922 * Uri should be one of the following formats:
923 * <ul>
924 * <li><code>android.resource://package_name/id_number</code><br/>
925 * <code>package_name</code> is your package name as listed in your AndroidManifest.xml.
926 * For example <code>com.example.myapp</code><br/>
927 * <code>id_number</code> is the int form of the ID.<br/>
928 * The easiest way to construct this form is
929 * <pre>Uri uri = Uri.parse("android.resource://com.example.myapp/" + R.raw.my_resource");</pre>
930 * </li>
931 * <li><code>android.resource://package_name/type/name</code><br/>
932 * <code>package_name</code> is your package name as listed in your AndroidManifest.xml.
933 * For example <code>com.example.myapp</code><br/>
934 * <code>type</code> is the string form of the resource type. For example, <code>raw</code>
935 * or <code>drawable</code>.
936 * <code>name</code> is the string form of the resource name. That is, whatever the file
937 * name was in your res directory, without the type extension.
938 * The easiest way to construct this form is
939 * <pre>Uri uri = Uri.parse("android.resource://com.example.myapp/raw/my_resource");</pre>
940 * </li>
941 * </ul>
942 *
943 * <p>Note that if this function is called for read-only input (mode is "r")
944 * on a content: URI, it will instead call {@link #openTypedAssetFileDescriptor}
John Spurlock33900182014-01-02 11:04:18 -0500945 * for you with a MIME type of "*&#47;*". This allows such callers to benefit
Jeff Sharkeybd3b9022013-08-20 15:20:04 -0700946 * from any built-in data conversion that a provider implements.
947 *
948 * @param uri The desired URI to open.
949 * @param mode The file mode to use, as per {@link ContentProvider#openAssetFile
950 * ContentProvider.openAssetFile}.
Ying Wang94366312013-08-23 22:20:03 -0700951 * @param cancellationSignal A signal to cancel the operation in progress, or null if
Jeff Sharkeybd3b9022013-08-20 15:20:04 -0700952 * none. If the operation is canceled, then
953 * {@link OperationCanceledException} will be thrown.
954 * @return Returns a new ParcelFileDescriptor pointing to the file. You
955 * own this descriptor and are responsible for closing it when done.
956 * @throws FileNotFoundException Throws FileNotFoundException of no
957 * file exists under the URI or the mode is invalid.
958 */
Jeff Sharkey673db442015-06-11 19:30:57 -0700959 public final @Nullable AssetFileDescriptor openAssetFileDescriptor(@NonNull Uri uri,
960 @NonNull String mode, @Nullable CancellationSignal cancellationSignal)
961 throws FileNotFoundException {
962 Preconditions.checkNotNull(uri, "uri");
963 Preconditions.checkNotNull(mode, "mode");
964
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800965 String scheme = uri.getScheme();
966 if (SCHEME_ANDROID_RESOURCE.equals(scheme)) {
967 if (!"r".equals(mode)) {
968 throw new FileNotFoundException("Can't write resources: " + uri);
969 }
970 OpenResourceIdResult r = getResourceId(uri);
971 try {
972 return r.r.openRawResourceFd(r.id);
973 } catch (Resources.NotFoundException ex) {
974 throw new FileNotFoundException("Resource does not exist: " + uri);
975 }
976 } else if (SCHEME_FILE.equals(scheme)) {
977 ParcelFileDescriptor pfd = ParcelFileDescriptor.open(
Adam Lesinskieb8c3f92013-09-20 14:08:25 -0700978 new File(uri.getPath()), ParcelFileDescriptor.parseMode(mode));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800979 return new AssetFileDescriptor(pfd, 0, -1);
980 } else {
Dianne Hackborn23fdaf62010-08-06 12:16:55 -0700981 if ("r".equals(mode)) {
Jeff Sharkeybd3b9022013-08-20 15:20:04 -0700982 return openTypedAssetFileDescriptor(uri, "*/*", null, cancellationSignal);
Dianne Hackborn23fdaf62010-08-06 12:16:55 -0700983 } else {
Dianne Hackborn6ae8d182012-05-23 13:12:42 -0700984 IContentProvider unstableProvider = acquireUnstableProvider(uri);
985 if (unstableProvider == null) {
986 throw new FileNotFoundException("No content provider: " + uri);
987 }
988 IContentProvider stableProvider = null;
989 AssetFileDescriptor fd = null;
990
991 try {
Jeff Sharkeybd3b9022013-08-20 15:20:04 -0700992 ICancellationSignal remoteCancellationSignal = null;
993 if (cancellationSignal != null) {
994 cancellationSignal.throwIfCanceled();
995 remoteCancellationSignal = unstableProvider.createCancellationSignal();
996 cancellationSignal.setRemote(remoteCancellationSignal);
997 }
998
Dianne Hackborn652b6d12012-05-09 18:18:40 -0700999 try {
Jeff Sharkeybd3b9022013-08-20 15:20:04 -07001000 fd = unstableProvider.openAssetFile(
1001 mPackageName, uri, mode, remoteCancellationSignal);
Dianne Hackborn652b6d12012-05-09 18:18:40 -07001002 if (fd == null) {
1003 // The provider will be released by the finally{} clause
1004 return null;
1005 }
Dianne Hackborn6ae8d182012-05-23 13:12:42 -07001006 } catch (DeadObjectException e) {
1007 // The remote process has died... but we only hold an unstable
1008 // reference though, so we might recover!!! Let's try!!!!
1009 // This is exciting!!1!!1!!!!1
1010 unstableProviderDied(unstableProvider);
1011 stableProvider = acquireProvider(uri);
1012 if (stableProvider == null) {
1013 throw new FileNotFoundException("No content provider: " + uri);
Dianne Hackborn652b6d12012-05-09 18:18:40 -07001014 }
Jeff Sharkeybd3b9022013-08-20 15:20:04 -07001015 fd = stableProvider.openAssetFile(
1016 mPackageName, uri, mode, remoteCancellationSignal);
Dianne Hackborn6ae8d182012-05-23 13:12:42 -07001017 if (fd == null) {
1018 // The provider will be released by the finally{} clause
1019 return null;
Dianne Hackborn652b6d12012-05-09 18:18:40 -07001020 }
Dianne Hackborn23fdaf62010-08-06 12:16:55 -07001021 }
Dianne Hackborn6ae8d182012-05-23 13:12:42 -07001022
1023 if (stableProvider == null) {
1024 stableProvider = acquireProvider(uri);
1025 }
1026 releaseUnstableProvider(unstableProvider);
Koji Fukuif783c022014-02-07 15:01:36 +09001027 unstableProvider = null;
Dianne Hackborn6ae8d182012-05-23 13:12:42 -07001028 ParcelFileDescriptor pfd = new ParcelFileDescriptorInner(
1029 fd.getParcelFileDescriptor(), stableProvider);
1030
1031 // Success! Don't release the provider when exiting, let
1032 // ParcelFileDescriptorInner do that when it is closed.
1033 stableProvider = null;
1034
1035 return new AssetFileDescriptor(pfd, fd.getStartOffset(),
1036 fd.getDeclaredLength());
1037
1038 } catch (RemoteException e) {
1039 // Whatever, whatever, we'll go away.
1040 throw new FileNotFoundException(
1041 "Failed opening content provider: " + uri);
1042 } catch (FileNotFoundException e) {
1043 throw e;
1044 } finally {
Jeff Sharkeybd3b9022013-08-20 15:20:04 -07001045 if (cancellationSignal != null) {
1046 cancellationSignal.setRemote(null);
1047 }
Dianne Hackborn6ae8d182012-05-23 13:12:42 -07001048 if (stableProvider != null) {
1049 releaseProvider(stableProvider);
1050 }
1051 if (unstableProvider != null) {
1052 releaseUnstableProvider(unstableProvider);
1053 }
Dianne Hackborn23fdaf62010-08-06 12:16:55 -07001054 }
1055 }
1056 }
1057 }
1058
1059 /**
1060 * Open a raw file descriptor to access (potentially type transformed)
1061 * data from a "content:" URI. This interacts with the underlying
1062 * {@link ContentProvider#openTypedAssetFile} method of the provider
1063 * associated with the given URI, to retrieve retrieve any appropriate
1064 * data stream for the data stored there.
1065 *
1066 * <p>Unlike {@link #openAssetFileDescriptor}, this function only works
1067 * with "content:" URIs, because content providers are the only facility
1068 * with an associated MIME type to ensure that the returned data stream
1069 * is of the desired type.
1070 *
1071 * <p>All text/* streams are encoded in UTF-8.
1072 *
1073 * @param uri The desired URI to open.
1074 * @param mimeType The desired MIME type of the returned data. This can
John Spurlock33900182014-01-02 11:04:18 -05001075 * be a pattern such as *&#47;*, which will allow the content provider to
Dianne Hackborn23fdaf62010-08-06 12:16:55 -07001076 * select a type, though there is no way for you to determine what type
1077 * it is returning.
1078 * @param opts Additional provider-dependent options.
1079 * @return Returns a new ParcelFileDescriptor from which you can read the
1080 * data stream from the provider. Note that this may be a pipe, meaning
1081 * you can't seek in it. The only seek you should do is if the
1082 * AssetFileDescriptor contains an offset, to move to that offset before
1083 * reading. You own this descriptor and are responsible for closing it when done.
1084 * @throws FileNotFoundException Throws FileNotFoundException of no
1085 * data of the desired type exists under the URI.
1086 */
Jeff Sharkey673db442015-06-11 19:30:57 -07001087 public final @Nullable AssetFileDescriptor openTypedAssetFileDescriptor(@NonNull Uri uri,
1088 @NonNull String mimeType, @Nullable Bundle opts) throws FileNotFoundException {
Jeff Sharkeybd3b9022013-08-20 15:20:04 -07001089 return openTypedAssetFileDescriptor(uri, mimeType, opts, null);
1090 }
1091
1092 /**
1093 * Open a raw file descriptor to access (potentially type transformed)
1094 * data from a "content:" URI. This interacts with the underlying
1095 * {@link ContentProvider#openTypedAssetFile} method of the provider
1096 * associated with the given URI, to retrieve retrieve any appropriate
1097 * data stream for the data stored there.
1098 *
1099 * <p>Unlike {@link #openAssetFileDescriptor}, this function only works
1100 * with "content:" URIs, because content providers are the only facility
1101 * with an associated MIME type to ensure that the returned data stream
1102 * is of the desired type.
1103 *
1104 * <p>All text/* streams are encoded in UTF-8.
1105 *
1106 * @param uri The desired URI to open.
1107 * @param mimeType The desired MIME type of the returned data. This can
John Spurlock33900182014-01-02 11:04:18 -05001108 * be a pattern such as *&#47;*, which will allow the content provider to
Jeff Sharkeybd3b9022013-08-20 15:20:04 -07001109 * select a type, though there is no way for you to determine what type
1110 * it is returning.
1111 * @param opts Additional provider-dependent options.
Ying Wang94366312013-08-23 22:20:03 -07001112 * @param cancellationSignal A signal to cancel the operation in progress,
1113 * or null if none. If the operation is canceled, then
1114 * {@link OperationCanceledException} will be thrown.
Jeff Sharkeybd3b9022013-08-20 15:20:04 -07001115 * @return Returns a new ParcelFileDescriptor from which you can read the
1116 * data stream from the provider. Note that this may be a pipe, meaning
1117 * you can't seek in it. The only seek you should do is if the
1118 * AssetFileDescriptor contains an offset, to move to that offset before
1119 * reading. You own this descriptor and are responsible for closing it when done.
1120 * @throws FileNotFoundException Throws FileNotFoundException of no
1121 * data of the desired type exists under the URI.
1122 */
Jeff Sharkey673db442015-06-11 19:30:57 -07001123 public final @Nullable AssetFileDescriptor openTypedAssetFileDescriptor(@NonNull Uri uri,
1124 @NonNull String mimeType, @Nullable Bundle opts,
1125 @Nullable CancellationSignal cancellationSignal) throws FileNotFoundException {
1126 Preconditions.checkNotNull(uri, "uri");
1127 Preconditions.checkNotNull(mimeType, "mimeType");
1128
Dianne Hackborn6ae8d182012-05-23 13:12:42 -07001129 IContentProvider unstableProvider = acquireUnstableProvider(uri);
1130 if (unstableProvider == null) {
1131 throw new FileNotFoundException("No content provider: " + uri);
1132 }
1133 IContentProvider stableProvider = null;
1134 AssetFileDescriptor fd = null;
1135
1136 try {
Jeff Sharkeybd3b9022013-08-20 15:20:04 -07001137 ICancellationSignal remoteCancellationSignal = null;
1138 if (cancellationSignal != null) {
1139 cancellationSignal.throwIfCanceled();
1140 remoteCancellationSignal = unstableProvider.createCancellationSignal();
1141 cancellationSignal.setRemote(remoteCancellationSignal);
1142 }
1143
Dianne Hackborn652b6d12012-05-09 18:18:40 -07001144 try {
Jeff Sharkeybd3b9022013-08-20 15:20:04 -07001145 fd = unstableProvider.openTypedAssetFile(
1146 mPackageName, uri, mimeType, opts, remoteCancellationSignal);
Dianne Hackborn652b6d12012-05-09 18:18:40 -07001147 if (fd == null) {
1148 // The provider will be released by the finally{} clause
1149 return null;
1150 }
Dianne Hackborn6ae8d182012-05-23 13:12:42 -07001151 } catch (DeadObjectException e) {
1152 // The remote process has died... but we only hold an unstable
1153 // reference though, so we might recover!!! Let's try!!!!
1154 // This is exciting!!1!!1!!!!1
1155 unstableProviderDied(unstableProvider);
1156 stableProvider = acquireProvider(uri);
1157 if (stableProvider == null) {
1158 throw new FileNotFoundException("No content provider: " + uri);
Dianne Hackborn652b6d12012-05-09 18:18:40 -07001159 }
Jeff Sharkeybd3b9022013-08-20 15:20:04 -07001160 fd = stableProvider.openTypedAssetFile(
1161 mPackageName, uri, mimeType, opts, remoteCancellationSignal);
Dianne Hackborn6ae8d182012-05-23 13:12:42 -07001162 if (fd == null) {
1163 // The provider will be released by the finally{} clause
1164 return null;
Dianne Hackborn652b6d12012-05-09 18:18:40 -07001165 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001166 }
Dianne Hackborn6ae8d182012-05-23 13:12:42 -07001167
1168 if (stableProvider == null) {
1169 stableProvider = acquireProvider(uri);
1170 }
1171 releaseUnstableProvider(unstableProvider);
Koji Fukuif783c022014-02-07 15:01:36 +09001172 unstableProvider = null;
Dianne Hackborn6ae8d182012-05-23 13:12:42 -07001173 ParcelFileDescriptor pfd = new ParcelFileDescriptorInner(
1174 fd.getParcelFileDescriptor(), stableProvider);
1175
1176 // Success! Don't release the provider when exiting, let
1177 // ParcelFileDescriptorInner do that when it is closed.
1178 stableProvider = null;
1179
1180 return new AssetFileDescriptor(pfd, fd.getStartOffset(),
1181 fd.getDeclaredLength());
1182
1183 } catch (RemoteException e) {
1184 // Whatever, whatever, we'll go away.
1185 throw new FileNotFoundException(
1186 "Failed opening content provider: " + uri);
1187 } catch (FileNotFoundException e) {
1188 throw e;
1189 } finally {
Jeff Sharkeybd3b9022013-08-20 15:20:04 -07001190 if (cancellationSignal != null) {
1191 cancellationSignal.setRemote(null);
1192 }
Dianne Hackborn6ae8d182012-05-23 13:12:42 -07001193 if (stableProvider != null) {
1194 releaseProvider(stableProvider);
1195 }
1196 if (unstableProvider != null) {
1197 releaseUnstableProvider(unstableProvider);
1198 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001199 }
1200 }
1201
Bjorn Bringert4c87a3f2009-09-16 15:59:37 +01001202 /**
1203 * A resource identified by the {@link Resources} that contains it, and a resource id.
1204 *
1205 * @hide
1206 */
1207 public class OpenResourceIdResult {
1208 public Resources r;
1209 public int id;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001210 }
Bjorn Bringert4c87a3f2009-09-16 15:59:37 +01001211
1212 /**
1213 * Resolves an android.resource URI to a {@link Resources} and a resource id.
1214 *
1215 * @hide
1216 */
1217 public OpenResourceIdResult getResourceId(Uri uri) throws FileNotFoundException {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001218 String authority = uri.getAuthority();
1219 Resources r;
1220 if (TextUtils.isEmpty(authority)) {
1221 throw new FileNotFoundException("No authority: " + uri);
1222 } else {
1223 try {
1224 r = mContext.getPackageManager().getResourcesForApplication(authority);
1225 } catch (NameNotFoundException ex) {
1226 throw new FileNotFoundException("No package found for authority: " + uri);
1227 }
1228 }
1229 List<String> path = uri.getPathSegments();
1230 if (path == null) {
1231 throw new FileNotFoundException("No path: " + uri);
1232 }
1233 int len = path.size();
1234 int id;
1235 if (len == 1) {
1236 try {
1237 id = Integer.parseInt(path.get(0));
1238 } catch (NumberFormatException e) {
1239 throw new FileNotFoundException("Single path segment is not a resource ID: " + uri);
1240 }
1241 } else if (len == 2) {
1242 id = r.getIdentifier(path.get(1), path.get(0), authority);
1243 } else {
1244 throw new FileNotFoundException("More than two path segments: " + uri);
1245 }
1246 if (id == 0) {
1247 throw new FileNotFoundException("No resource found for: " + uri);
1248 }
1249 OpenResourceIdResult res = new OpenResourceIdResult();
1250 res.r = r;
1251 res.id = id;
1252 return res;
1253 }
Tom O'Neill0ba1cb02010-01-08 12:53:50 -08001254
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001255 /**
1256 * Inserts a row into a table at the given URL.
1257 *
1258 * If the content provider supports transactions the insertion will be atomic.
1259 *
1260 * @param url The URL of the table to insert into.
1261 * @param values The initial values for the newly inserted row. The key is the column name for
1262 * the field. Passing an empty ContentValues will create an empty row.
1263 * @return the URL of the newly created row.
1264 */
Tor Norbye788fc2b2015-07-05 16:10:42 -07001265 public final @Nullable Uri insert(@RequiresPermission.Write @NonNull Uri url,
1266 @Nullable ContentValues values) {
Jeff Sharkey673db442015-06-11 19:30:57 -07001267 Preconditions.checkNotNull(url, "url");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001268 IContentProvider provider = acquireProvider(url);
1269 if (provider == null) {
1270 throw new IllegalArgumentException("Unknown URL " + url);
1271 }
1272 try {
Brad Fitzpatrickd72f7182010-02-11 17:07:51 -08001273 long startTime = SystemClock.uptimeMillis();
Dianne Hackborn35654b62013-01-14 17:38:02 -08001274 Uri createdRow = provider.insert(mPackageName, url, values);
Brad Fitzpatrickd72f7182010-02-11 17:07:51 -08001275 long durationMillis = SystemClock.uptimeMillis() - startTime;
Brad Fitzpatricka63730d2010-02-07 22:25:34 -08001276 maybeLogUpdateToEventLog(durationMillis, url, "insert", null /* where */);
1277 return createdRow;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001278 } catch (RemoteException e) {
Brad Fitzpatrick534c84c2011-01-12 14:06:30 -08001279 // Arbitrary and not worth documenting, as Activity
1280 // Manager will kill this process shortly anyway.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001281 return null;
1282 } finally {
1283 releaseProvider(provider);
1284 }
1285 }
1286
Fred Quintana89437372009-05-15 15:10:40 -07001287 /**
Fred Quintana89437372009-05-15 15:10:40 -07001288 * Applies each of the {@link ContentProviderOperation} objects and returns an array
1289 * of their results. Passes through OperationApplicationException, which may be thrown
1290 * by the call to {@link ContentProviderOperation#apply}.
1291 * If all the applications succeed then a {@link ContentProviderResult} array with the
1292 * same number of elements as the operations will be returned. It is implementation-specific
1293 * how many, if any, operations will have been successfully applied if a call to
1294 * apply results in a {@link OperationApplicationException}.
1295 * @param authority the authority of the ContentProvider to which this batch should be applied
1296 * @param operations the operations to apply
1297 * @return the results of the applications
1298 * @throws OperationApplicationException thrown if an application fails.
1299 * See {@link ContentProviderOperation#apply} for more information.
1300 * @throws RemoteException thrown if a RemoteException is encountered while attempting
1301 * to communicate with a remote provider.
1302 */
Jeff Sharkey673db442015-06-11 19:30:57 -07001303 public @NonNull ContentProviderResult[] applyBatch(@NonNull String authority,
1304 @NonNull ArrayList<ContentProviderOperation> operations)
1305 throws RemoteException, OperationApplicationException {
1306 Preconditions.checkNotNull(authority, "authority");
1307 Preconditions.checkNotNull(operations, "operations");
Fred Quintana89437372009-05-15 15:10:40 -07001308 ContentProviderClient provider = acquireContentProviderClient(authority);
Fred Quintana6a8d5332009-05-07 17:35:38 -07001309 if (provider == null) {
Fred Quintana89437372009-05-15 15:10:40 -07001310 throw new IllegalArgumentException("Unknown authority " + authority);
Fred Quintana6a8d5332009-05-07 17:35:38 -07001311 }
1312 try {
Fred Quintana89437372009-05-15 15:10:40 -07001313 return provider.applyBatch(operations);
Fred Quintana6a8d5332009-05-07 17:35:38 -07001314 } finally {
1315 provider.release();
1316 }
1317 }
1318
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001319 /**
1320 * Inserts multiple rows into a table at the given URL.
1321 *
1322 * This function make no guarantees about the atomicity of the insertions.
1323 *
1324 * @param url The URL of the table to insert into.
1325 * @param values The initial values for the newly inserted rows. The key is the column name for
1326 * the field. Passing null will create an empty row.
1327 * @return the number of newly created rows.
1328 */
Tor Norbye788fc2b2015-07-05 16:10:42 -07001329 public final int bulkInsert(@RequiresPermission.Write @NonNull Uri url,
1330 @NonNull ContentValues[] values) {
Jeff Sharkey673db442015-06-11 19:30:57 -07001331 Preconditions.checkNotNull(url, "url");
1332 Preconditions.checkNotNull(values, "values");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001333 IContentProvider provider = acquireProvider(url);
1334 if (provider == null) {
1335 throw new IllegalArgumentException("Unknown URL " + url);
1336 }
1337 try {
Brad Fitzpatrickd72f7182010-02-11 17:07:51 -08001338 long startTime = SystemClock.uptimeMillis();
Dianne Hackborn35654b62013-01-14 17:38:02 -08001339 int rowsCreated = provider.bulkInsert(mPackageName, url, values);
Brad Fitzpatrickd72f7182010-02-11 17:07:51 -08001340 long durationMillis = SystemClock.uptimeMillis() - startTime;
Brad Fitzpatricka63730d2010-02-07 22:25:34 -08001341 maybeLogUpdateToEventLog(durationMillis, url, "bulkinsert", null /* where */);
1342 return rowsCreated;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001343 } catch (RemoteException e) {
Brad Fitzpatrick534c84c2011-01-12 14:06:30 -08001344 // Arbitrary and not worth documenting, as Activity
1345 // Manager will kill this process shortly anyway.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001346 return 0;
1347 } finally {
1348 releaseProvider(provider);
1349 }
1350 }
1351
1352 /**
1353 * Deletes row(s) specified by a content URI.
1354 *
1355 * If the content provider supports transactions, the deletion will be atomic.
1356 *
1357 * @param url The URL of the row to delete.
1358 * @param where A filter to apply to rows before deleting, formatted as an SQL WHERE clause
1359 (excluding the WHERE itself).
1360 * @return The number of rows deleted.
1361 */
Tor Norbye788fc2b2015-07-05 16:10:42 -07001362 public final int delete(@RequiresPermission.Write @NonNull Uri url, @Nullable String where,
Jeff Sharkey673db442015-06-11 19:30:57 -07001363 @Nullable String[] selectionArgs) {
1364 Preconditions.checkNotNull(url, "url");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001365 IContentProvider provider = acquireProvider(url);
1366 if (provider == null) {
1367 throw new IllegalArgumentException("Unknown URL " + url);
1368 }
1369 try {
Brad Fitzpatrickd72f7182010-02-11 17:07:51 -08001370 long startTime = SystemClock.uptimeMillis();
Dianne Hackborn35654b62013-01-14 17:38:02 -08001371 int rowsDeleted = provider.delete(mPackageName, url, where, selectionArgs);
Brad Fitzpatrickd72f7182010-02-11 17:07:51 -08001372 long durationMillis = SystemClock.uptimeMillis() - startTime;
Brad Fitzpatricka63730d2010-02-07 22:25:34 -08001373 maybeLogUpdateToEventLog(durationMillis, url, "delete", where);
1374 return rowsDeleted;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001375 } catch (RemoteException e) {
Brad Fitzpatrick534c84c2011-01-12 14:06:30 -08001376 // Arbitrary and not worth documenting, as Activity
1377 // Manager will kill this process shortly anyway.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001378 return -1;
1379 } finally {
1380 releaseProvider(provider);
1381 }
1382 }
1383
1384 /**
1385 * Update row(s) in a content URI.
1386 *
1387 * If the content provider supports transactions the update will be atomic.
1388 *
1389 * @param uri The URI to modify.
1390 * @param values The new field values. The key is the column name for the field.
1391 A null value will remove an existing field value.
Omari Stephensd2a2daa2010-03-10 18:53:54 -08001392 * @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 -08001393 (excluding the WHERE itself).
Brad Fitzpatrick534c84c2011-01-12 14:06:30 -08001394 * @return the number of rows updated.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001395 * @throws NullPointerException if uri or values are null
1396 */
Tor Norbye788fc2b2015-07-05 16:10:42 -07001397 public final int update(@RequiresPermission.Write @NonNull Uri uri,
1398 @Nullable ContentValues values, @Nullable String where,
1399 @Nullable String[] selectionArgs) {
Jeff Sharkey673db442015-06-11 19:30:57 -07001400 Preconditions.checkNotNull(uri, "uri");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001401 IContentProvider provider = acquireProvider(uri);
1402 if (provider == null) {
1403 throw new IllegalArgumentException("Unknown URI " + uri);
1404 }
1405 try {
Brad Fitzpatrickd72f7182010-02-11 17:07:51 -08001406 long startTime = SystemClock.uptimeMillis();
Dianne Hackborn35654b62013-01-14 17:38:02 -08001407 int rowsUpdated = provider.update(mPackageName, uri, values, where, selectionArgs);
Brad Fitzpatrickd72f7182010-02-11 17:07:51 -08001408 long durationMillis = SystemClock.uptimeMillis() - startTime;
Brad Fitzpatricka63730d2010-02-07 22:25:34 -08001409 maybeLogUpdateToEventLog(durationMillis, uri, "update", where);
1410 return rowsUpdated;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001411 } catch (RemoteException e) {
Brad Fitzpatrick534c84c2011-01-12 14:06:30 -08001412 // Arbitrary and not worth documenting, as Activity
1413 // Manager will kill this process shortly anyway.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001414 return -1;
1415 } finally {
1416 releaseProvider(provider);
1417 }
1418 }
1419
1420 /**
Ken Wakasaf76a50c2012-03-09 19:56:35 +09001421 * Call a provider-defined method. This can be used to implement
Brad Fitzpatrick534c84c2011-01-12 14:06:30 -08001422 * read or write interfaces which are cheaper than using a Cursor and/or
1423 * do not fit into the traditional table model.
1424 *
1425 * @param method provider-defined method name to call. Opaque to
1426 * framework, but must be non-null.
1427 * @param arg provider-defined String argument. May be null.
1428 * @param extras provider-defined Bundle argument. May be null.
1429 * @return a result Bundle, possibly null. Will be null if the ContentProvider
1430 * does not implement call.
1431 * @throws NullPointerException if uri or method is null
1432 * @throws IllegalArgumentException if uri is not known
1433 */
Jeff Sharkey673db442015-06-11 19:30:57 -07001434 public final @Nullable Bundle call(@NonNull Uri uri, @NonNull String method,
1435 @Nullable String arg, @Nullable Bundle extras) {
1436 Preconditions.checkNotNull(uri, "uri");
1437 Preconditions.checkNotNull(method, "method");
Brad Fitzpatrick534c84c2011-01-12 14:06:30 -08001438 IContentProvider provider = acquireProvider(uri);
1439 if (provider == null) {
1440 throw new IllegalArgumentException("Unknown URI " + uri);
1441 }
1442 try {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06001443 final Bundle res = provider.call(mPackageName, method, arg, extras);
1444 Bundle.setDefusable(res, true);
1445 return res;
Brad Fitzpatrick534c84c2011-01-12 14:06:30 -08001446 } catch (RemoteException e) {
1447 // Arbitrary and not worth documenting, as Activity
1448 // Manager will kill this process shortly anyway.
1449 return null;
1450 } finally {
1451 releaseProvider(provider);
1452 }
1453 }
1454
1455 /**
Dianne Hackborncca1f0e2010-09-26 18:34:53 -07001456 * Returns the content provider for the given content URI.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001457 *
1458 * @param uri The URI to a content provider
1459 * @return The ContentProvider for the given URI, or null if no content provider is found.
1460 * @hide
1461 */
Dianne Hackborncca1f0e2010-09-26 18:34:53 -07001462 public final IContentProvider acquireProvider(Uri uri) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001463 if (!SCHEME_CONTENT.equals(uri.getScheme())) {
1464 return null;
1465 }
Yury Zhauniarovichf9c51762012-05-12 18:39:25 +02001466 final String auth = uri.getAuthority();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001467 if (auth != null) {
Yury Zhauniarovichf9c51762012-05-12 18:39:25 +02001468 return acquireProvider(mContext, auth);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001469 }
1470 return null;
1471 }
1472
1473 /**
Dianne Hackborncca1f0e2010-09-26 18:34:53 -07001474 * Returns the content provider for the given content URI if the process
1475 * already has a reference on it.
1476 *
1477 * @param uri The URI to a content provider
1478 * @return The ContentProvider for the given URI, or null if no content provider is found.
1479 * @hide
1480 */
1481 public final IContentProvider acquireExistingProvider(Uri uri) {
1482 if (!SCHEME_CONTENT.equals(uri.getScheme())) {
1483 return null;
1484 }
Yury Zhauniarovichf9c51762012-05-12 18:39:25 +02001485 final String auth = uri.getAuthority();
Dianne Hackborncca1f0e2010-09-26 18:34:53 -07001486 if (auth != null) {
Yury Zhauniarovichf9c51762012-05-12 18:39:25 +02001487 return acquireExistingProvider(mContext, auth);
Dianne Hackborncca1f0e2010-09-26 18:34:53 -07001488 }
1489 return null;
1490 }
1491
1492 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001493 * @hide
1494 */
1495 public final IContentProvider acquireProvider(String name) {
Brad Fitzpatrick1877d012010-03-04 17:48:13 -08001496 if (name == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001497 return null;
1498 }
1499 return acquireProvider(mContext, name);
1500 }
1501
1502 /**
Dianne Hackborn652b6d12012-05-09 18:18:40 -07001503 * Returns the content provider for the given content URI.
1504 *
1505 * @param uri The URI to a content provider
1506 * @return The ContentProvider for the given URI, or null if no content provider is found.
1507 * @hide
1508 */
1509 public final IContentProvider acquireUnstableProvider(Uri uri) {
1510 if (!SCHEME_CONTENT.equals(uri.getScheme())) {
1511 return null;
1512 }
1513 String auth = uri.getAuthority();
1514 if (auth != null) {
1515 return acquireUnstableProvider(mContext, uri.getAuthority());
1516 }
1517 return null;
1518 }
1519
1520 /**
1521 * @hide
1522 */
1523 public final IContentProvider acquireUnstableProvider(String name) {
1524 if (name == null) {
1525 return null;
1526 }
Dianne Hackborn6ae8d182012-05-23 13:12:42 -07001527 return acquireUnstableProvider(mContext, name);
Dianne Hackborn652b6d12012-05-09 18:18:40 -07001528 }
1529
1530 /**
Fred Quintana718d8a22009-04-29 17:53:20 -07001531 * Returns a {@link ContentProviderClient} that is associated with the {@link ContentProvider}
1532 * that services the content at uri, starting the provider if necessary. Returns
1533 * null if there is no provider associated wih the uri. The caller must indicate that they are
1534 * done with the provider by calling {@link ContentProviderClient#release} which will allow
1535 * the system to release the provider it it determines that there is no other reason for
1536 * keeping it active.
1537 * @param uri specifies which provider should be acquired
1538 * @return a {@link ContentProviderClient} that is associated with the {@link ContentProvider}
1539 * that services the content at uri or null if there isn't one.
1540 */
Jeff Sharkey673db442015-06-11 19:30:57 -07001541 public final @Nullable ContentProviderClient acquireContentProviderClient(@NonNull Uri uri) {
1542 Preconditions.checkNotNull(uri, "uri");
Fred Quintana718d8a22009-04-29 17:53:20 -07001543 IContentProvider provider = acquireProvider(uri);
1544 if (provider != null) {
Dianne Hackborn652b6d12012-05-09 18:18:40 -07001545 return new ContentProviderClient(this, provider, true);
Fred Quintana718d8a22009-04-29 17:53:20 -07001546 }
Fred Quintana718d8a22009-04-29 17:53:20 -07001547 return null;
1548 }
1549
1550 /**
1551 * Returns a {@link ContentProviderClient} that is associated with the {@link ContentProvider}
1552 * with the authority of name, starting the provider if necessary. Returns
1553 * null if there is no provider associated wih the uri. The caller must indicate that they are
1554 * done with the provider by calling {@link ContentProviderClient#release} which will allow
1555 * the system to release the provider it it determines that there is no other reason for
1556 * keeping it active.
1557 * @param name specifies which provider should be acquired
1558 * @return a {@link ContentProviderClient} that is associated with the {@link ContentProvider}
1559 * with the authority of name or null if there isn't one.
1560 */
Jeff Sharkey673db442015-06-11 19:30:57 -07001561 public final @Nullable ContentProviderClient acquireContentProviderClient(
1562 @NonNull String name) {
1563 Preconditions.checkNotNull(name, "name");
Fred Quintana718d8a22009-04-29 17:53:20 -07001564 IContentProvider provider = acquireProvider(name);
1565 if (provider != null) {
Dianne Hackborn652b6d12012-05-09 18:18:40 -07001566 return new ContentProviderClient(this, provider, true);
1567 }
1568
1569 return null;
1570 }
1571
1572 /**
1573 * Like {@link #acquireContentProviderClient(Uri)}, but for use when you do
1574 * not trust the stability of the target content provider. This turns off
1575 * the mechanism in the platform clean up processes that are dependent on
1576 * a content provider if that content provider's process goes away. Normally
1577 * you can safely assume that once you have acquired a provider, you can freely
1578 * use it as needed and it won't disappear, even if your process is in the
1579 * background. If using this method, you need to take care to deal with any
1580 * failures when communicating with the provider, and be sure to close it
Dianne Hackborn6ae8d182012-05-23 13:12:42 -07001581 * so that it can be re-opened later. In particular, catching a
1582 * {@link android.os.DeadObjectException} from the calls there will let you
1583 * know that the content provider has gone away; at that point the current
1584 * ContentProviderClient object is invalid, and you should release it. You
1585 * can acquire a new one if you would like to try to restart the provider
1586 * and perform new operations on it.
Dianne Hackborn652b6d12012-05-09 18:18:40 -07001587 */
Jeff Sharkey673db442015-06-11 19:30:57 -07001588 public final @Nullable ContentProviderClient acquireUnstableContentProviderClient(
1589 @NonNull Uri uri) {
1590 Preconditions.checkNotNull(uri, "uri");
Dianne Hackborn6ae8d182012-05-23 13:12:42 -07001591 IContentProvider provider = acquireUnstableProvider(uri);
Dianne Hackborn652b6d12012-05-09 18:18:40 -07001592 if (provider != null) {
1593 return new ContentProviderClient(this, provider, false);
1594 }
1595
1596 return null;
1597 }
1598
1599 /**
1600 * Like {@link #acquireContentProviderClient(String)}, but for use when you do
1601 * not trust the stability of the target content provider. This turns off
1602 * the mechanism in the platform clean up processes that are dependent on
1603 * a content provider if that content provider's process goes away. Normally
1604 * you can safely assume that once you have acquired a provider, you can freely
1605 * use it as needed and it won't disappear, even if your process is in the
1606 * background. If using this method, you need to take care to deal with any
1607 * failures when communicating with the provider, and be sure to close it
Dianne Hackborn6ae8d182012-05-23 13:12:42 -07001608 * so that it can be re-opened later. In particular, catching a
1609 * {@link android.os.DeadObjectException} from the calls there will let you
1610 * know that the content provider has gone away; at that point the current
1611 * ContentProviderClient object is invalid, and you should release it. You
1612 * can acquire a new one if you would like to try to restart the provider
1613 * and perform new operations on it.
Dianne Hackborn652b6d12012-05-09 18:18:40 -07001614 */
Jeff Sharkey673db442015-06-11 19:30:57 -07001615 public final @Nullable ContentProviderClient acquireUnstableContentProviderClient(
1616 @NonNull String name) {
1617 Preconditions.checkNotNull(name, "name");
Dianne Hackborn6ae8d182012-05-23 13:12:42 -07001618 IContentProvider provider = acquireUnstableProvider(name);
Dianne Hackborn652b6d12012-05-09 18:18:40 -07001619 if (provider != null) {
1620 return new ContentProviderClient(this, provider, false);
Fred Quintana718d8a22009-04-29 17:53:20 -07001621 }
1622
1623 return null;
1624 }
1625
1626 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001627 * Register an observer class that gets callbacks when data identified by a
1628 * given content URI changes.
1629 *
1630 * @param uri The URI to watch for changes. This can be a specific row URI, or a base URI
1631 * for a whole class of content.
Dianne Hackborn1a30bd92016-01-11 11:05:00 -08001632 * @param notifyForDescendants When false, the observer will be notified whenever a
Jeff Brown143739c2015-06-02 14:52:50 -07001633 * change occurs to the exact URI specified by <code>uri</code> or to one of the
1634 * URI's ancestors in the path hierarchy. When true, the observer will also be notified
1635 * whenever a change occurs to the URI's descendants in the path hierarchy.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001636 * @param observer The object that receives callbacks when changes occur.
1637 * @see #unregisterContentObserver
1638 */
Dianne Hackborn1a30bd92016-01-11 11:05:00 -08001639 public final void registerContentObserver(@NonNull Uri uri, boolean notifyForDescendants,
Jeff Sharkey673db442015-06-11 19:30:57 -07001640 @NonNull ContentObserver observer) {
1641 Preconditions.checkNotNull(uri, "uri");
1642 Preconditions.checkNotNull(observer, "observer");
Benjamin Franzadea1912015-06-19 16:03:38 +01001643 registerContentObserver(
1644 ContentProvider.getUriWithoutUserId(uri),
Dianne Hackborn1a30bd92016-01-11 11:05:00 -08001645 notifyForDescendants,
Benjamin Franzadea1912015-06-19 16:03:38 +01001646 observer,
1647 ContentProvider.getUserIdFromUri(uri, UserHandle.myUserId()));
Christopher Tate16aa9732012-09-17 16:23:44 -07001648 }
1649
1650 /** @hide - designated user version */
1651 public final void registerContentObserver(Uri uri, boolean notifyForDescendents,
Jeff Sharkey8588bc12016-01-06 16:47:42 -07001652 ContentObserver observer, @UserIdInt int userHandle) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001653 try {
Dianne Hackborn231cc602009-04-27 17:10:36 -07001654 getContentService().registerContentObserver(uri, notifyForDescendents,
Christopher Tate16aa9732012-09-17 16:23:44 -07001655 observer.getContentObserver(), userHandle);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001656 } catch (RemoteException e) {
1657 }
1658 }
1659
1660 /**
1661 * Unregisters a change observer.
1662 *
1663 * @param observer The previously registered observer that is no longer needed.
1664 * @see #registerContentObserver
1665 */
Jeff Sharkey673db442015-06-11 19:30:57 -07001666 public final void unregisterContentObserver(@NonNull ContentObserver observer) {
1667 Preconditions.checkNotNull(observer, "observer");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001668 try {
1669 IContentObserver contentObserver = observer.releaseContentObserver();
1670 if (contentObserver != null) {
Dianne Hackborn231cc602009-04-27 17:10:36 -07001671 getContentService().unregisterContentObserver(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001672 contentObserver);
1673 }
1674 } catch (RemoteException e) {
1675 }
1676 }
1677
1678 /**
Steve Pomeroyd7a1aad2012-01-18 16:15:59 -05001679 * Notify registered observers that a row was updated and attempt to sync changes
1680 * to the network.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001681 * To register, call {@link #registerContentObserver(android.net.Uri , boolean, android.database.ContentObserver) registerContentObserver()}.
1682 * By default, CursorAdapter objects will get this notification.
1683 *
Jeff Brown86de0592012-01-23 13:01:18 -08001684 * @param uri The uri of the content that was changed.
1685 * @param observer The observer that originated the change, may be <code>null</null>.
1686 * The observer that originated the change will only receive the notification if it
1687 * has requested to receive self-change notifications by implementing
1688 * {@link ContentObserver#deliverSelfNotifications()} to return true.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001689 */
Jeff Sharkey673db442015-06-11 19:30:57 -07001690 public void notifyChange(@NonNull Uri uri, @Nullable ContentObserver observer) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001691 notifyChange(uri, observer, true /* sync to network */);
1692 }
1693
1694 /**
1695 * Notify registered observers that a row was updated.
1696 * To register, call {@link #registerContentObserver(android.net.Uri , boolean, android.database.ContentObserver) registerContentObserver()}.
1697 * By default, CursorAdapter objects will get this notification.
Steve Pomeroyd7a1aad2012-01-18 16:15:59 -05001698 * If syncToNetwork is true, this will attempt to schedule a local sync using the sync
1699 * adapter that's registered for the authority of the provided uri. No account will be
1700 * passed to the sync adapter, so all matching accounts will be synchronized.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001701 *
Jeff Brown86de0592012-01-23 13:01:18 -08001702 * @param uri The uri of the content that was changed.
1703 * @param observer The observer that originated the change, may be <code>null</null>.
1704 * The observer that originated the change will only receive the notification if it
1705 * has requested to receive self-change notifications by implementing
1706 * {@link ContentObserver#deliverSelfNotifications()} to return true.
Dianne Hackborn141f11c2016-04-05 15:46:12 -07001707 * @param syncToNetwork If true, same as {@link #NOTIFY_SYNC_TO_NETWORK}.
Steve Pomeroyd7a1aad2012-01-18 16:15:59 -05001708 * @see #requestSync(android.accounts.Account, String, android.os.Bundle)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001709 */
Jeff Sharkey673db442015-06-11 19:30:57 -07001710 public void notifyChange(@NonNull Uri uri, @Nullable ContentObserver observer,
1711 boolean syncToNetwork) {
1712 Preconditions.checkNotNull(uri, "uri");
Benjamin Franzadea1912015-06-19 16:03:38 +01001713 notifyChange(
1714 ContentProvider.getUriWithoutUserId(uri),
1715 observer,
1716 syncToNetwork,
1717 ContentProvider.getUserIdFromUri(uri, UserHandle.myUserId()));
Christopher Tate16aa9732012-09-17 16:23:44 -07001718 }
1719
1720 /**
Dianne Hackborn141f11c2016-04-05 15:46:12 -07001721 * Notify registered observers that a row was updated.
1722 * To register, call {@link #registerContentObserver(android.net.Uri, boolean, android.database.ContentObserver) registerContentObserver()}.
1723 * By default, CursorAdapter objects will get this notification.
1724 * If syncToNetwork is true, this will attempt to schedule a local sync using the sync
1725 * adapter that's registered for the authority of the provided uri. No account will be
1726 * passed to the sync adapter, so all matching accounts will be synchronized.
1727 *
1728 * @param uri The uri of the content that was changed.
1729 * @param observer The observer that originated the change, may be <code>null</null>.
1730 * The observer that originated the change will only receive the notification if it
1731 * has requested to receive self-change notifications by implementing
1732 * {@link ContentObserver#deliverSelfNotifications()} to return true.
1733 * @param flags Additional flags: {@link #NOTIFY_SYNC_TO_NETWORK}.
1734 * @see #requestSync(android.accounts.Account, String, android.os.Bundle)
1735 */
1736 public void notifyChange(@NonNull Uri uri, @Nullable ContentObserver observer,
1737 @NotifyFlags int flags) {
1738 Preconditions.checkNotNull(uri, "uri");
1739 notifyChange(
1740 ContentProvider.getUriWithoutUserId(uri),
1741 observer,
1742 flags,
1743 ContentProvider.getUserIdFromUri(uri, UserHandle.myUserId()));
1744 }
1745
1746 /**
Christopher Tate16aa9732012-09-17 16:23:44 -07001747 * Notify registered observers within the designated user(s) that a row was updated.
1748 *
1749 * @hide
1750 */
Dianne Hackborne7617772016-04-27 17:03:52 -07001751 public void notifyChange(@NonNull Uri uri, ContentObserver observer, boolean syncToNetwork,
Jeff Sharkey8588bc12016-01-06 16:47:42 -07001752 @UserIdInt int userHandle) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001753 try {
Dianne Hackborn231cc602009-04-27 17:10:36 -07001754 getContentService().notifyChange(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001755 uri, observer == null ? null : observer.getContentObserver(),
Dianne Hackborn141f11c2016-04-05 15:46:12 -07001756 observer != null && observer.deliverSelfNotifications(),
1757 syncToNetwork ? NOTIFY_SYNC_TO_NETWORK : 0,
1758 userHandle);
1759 } catch (RemoteException e) {
1760 }
1761 }
1762
1763 /**
1764 * Notify registered observers within the designated user(s) that a row was updated.
1765 *
1766 * @hide
1767 */
Dianne Hackborne7617772016-04-27 17:03:52 -07001768 public void notifyChange(@NonNull Uri uri, ContentObserver observer, @NotifyFlags int flags,
Dianne Hackborn141f11c2016-04-05 15:46:12 -07001769 @UserIdInt int userHandle) {
1770 try {
1771 getContentService().notifyChange(
1772 uri, observer == null ? null : observer.getContentObserver(),
1773 observer != null && observer.deliverSelfNotifications(), flags,
Christopher Tate16aa9732012-09-17 16:23:44 -07001774 userHandle);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001775 } catch (RemoteException e) {
1776 }
1777 }
1778
1779 /**
Jeff Sharkeyadef88a2013-10-15 13:54:44 -07001780 * Take a persistable URI permission grant that has been offered. Once
Jeff Sharkeye66c1772013-09-20 14:30:59 -07001781 * taken, the permission grant will be remembered across device reboots.
Jeff Sharkeyadef88a2013-10-15 13:54:44 -07001782 * Only URI permissions granted with
Jeff Sharkeye66c1772013-09-20 14:30:59 -07001783 * {@link Intent#FLAG_GRANT_PERSISTABLE_URI_PERMISSION} can be persisted. If
1784 * the grant has already been persisted, taking it again will touch
1785 * {@link UriPermission#getPersistedTime()}.
Jeff Sharkey08da7a12013-08-11 20:53:18 -07001786 *
Jeff Sharkeye66c1772013-09-20 14:30:59 -07001787 * @see #getPersistedUriPermissions()
Jeff Sharkey08da7a12013-08-11 20:53:18 -07001788 */
Jeff Sharkey673db442015-06-11 19:30:57 -07001789 public void takePersistableUriPermission(@NonNull Uri uri,
1790 @Intent.AccessUriMode int modeFlags) {
1791 Preconditions.checkNotNull(uri, "uri");
Jeff Sharkey08da7a12013-08-11 20:53:18 -07001792 try {
Nicolas Prevotd85fc722014-04-16 19:52:08 +01001793 ActivityManagerNative.getDefault().takePersistableUriPermission(
1794 ContentProvider.getUriWithoutUserId(uri), modeFlags, resolveUserId(uri));
Jeff Sharkey08da7a12013-08-11 20:53:18 -07001795 } catch (RemoteException e) {
Jeff Sharkey08da7a12013-08-11 20:53:18 -07001796 }
1797 }
1798
1799 /**
Jeff Sharkeyadef88a2013-10-15 13:54:44 -07001800 * Relinquish a persisted URI permission grant. The URI must have been
Jeff Sharkeye66c1772013-09-20 14:30:59 -07001801 * previously made persistent with
1802 * {@link #takePersistableUriPermission(Uri, int)}. Any non-persistent
1803 * grants to the calling package will remain intact.
Jeff Sharkey08da7a12013-08-11 20:53:18 -07001804 *
Jeff Sharkeye66c1772013-09-20 14:30:59 -07001805 * @see #getPersistedUriPermissions()
Jeff Sharkey08da7a12013-08-11 20:53:18 -07001806 */
Jeff Sharkey673db442015-06-11 19:30:57 -07001807 public void releasePersistableUriPermission(@NonNull Uri uri,
1808 @Intent.AccessUriMode int modeFlags) {
1809 Preconditions.checkNotNull(uri, "uri");
Jeff Sharkey08da7a12013-08-11 20:53:18 -07001810 try {
Nicolas Prevotd85fc722014-04-16 19:52:08 +01001811 ActivityManagerNative.getDefault().releasePersistableUriPermission(
1812 ContentProvider.getUriWithoutUserId(uri), modeFlags, resolveUserId(uri));
Jeff Sharkey08da7a12013-08-11 20:53:18 -07001813 } catch (RemoteException e) {
Jeff Sharkeye66c1772013-09-20 14:30:59 -07001814 }
1815 }
1816
1817 /**
Jeff Sharkeyadef88a2013-10-15 13:54:44 -07001818 * Return list of all URI permission grants that have been persisted by the
Jeff Sharkeybcaac0a2013-10-09 14:21:08 -07001819 * calling app. That is, the returned permissions have been granted
1820 * <em>to</em> the calling app. Only persistable grants taken with
Jeff Sharkeye66c1772013-09-20 14:30:59 -07001821 * {@link #takePersistableUriPermission(Uri, int)} are returned.
1822 *
1823 * @see #takePersistableUriPermission(Uri, int)
1824 * @see #releasePersistableUriPermission(Uri, int)
1825 */
Jeff Sharkey673db442015-06-11 19:30:57 -07001826 public @NonNull List<UriPermission> getPersistedUriPermissions() {
Jeff Sharkeye66c1772013-09-20 14:30:59 -07001827 try {
Jeff Sharkeybcaac0a2013-10-09 14:21:08 -07001828 return ActivityManagerNative.getDefault()
1829 .getPersistedUriPermissions(mPackageName, true).getList();
1830 } catch (RemoteException e) {
1831 throw new RuntimeException("Activity manager has died", e);
1832 }
1833 }
1834
1835 /**
Jeff Sharkeyadef88a2013-10-15 13:54:44 -07001836 * Return list of all persisted URI permission grants that are hosted by the
Jeff Sharkeybcaac0a2013-10-09 14:21:08 -07001837 * calling app. That is, the returned permissions have been granted
1838 * <em>from</em> the calling app. Only grants taken with
1839 * {@link #takePersistableUriPermission(Uri, int)} are returned.
1840 */
Jeff Sharkey673db442015-06-11 19:30:57 -07001841 public @NonNull List<UriPermission> getOutgoingPersistedUriPermissions() {
Jeff Sharkeybcaac0a2013-10-09 14:21:08 -07001842 try {
1843 return ActivityManagerNative.getDefault()
1844 .getPersistedUriPermissions(mPackageName, false).getList();
Jeff Sharkeye66c1772013-09-20 14:30:59 -07001845 } catch (RemoteException e) {
1846 throw new RuntimeException("Activity manager has died", e);
Jeff Sharkey08da7a12013-08-11 20:53:18 -07001847 }
1848 }
1849
1850 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001851 * Start an asynchronous sync operation. If you want to monitor the progress
1852 * of the sync you may register a SyncObserver. Only values of the following
1853 * types may be used in the extras bundle:
1854 * <ul>
1855 * <li>Integer</li>
1856 * <li>Long</li>
1857 * <li>Boolean</li>
1858 * <li>Float</li>
1859 * <li>Double</li>
1860 * <li>String</li>
Matthew Williamsfa774182013-06-18 15:44:11 -07001861 * <li>Account</li>
1862 * <li>null</li>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001863 * </ul>
1864 *
1865 * @param uri the uri of the provider to sync or null to sync all providers.
1866 * @param extras any extras to pass to the SyncAdapter.
Fred Quintanaac9385e2009-06-22 18:00:59 -07001867 * @deprecated instead use
1868 * {@link #requestSync(android.accounts.Account, String, android.os.Bundle)}
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001869 */
Dianne Hackborn4a51c202009-08-21 15:14:02 -07001870 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001871 public void startSync(Uri uri, Bundle extras) {
Fred Quintanaac9385e2009-06-22 18:00:59 -07001872 Account account = null;
1873 if (extras != null) {
1874 String accountName = extras.getString(SYNC_EXTRAS_ACCOUNT);
1875 if (!TextUtils.isEmpty(accountName)) {
Costin Manolache3348f142009-09-29 18:58:36 -07001876 account = new Account(accountName, "com.google");
Fred Quintanaac9385e2009-06-22 18:00:59 -07001877 }
1878 extras.remove(SYNC_EXTRAS_ACCOUNT);
1879 }
1880 requestSync(account, uri != null ? uri.getAuthority() : null, extras);
1881 }
1882
1883 /**
1884 * Start an asynchronous sync operation. If you want to monitor the progress
1885 * of the sync you may register a SyncObserver. Only values of the following
1886 * types may be used in the extras bundle:
1887 * <ul>
1888 * <li>Integer</li>
1889 * <li>Long</li>
1890 * <li>Boolean</li>
1891 * <li>Float</li>
1892 * <li>Double</li>
1893 * <li>String</li>
Matthew Williamsfa774182013-06-18 15:44:11 -07001894 * <li>Account</li>
1895 * <li>null</li>
Fred Quintanaac9385e2009-06-22 18:00:59 -07001896 * </ul>
1897 *
1898 * @param account which account should be synced
1899 * @param authority which authority should be synced
1900 * @param extras any extras to pass to the SyncAdapter.
1901 */
1902 public static void requestSync(Account account, String authority, Bundle extras) {
Alexandra Gherghina03e1e832014-09-10 16:06:10 +01001903 requestSyncAsUser(account, authority, UserHandle.myUserId(), extras);
Alexandra Gherghina0363c3e2014-06-23 13:34:59 +01001904 }
1905
1906 /**
1907 * @see #requestSync(Account, String, Bundle)
1908 * @hide
1909 */
Jeff Sharkey8588bc12016-01-06 16:47:42 -07001910 public static void requestSyncAsUser(Account account, String authority, @UserIdInt int userId,
Alexandra Gherghina0363c3e2014-06-23 13:34:59 +01001911 Bundle extras) {
Matthew Williamsd8abd6a2013-09-09 14:35:27 -07001912 if (extras == null) {
1913 throw new IllegalArgumentException("Must specify extras.");
1914 }
Matthew Williamsfa774182013-06-18 15:44:11 -07001915 SyncRequest request =
1916 new SyncRequest.Builder()
1917 .setSyncAdapter(account, authority)
1918 .setExtras(extras)
Nick Kralevich69002ae2013-10-19 08:43:08 -07001919 .syncOnce() // Immediate sync.
Matthew Williamsfa774182013-06-18 15:44:11 -07001920 .build();
Alexandra Gherghina0363c3e2014-06-23 13:34:59 +01001921 try {
1922 getContentService().syncAsUser(request, userId);
1923 } catch(RemoteException e) {
1924 // Shouldn't happen.
1925 }
Matthew Williamsfa774182013-06-18 15:44:11 -07001926 }
1927
1928 /**
1929 * Register a sync with the SyncManager. These requests are built using the
1930 * {@link SyncRequest.Builder}.
1931 */
1932 public static void requestSync(SyncRequest request) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001933 try {
Matthew Williamsfa774182013-06-18 15:44:11 -07001934 getContentService().sync(request);
1935 } catch(RemoteException e) {
1936 // Shouldn't happen.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001937 }
1938 }
1939
1940 /**
1941 * Check that only values of the following types are in the Bundle:
1942 * <ul>
1943 * <li>Integer</li>
1944 * <li>Long</li>
1945 * <li>Boolean</li>
1946 * <li>Float</li>
1947 * <li>Double</li>
1948 * <li>String</li>
Fred Quintanad9d2f112009-04-23 13:36:27 -07001949 * <li>Account</li>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001950 * <li>null</li>
1951 * </ul>
1952 * @param extras the Bundle to check
1953 */
1954 public static void validateSyncExtrasBundle(Bundle extras) {
1955 try {
1956 for (String key : extras.keySet()) {
1957 Object value = extras.get(key);
1958 if (value == null) continue;
1959 if (value instanceof Long) continue;
1960 if (value instanceof Integer) continue;
1961 if (value instanceof Boolean) continue;
1962 if (value instanceof Float) continue;
1963 if (value instanceof Double) continue;
1964 if (value instanceof String) continue;
Fred Quintanad9d2f112009-04-23 13:36:27 -07001965 if (value instanceof Account) continue;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001966 throw new IllegalArgumentException("unexpected value type: "
1967 + value.getClass().getName());
1968 }
1969 } catch (IllegalArgumentException e) {
1970 throw e;
1971 } catch (RuntimeException exc) {
1972 throw new IllegalArgumentException("error unparceling Bundle", exc);
1973 }
1974 }
1975
Fred Quintanaac9385e2009-06-22 18:00:59 -07001976 /**
1977 * Cancel any active or pending syncs that match the Uri. If the uri is null then
1978 * all syncs will be canceled.
1979 *
1980 * @param uri the uri of the provider to sync or null to sync all providers.
1981 * @deprecated instead use {@link #cancelSync(android.accounts.Account, String)}
1982 */
Dianne Hackborn4a51c202009-08-21 15:14:02 -07001983 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001984 public void cancelSync(Uri uri) {
Fred Quintanaac9385e2009-06-22 18:00:59 -07001985 cancelSync(null /* all accounts */, uri != null ? uri.getAuthority() : null);
1986 }
1987
1988 /**
1989 * Cancel any active or pending syncs that match account and authority. The account and
1990 * authority can each independently be set to null, which means that syncs with any account
1991 * or authority, respectively, will match.
1992 *
1993 * @param account filters the syncs that match by this account
1994 * @param authority filters the syncs that match by this authority
1995 */
1996 public static void cancelSync(Account account, String authority) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001997 try {
Matthew Williams56dbf8f2013-07-26 12:56:39 -07001998 getContentService().cancelSync(account, authority, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001999 } catch (RemoteException e) {
2000 }
2001 }
2002
Fred Quintanaac9385e2009-06-22 18:00:59 -07002003 /**
Alexandra Gherghina0363c3e2014-06-23 13:34:59 +01002004 * @see #cancelSync(Account, String)
2005 * @hide
2006 */
Jeff Sharkey8588bc12016-01-06 16:47:42 -07002007 public static void cancelSyncAsUser(Account account, String authority, @UserIdInt int userId) {
Alexandra Gherghina0363c3e2014-06-23 13:34:59 +01002008 try {
2009 getContentService().cancelSyncAsUser(account, authority, null, userId);
2010 } catch (RemoteException e) {
2011 }
2012 }
2013
2014 /**
Fred Quintanaac9385e2009-06-22 18:00:59 -07002015 * Get information about the SyncAdapters that are known to the system.
2016 * @return an array of SyncAdapters that have registered with the system
2017 */
2018 public static SyncAdapterType[] getSyncAdapterTypes() {
2019 try {
2020 return getContentService().getSyncAdapterTypes();
2021 } catch (RemoteException e) {
2022 throw new RuntimeException("the ContentService should always be reachable", e);
2023 }
2024 }
2025
2026 /**
Alexandra Gherghina0363c3e2014-06-23 13:34:59 +01002027 * @see #getSyncAdapterTypes()
2028 * @hide
2029 */
Jeff Sharkey8588bc12016-01-06 16:47:42 -07002030 public static SyncAdapterType[] getSyncAdapterTypesAsUser(@UserIdInt int userId) {
Alexandra Gherghina0363c3e2014-06-23 13:34:59 +01002031 try {
2032 return getContentService().getSyncAdapterTypesAsUser(userId);
2033 } catch (RemoteException e) {
2034 throw new RuntimeException("the ContentService should always be reachable", e);
2035 }
2036 }
2037
2038 /**
Amith Yamasani37a40c22015-06-17 13:25:42 -07002039 * @hide
2040 * Returns the package names of syncadapters that match a given user and authority.
2041 */
Jeff Sharkeya73b8fd2016-01-06 17:02:08 -07002042 @TestApi
Amith Yamasani37a40c22015-06-17 13:25:42 -07002043 public static String[] getSyncAdapterPackagesForAuthorityAsUser(String authority,
Jeff Sharkey8588bc12016-01-06 16:47:42 -07002044 @UserIdInt int userId) {
Amith Yamasani37a40c22015-06-17 13:25:42 -07002045 try {
2046 return getContentService().getSyncAdapterPackagesForAuthorityAsUser(authority, userId);
2047 } catch (RemoteException e) {
2048 }
2049 return ArrayUtils.emptyArray(String.class);
2050 }
2051
2052 /**
Fred Quintanaac9385e2009-06-22 18:00:59 -07002053 * Check if the provider should be synced when a network tickle is received
Nicolas Falliere9530e3a2012-06-18 17:21:06 -07002054 * <p>This method requires the caller to hold the permission
2055 * {@link android.Manifest.permission#READ_SYNC_SETTINGS}.
Fred Quintanaac9385e2009-06-22 18:00:59 -07002056 *
2057 * @param account the account whose setting we are querying
2058 * @param authority the provider whose setting we are querying
2059 * @return true if the provider should be synced when a network tickle is received
2060 */
2061 public static boolean getSyncAutomatically(Account account, String authority) {
2062 try {
2063 return getContentService().getSyncAutomatically(account, authority);
2064 } catch (RemoteException e) {
2065 throw new RuntimeException("the ContentService should always be reachable", e);
2066 }
2067 }
2068
2069 /**
Alexandra Gherghina0363c3e2014-06-23 13:34:59 +01002070 * @see #getSyncAutomatically(Account, String)
2071 * @hide
2072 */
2073 public static boolean getSyncAutomaticallyAsUser(Account account, String authority,
Jeff Sharkey8588bc12016-01-06 16:47:42 -07002074 @UserIdInt int userId) {
Alexandra Gherghina0363c3e2014-06-23 13:34:59 +01002075 try {
2076 return getContentService().getSyncAutomaticallyAsUser(account, authority, userId);
2077 } catch (RemoteException e) {
2078 throw new RuntimeException("the ContentService should always be reachable", e);
2079 }
2080 }
2081
2082 /**
Fred Quintanaac9385e2009-06-22 18:00:59 -07002083 * Set whether or not the provider is synced when it receives a network tickle.
Nicolas Falliere9530e3a2012-06-18 17:21:06 -07002084 * <p>This method requires the caller to hold the permission
2085 * {@link android.Manifest.permission#WRITE_SYNC_SETTINGS}.
Fred Quintanaac9385e2009-06-22 18:00:59 -07002086 *
2087 * @param account the account whose setting we are querying
2088 * @param authority the provider whose behavior is being controlled
2089 * @param sync true if the provider should be synced when tickles are received for it
2090 */
2091 public static void setSyncAutomatically(Account account, String authority, boolean sync) {
Alexandra Gherghina03e1e832014-09-10 16:06:10 +01002092 setSyncAutomaticallyAsUser(account, authority, sync, UserHandle.myUserId());
Alexandra Gherghinacb228072014-07-01 15:14:11 +01002093 }
2094
2095 /**
2096 * @see #setSyncAutomatically(Account, String, boolean)
2097 * @hide
2098 */
2099 public static void setSyncAutomaticallyAsUser(Account account, String authority, boolean sync,
Jeff Sharkey8588bc12016-01-06 16:47:42 -07002100 @UserIdInt int userId) {
Fred Quintanaac9385e2009-06-22 18:00:59 -07002101 try {
Alexandra Gherghinacb228072014-07-01 15:14:11 +01002102 getContentService().setSyncAutomaticallyAsUser(account, authority, sync, userId);
Fred Quintanaac9385e2009-06-22 18:00:59 -07002103 } catch (RemoteException e) {
2104 // exception ignored; if this is thrown then it means the runtime is in the midst of
2105 // being restarted
2106 }
2107 }
2108
2109 /**
Fred Quintanac5d1c6d2010-01-27 12:17:49 -08002110 * Specifies that a sync should be requested with the specified the account, authority,
2111 * and extras at the given frequency. If there is already another periodic sync scheduled
2112 * with the account, authority and extras then a new periodic sync won't be added, instead
2113 * the frequency of the previous one will be updated.
2114 * <p>
2115 * These periodic syncs honor the "syncAutomatically" and "masterSyncAutomatically" settings.
2116 * Although these sync are scheduled at the specified frequency, it may take longer for it to
2117 * actually be started if other syncs are ahead of it in the sync operation queue. This means
2118 * that the actual start time may drift.
Fred Quintana53bd2522010-02-05 15:28:12 -08002119 * <p>
2120 * Periodic syncs are not allowed to have any of {@link #SYNC_EXTRAS_DO_NOT_RETRY},
2121 * {@link #SYNC_EXTRAS_IGNORE_BACKOFF}, {@link #SYNC_EXTRAS_IGNORE_SETTINGS},
2122 * {@link #SYNC_EXTRAS_INITIALIZE}, {@link #SYNC_EXTRAS_FORCE},
2123 * {@link #SYNC_EXTRAS_EXPEDITED}, {@link #SYNC_EXTRAS_MANUAL} set to true.
2124 * If any are supplied then an {@link IllegalArgumentException} will be thrown.
Fred Quintanac5d1c6d2010-01-27 12:17:49 -08002125 *
Nicolas Falliere9530e3a2012-06-18 17:21:06 -07002126 * <p>This method requires the caller to hold the permission
2127 * {@link android.Manifest.permission#WRITE_SYNC_SETTINGS}.
Matthew Williams56dbf8f2013-07-26 12:56:39 -07002128 * <p>The bundle for a periodic sync can be queried by applications with the correct
2129 * permissions using
2130 * {@link ContentResolver#getPeriodicSyncs(Account account, String provider)}, so no
2131 * sensitive data should be transferred here.
Nicolas Falliere9530e3a2012-06-18 17:21:06 -07002132 *
Fred Quintanac5d1c6d2010-01-27 12:17:49 -08002133 * @param account the account to specify in the sync
2134 * @param authority the provider to specify in the sync request
2135 * @param extras extra parameters to go along with the sync request
Shreyas Basargee96c3b72016-01-29 19:25:51 +00002136 * @param pollFrequency how frequently the sync should be performed, in seconds. A minimum value
2137 * of 1 hour is enforced.
Fred Quintana53bd2522010-02-05 15:28:12 -08002138 * @throws IllegalArgumentException if an illegal extra was set or if any of the parameters
2139 * are null.
Fred Quintanac5d1c6d2010-01-27 12:17:49 -08002140 */
2141 public static void addPeriodicSync(Account account, String authority, Bundle extras,
2142 long pollFrequency) {
2143 validateSyncExtrasBundle(extras);
Fred Quintana53bd2522010-02-05 15:28:12 -08002144 if (extras.getBoolean(SYNC_EXTRAS_MANUAL, false)
2145 || extras.getBoolean(SYNC_EXTRAS_DO_NOT_RETRY, false)
2146 || extras.getBoolean(SYNC_EXTRAS_IGNORE_BACKOFF, false)
2147 || extras.getBoolean(SYNC_EXTRAS_IGNORE_SETTINGS, false)
2148 || extras.getBoolean(SYNC_EXTRAS_INITIALIZE, false)
2149 || extras.getBoolean(SYNC_EXTRAS_FORCE, false)
2150 || extras.getBoolean(SYNC_EXTRAS_EXPEDITED, false)) {
2151 throw new IllegalArgumentException("illegal extras were set");
2152 }
Fred Quintanac5d1c6d2010-01-27 12:17:49 -08002153 try {
Matthew Williamsfa774182013-06-18 15:44:11 -07002154 getContentService().addPeriodicSync(account, authority, extras, pollFrequency);
Fred Quintanac5d1c6d2010-01-27 12:17:49 -08002155 } catch (RemoteException e) {
2156 // exception ignored; if this is thrown then it means the runtime is in the midst of
2157 // being restarted
2158 }
2159 }
2160
2161 /**
Matthew Williams56dbf8f2013-07-26 12:56:39 -07002162 * {@hide}
2163 * Helper function to throw an <code>IllegalArgumentException</code> if any illegal
2164 * extras were set for a periodic sync.
2165 *
2166 * @param extras bundle to validate.
2167 */
2168 public static boolean invalidPeriodicExtras(Bundle extras) {
2169 if (extras.getBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, false)
2170 || extras.getBoolean(ContentResolver.SYNC_EXTRAS_DO_NOT_RETRY, false)
2171 || extras.getBoolean(ContentResolver.SYNC_EXTRAS_IGNORE_BACKOFF, false)
2172 || extras.getBoolean(ContentResolver.SYNC_EXTRAS_IGNORE_SETTINGS, false)
2173 || extras.getBoolean(ContentResolver.SYNC_EXTRAS_INITIALIZE, false)
2174 || extras.getBoolean(ContentResolver.SYNC_EXTRAS_FORCE, false)
2175 || extras.getBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, false)) {
2176 return true;
2177 }
2178 return false;
2179 }
2180
2181 /**
Fred Quintanac5d1c6d2010-01-27 12:17:49 -08002182 * Remove a periodic sync. Has no affect if account, authority and extras don't match
2183 * an existing periodic sync.
Nicolas Falliere9530e3a2012-06-18 17:21:06 -07002184 * <p>This method requires the caller to hold the permission
2185 * {@link android.Manifest.permission#WRITE_SYNC_SETTINGS}.
Fred Quintanac5d1c6d2010-01-27 12:17:49 -08002186 *
2187 * @param account the account of the periodic sync to remove
2188 * @param authority the provider of the periodic sync to remove
2189 * @param extras the extras of the periodic sync to remove
2190 */
2191 public static void removePeriodicSync(Account account, String authority, Bundle extras) {
2192 validateSyncExtrasBundle(extras);
2193 try {
2194 getContentService().removePeriodicSync(account, authority, extras);
2195 } catch (RemoteException e) {
2196 throw new RuntimeException("the ContentService should always be reachable", e);
2197 }
2198 }
2199
2200 /**
Matthew Williams56dbf8f2013-07-26 12:56:39 -07002201 * Remove the specified sync. This will cancel any pending or active syncs. If the request is
2202 * for a periodic sync, this call will remove any future occurrences.
Matthew Williams5a9decd2014-06-04 09:25:11 -07002203 * <p>
2204 * If a periodic sync is specified, the caller must hold the permission
2205 * {@link android.Manifest.permission#WRITE_SYNC_SETTINGS}.
2206 *</p>
2207 * It is possible to cancel a sync using a SyncRequest object that is not the same object
Matthew Williams56dbf8f2013-07-26 12:56:39 -07002208 * with which you requested the sync. Do so by building a SyncRequest with the same
Matthew Williams5a9decd2014-06-04 09:25:11 -07002209 * adapter, frequency, <b>and</b> extras bundle.
Matthew Williamsfa774182013-06-18 15:44:11 -07002210 *
2211 * @param request SyncRequest object containing information about sync to cancel.
2212 */
2213 public static void cancelSync(SyncRequest request) {
Matthew Williams56dbf8f2013-07-26 12:56:39 -07002214 if (request == null) {
2215 throw new IllegalArgumentException("request cannot be null");
2216 }
2217 try {
2218 getContentService().cancelRequest(request);
2219 } catch (RemoteException e) {
2220 // exception ignored; if this is thrown then it means the runtime is in the midst of
2221 // being restarted
2222 }
Matthew Williamsfa774182013-06-18 15:44:11 -07002223 }
2224
2225 /**
Fred Quintanac5d1c6d2010-01-27 12:17:49 -08002226 * Get the list of information about the periodic syncs for the given account and authority.
Nicolas Falliere9530e3a2012-06-18 17:21:06 -07002227 * <p>This method requires the caller to hold the permission
2228 * {@link android.Manifest.permission#READ_SYNC_SETTINGS}.
Fred Quintanac5d1c6d2010-01-27 12:17:49 -08002229 *
2230 * @param account the account whose periodic syncs we are querying
2231 * @param authority the provider whose periodic syncs we are querying
2232 * @return a list of PeriodicSync objects. This list may be empty but will never be null.
2233 */
2234 public static List<PeriodicSync> getPeriodicSyncs(Account account, String authority) {
2235 try {
Matthew Williams56dbf8f2013-07-26 12:56:39 -07002236 return getContentService().getPeriodicSyncs(account, authority, null);
2237 } catch (RemoteException e) {
2238 throw new RuntimeException("the ContentService should always be reachable", e);
2239 }
2240 }
2241
2242 /**
Fred Quintana5e787c42009-08-16 23:13:53 -07002243 * Check if this account/provider is syncable.
Nicolas Falliere9530e3a2012-06-18 17:21:06 -07002244 * <p>This method requires the caller to hold the permission
2245 * {@link android.Manifest.permission#READ_SYNC_SETTINGS}.
Fred Quintana5e787c42009-08-16 23:13:53 -07002246 * @return >0 if it is syncable, 0 if not, and <0 if the state isn't known yet.
2247 */
Jim Miller20ea6ce2009-08-17 15:47:14 -07002248 public static int getIsSyncable(Account account, String authority) {
Fred Quintana5e787c42009-08-16 23:13:53 -07002249 try {
2250 return getContentService().getIsSyncable(account, authority);
2251 } catch (RemoteException e) {
2252 throw new RuntimeException("the ContentService should always be reachable", e);
2253 }
2254 }
2255
2256 /**
Alexandra Gherghina0363c3e2014-06-23 13:34:59 +01002257 * @see #getIsSyncable(Account, String)
2258 * @hide
2259 */
Jeff Sharkey8588bc12016-01-06 16:47:42 -07002260 public static int getIsSyncableAsUser(Account account, String authority,
2261 @UserIdInt int userId) {
Alexandra Gherghina0363c3e2014-06-23 13:34:59 +01002262 try {
2263 return getContentService().getIsSyncableAsUser(account, authority, userId);
2264 } catch (RemoteException e) {
2265 throw new RuntimeException("the ContentService should always be reachable", e);
2266 }
2267 }
2268
2269 /**
Fred Quintana5e787c42009-08-16 23:13:53 -07002270 * Set whether this account/provider is syncable.
Nicolas Falliere9530e3a2012-06-18 17:21:06 -07002271 * <p>This method requires the caller to hold the permission
2272 * {@link android.Manifest.permission#WRITE_SYNC_SETTINGS}.
Fred Quintana718671b2009-08-17 14:08:37 -07002273 * @param syncable >0 denotes syncable, 0 means not syncable, <0 means unknown
Fred Quintana5e787c42009-08-16 23:13:53 -07002274 */
Jim Miller20ea6ce2009-08-17 15:47:14 -07002275 public static void setIsSyncable(Account account, String authority, int syncable) {
Fred Quintana5e787c42009-08-16 23:13:53 -07002276 try {
2277 getContentService().setIsSyncable(account, authority, syncable);
2278 } catch (RemoteException e) {
2279 // exception ignored; if this is thrown then it means the runtime is in the midst of
2280 // being restarted
2281 }
2282 }
2283
2284 /**
Fred Quintanaac9385e2009-06-22 18:00:59 -07002285 * Gets the master auto-sync setting that applies to all the providers and accounts.
2286 * If this is false then the per-provider auto-sync setting is ignored.
Nicolas Falliere9530e3a2012-06-18 17:21:06 -07002287 * <p>This method requires the caller to hold the permission
2288 * {@link android.Manifest.permission#READ_SYNC_SETTINGS}.
Fred Quintanaac9385e2009-06-22 18:00:59 -07002289 *
2290 * @return the master auto-sync setting that applies to all the providers and accounts
2291 */
2292 public static boolean getMasterSyncAutomatically() {
2293 try {
2294 return getContentService().getMasterSyncAutomatically();
2295 } catch (RemoteException e) {
2296 throw new RuntimeException("the ContentService should always be reachable", e);
2297 }
2298 }
2299
2300 /**
Alexandra Gherghina0363c3e2014-06-23 13:34:59 +01002301 * @see #getMasterSyncAutomatically()
2302 * @hide
2303 */
Jeff Sharkey8588bc12016-01-06 16:47:42 -07002304 public static boolean getMasterSyncAutomaticallyAsUser(@UserIdInt int userId) {
Alexandra Gherghina0363c3e2014-06-23 13:34:59 +01002305 try {
2306 return getContentService().getMasterSyncAutomaticallyAsUser(userId);
2307 } catch (RemoteException e) {
2308 throw new RuntimeException("the ContentService should always be reachable", e);
2309 }
2310 }
2311
2312 /**
Fred Quintanaac9385e2009-06-22 18:00:59 -07002313 * Sets the master auto-sync setting that applies to all the providers and accounts.
2314 * If this is false then the per-provider auto-sync setting is ignored.
Nicolas Falliere9530e3a2012-06-18 17:21:06 -07002315 * <p>This method requires the caller to hold the permission
2316 * {@link android.Manifest.permission#WRITE_SYNC_SETTINGS}.
Fred Quintanaac9385e2009-06-22 18:00:59 -07002317 *
2318 * @param sync the master auto-sync setting that applies to all the providers and accounts
2319 */
2320 public static void setMasterSyncAutomatically(boolean sync) {
Alexandra Gherghina03e1e832014-09-10 16:06:10 +01002321 setMasterSyncAutomaticallyAsUser(sync, UserHandle.myUserId());
Alexandra Gherghina0e9ac202014-07-15 23:11:48 +01002322 }
2323
2324 /**
2325 * @see #setMasterSyncAutomatically(boolean)
2326 * @hide
2327 */
Jeff Sharkey8588bc12016-01-06 16:47:42 -07002328 public static void setMasterSyncAutomaticallyAsUser(boolean sync, @UserIdInt int userId) {
Fred Quintanaac9385e2009-06-22 18:00:59 -07002329 try {
Alexandra Gherghina0e9ac202014-07-15 23:11:48 +01002330 getContentService().setMasterSyncAutomaticallyAsUser(sync, userId);
Fred Quintanaac9385e2009-06-22 18:00:59 -07002331 } catch (RemoteException e) {
2332 // exception ignored; if this is thrown then it means the runtime is in the midst of
2333 // being restarted
2334 }
2335 }
2336
2337 /**
Matthew Williams56dbf8f2013-07-26 12:56:39 -07002338 * Returns true if there is currently a sync operation for the given account or authority
2339 * actively being processed.
Nicolas Falliere9530e3a2012-06-18 17:21:06 -07002340 * <p>This method requires the caller to hold the permission
2341 * {@link android.Manifest.permission#READ_SYNC_STATS}.
Fred Quintanaac9385e2009-06-22 18:00:59 -07002342 * @param account the account whose setting we are querying
2343 * @param authority the provider whose behavior is being queried
2344 * @return true if a sync is active for the given account or authority.
2345 */
2346 public static boolean isSyncActive(Account account, String authority) {
Matthew Williams56dbf8f2013-07-26 12:56:39 -07002347 if (account == null) {
2348 throw new IllegalArgumentException("account must not be null");
2349 }
2350 if (authority == null) {
2351 throw new IllegalArgumentException("authority must not be null");
2352 }
2353
Fred Quintanaac9385e2009-06-22 18:00:59 -07002354 try {
Matthew Williams56dbf8f2013-07-26 12:56:39 -07002355 return getContentService().isSyncActive(account, authority, null);
2356 } catch (RemoteException e) {
2357 throw new RuntimeException("the ContentService should always be reachable", e);
2358 }
2359 }
2360
Fred Quintanaac9385e2009-06-22 18:00:59 -07002361 /**
Fred Quintanac6a69552010-09-27 17:05:04 -07002362 * If a sync is active returns the information about it, otherwise returns null.
2363 * <p>
Nicolas Falliere9530e3a2012-06-18 17:21:06 -07002364 * This method requires the caller to hold the permission
2365 * {@link android.Manifest.permission#READ_SYNC_STATS}.
2366 * <p>
Fred Quintanad5e4fdc2010-03-30 15:16:21 -07002367 * @return the SyncInfo for the currently active sync or null if one is not active.
Fred Quintanac6a69552010-09-27 17:05:04 -07002368 * @deprecated
2369 * Since multiple concurrent syncs are now supported you should use
2370 * {@link #getCurrentSyncs()} to get the accurate list of current syncs.
2371 * This method returns the first item from the list of current syncs
2372 * or null if there are none.
Fred Quintanaac9385e2009-06-22 18:00:59 -07002373 */
Fred Quintanac6a69552010-09-27 17:05:04 -07002374 @Deprecated
Fred Quintanad5e4fdc2010-03-30 15:16:21 -07002375 public static SyncInfo getCurrentSync() {
Fred Quintanaac9385e2009-06-22 18:00:59 -07002376 try {
Fred Quintanac6a69552010-09-27 17:05:04 -07002377 final List<SyncInfo> syncs = getContentService().getCurrentSyncs();
2378 if (syncs.isEmpty()) {
2379 return null;
2380 }
2381 return syncs.get(0);
2382 } catch (RemoteException e) {
2383 throw new RuntimeException("the ContentService should always be reachable", e);
2384 }
2385 }
2386
2387 /**
2388 * Returns a list with information about all the active syncs. This list will be empty
2389 * if there are no active syncs.
Nicolas Falliere9530e3a2012-06-18 17:21:06 -07002390 * <p>
2391 * This method requires the caller to hold the permission
2392 * {@link android.Manifest.permission#READ_SYNC_STATS}.
2393 * <p>
Fred Quintanac6a69552010-09-27 17:05:04 -07002394 * @return a List of SyncInfo objects for the currently active syncs.
2395 */
2396 public static List<SyncInfo> getCurrentSyncs() {
2397 try {
2398 return getContentService().getCurrentSyncs();
Fred Quintanaac9385e2009-06-22 18:00:59 -07002399 } catch (RemoteException e) {
2400 throw new RuntimeException("the ContentService should always be reachable", e);
2401 }
2402 }
2403
2404 /**
Alexandra Gherghina0363c3e2014-06-23 13:34:59 +01002405 * @see #getCurrentSyncs()
2406 * @hide
2407 */
Jeff Sharkey8588bc12016-01-06 16:47:42 -07002408 public static List<SyncInfo> getCurrentSyncsAsUser(@UserIdInt int userId) {
Alexandra Gherghina0363c3e2014-06-23 13:34:59 +01002409 try {
2410 return getContentService().getCurrentSyncsAsUser(userId);
2411 } catch (RemoteException e) {
2412 throw new RuntimeException("the ContentService should always be reachable", e);
2413 }
2414 }
2415
2416 /**
Fred Quintana4a6679b2009-08-17 13:05:39 -07002417 * Returns the status that matches the authority.
Fred Quintanaac9385e2009-06-22 18:00:59 -07002418 * @param account the account whose setting we are querying
2419 * @param authority the provider whose behavior is being queried
2420 * @return the SyncStatusInfo for the authority, or null if none exists
2421 * @hide
2422 */
2423 public static SyncStatusInfo getSyncStatus(Account account, String authority) {
2424 try {
Matthew Williams56dbf8f2013-07-26 12:56:39 -07002425 return getContentService().getSyncStatus(account, authority, null);
Fred Quintanaac9385e2009-06-22 18:00:59 -07002426 } catch (RemoteException e) {
2427 throw new RuntimeException("the ContentService should always be reachable", e);
2428 }
2429 }
2430
2431 /**
Alexandra Gherghina0363c3e2014-06-23 13:34:59 +01002432 * @see #getSyncStatus(Account, String)
2433 * @hide
2434 */
2435 public static SyncStatusInfo getSyncStatusAsUser(Account account, String authority,
Jeff Sharkey8588bc12016-01-06 16:47:42 -07002436 @UserIdInt int userId) {
Alexandra Gherghina0363c3e2014-06-23 13:34:59 +01002437 try {
2438 return getContentService().getSyncStatusAsUser(account, authority, null, userId);
2439 } catch (RemoteException e) {
2440 throw new RuntimeException("the ContentService should always be reachable", e);
2441 }
2442 }
2443
2444 /**
Fred Quintanaac9385e2009-06-22 18:00:59 -07002445 * Return true if the pending status is true of any matching authorities.
Nicolas Falliere9530e3a2012-06-18 17:21:06 -07002446 * <p>This method requires the caller to hold the permission
2447 * {@link android.Manifest.permission#READ_SYNC_STATS}.
Fred Quintanaac9385e2009-06-22 18:00:59 -07002448 * @param account the account whose setting we are querying
2449 * @param authority the provider whose behavior is being queried
2450 * @return true if there is a pending sync with the matching account and authority
2451 */
2452 public static boolean isSyncPending(Account account, String authority) {
Alexandra Gherghina03e1e832014-09-10 16:06:10 +01002453 return isSyncPendingAsUser(account, authority, UserHandle.myUserId());
Alexandra Gherghinacb228072014-07-01 15:14:11 +01002454 }
2455
2456 /**
2457 * @see #requestSync(Account, String, Bundle)
2458 * @hide
2459 */
Jeff Sharkey8588bc12016-01-06 16:47:42 -07002460 public static boolean isSyncPendingAsUser(Account account, String authority,
2461 @UserIdInt int userId) {
Fred Quintanaac9385e2009-06-22 18:00:59 -07002462 try {
Alexandra Gherghinacb228072014-07-01 15:14:11 +01002463 return getContentService().isSyncPendingAsUser(account, authority, null, userId);
Matthew Williams56dbf8f2013-07-26 12:56:39 -07002464 } catch (RemoteException e) {
2465 throw new RuntimeException("the ContentService should always be reachable", e);
2466 }
2467 }
2468
Fred Quintana1b487ec2010-02-26 10:57:55 -08002469 /**
2470 * Request notifications when the different aspects of the SyncManager change. The
2471 * different items that can be requested are:
2472 * <ul>
2473 * <li> {@link #SYNC_OBSERVER_TYPE_PENDING}
2474 * <li> {@link #SYNC_OBSERVER_TYPE_ACTIVE}
2475 * <li> {@link #SYNC_OBSERVER_TYPE_SETTINGS}
2476 * </ul>
2477 * The caller can set one or more of the status types in the mask for any
2478 * given listener registration.
2479 * @param mask the status change types that will cause the callback to be invoked
2480 * @param callback observer to be invoked when the status changes
2481 * @return a handle that can be used to remove the listener at a later time
2482 */
Fred Quintanaac9385e2009-06-22 18:00:59 -07002483 public static Object addStatusChangeListener(int mask, final SyncStatusObserver callback) {
Fred Quintana1b487ec2010-02-26 10:57:55 -08002484 if (callback == null) {
2485 throw new IllegalArgumentException("you passed in a null callback");
2486 }
Fred Quintanaac9385e2009-06-22 18:00:59 -07002487 try {
2488 ISyncStatusObserver.Stub observer = new ISyncStatusObserver.Stub() {
2489 public void onStatusChanged(int which) throws RemoteException {
2490 callback.onStatusChanged(which);
2491 }
2492 };
2493 getContentService().addStatusChangeListener(mask, observer);
2494 return observer;
2495 } catch (RemoteException e) {
2496 throw new RuntimeException("the ContentService should always be reachable", e);
2497 }
2498 }
2499
Fred Quintana1b487ec2010-02-26 10:57:55 -08002500 /**
2501 * Remove a previously registered status change listener.
2502 * @param handle the handle that was returned by {@link #addStatusChangeListener}
2503 */
Fred Quintanaac9385e2009-06-22 18:00:59 -07002504 public static void removeStatusChangeListener(Object handle) {
Fred Quintana1b487ec2010-02-26 10:57:55 -08002505 if (handle == null) {
2506 throw new IllegalArgumentException("you passed in a null handle");
2507 }
Fred Quintanaac9385e2009-06-22 18:00:59 -07002508 try {
2509 getContentService().removeStatusChangeListener((ISyncStatusObserver.Stub) handle);
2510 } catch (RemoteException e) {
2511 // exception ignored; if this is thrown then it means the runtime is in the midst of
2512 // being restarted
2513 }
2514 }
2515
Jeff Sharkey87314082016-03-11 17:25:11 -07002516 /** {@hide} */
2517 public void putCache(Uri key, Bundle value) {
2518 try {
2519 getContentService().putCache(mContext.getPackageName(), key, value,
2520 mContext.getUserId());
2521 } catch (RemoteException e) {
2522 throw e.rethrowFromSystemServer();
2523 }
2524 }
2525
2526 /** {@hide} */
2527 public Bundle getCache(Uri key) {
2528 try {
2529 final Bundle bundle = getContentService().getCache(mContext.getPackageName(), key,
2530 mContext.getUserId());
2531 if (bundle != null) bundle.setClassLoader(mContext.getClassLoader());
2532 return bundle;
2533 } catch (RemoteException e) {
2534 throw e.rethrowFromSystemServer();
2535 }
2536 }
2537
Brad Fitzpatricka63730d2010-02-07 22:25:34 -08002538 /**
2539 * Returns sampling percentage for a given duration.
2540 *
2541 * Always returns at least 1%.
2542 */
2543 private int samplePercentForDuration(long durationMillis) {
2544 if (durationMillis >= SLOW_THRESHOLD_MILLIS) {
2545 return 100;
2546 }
2547 return (int) (100 * durationMillis / SLOW_THRESHOLD_MILLIS) + 1;
2548 }
2549
2550 private void maybeLogQueryToEventLog(long durationMillis,
2551 Uri uri, String[] projection,
2552 String selection, String sortOrder) {
Jeff Sharkey2b4d22c2013-04-26 10:52:00 -07002553 if (!ENABLE_CONTENT_SAMPLE) return;
Brad Fitzpatricka63730d2010-02-07 22:25:34 -08002554 int samplePercent = samplePercentForDuration(durationMillis);
2555 if (samplePercent < 100) {
2556 synchronized (mRandom) {
2557 if (mRandom.nextInt(100) >= samplePercent) {
2558 return;
2559 }
2560 }
2561 }
2562
2563 StringBuilder projectionBuffer = new StringBuilder(100);
2564 if (projection != null) {
2565 for (int i = 0; i < projection.length; ++i) {
2566 // Note: not using a comma delimiter here, as the
2567 // multiple arguments to EventLog.writeEvent later
2568 // stringify with a comma delimiter, which would make
2569 // parsing uglier later.
2570 if (i != 0) projectionBuffer.append('/');
2571 projectionBuffer.append(projection[i]);
2572 }
2573 }
2574
2575 // ActivityThread.currentPackageName() only returns non-null if the
2576 // current thread is an application main thread. This parameter tells
2577 // us whether an event loop is blocked, and if so, which app it is.
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -07002578 String blockingPackage = AppGlobals.getInitialPackage();
Brad Fitzpatricka63730d2010-02-07 22:25:34 -08002579
2580 EventLog.writeEvent(
Brad Fitzpatricka8fbedb2010-04-08 14:08:54 -07002581 EventLogTags.CONTENT_QUERY_SAMPLE,
Brad Fitzpatricka63730d2010-02-07 22:25:34 -08002582 uri.toString(),
2583 projectionBuffer.toString(),
2584 selection != null ? selection : "",
2585 sortOrder != null ? sortOrder : "",
2586 durationMillis,
2587 blockingPackage != null ? blockingPackage : "",
2588 samplePercent);
2589 }
2590
2591 private void maybeLogUpdateToEventLog(
2592 long durationMillis, Uri uri, String operation, String selection) {
Jeff Sharkey2b4d22c2013-04-26 10:52:00 -07002593 if (!ENABLE_CONTENT_SAMPLE) return;
Brad Fitzpatricka63730d2010-02-07 22:25:34 -08002594 int samplePercent = samplePercentForDuration(durationMillis);
2595 if (samplePercent < 100) {
2596 synchronized (mRandom) {
2597 if (mRandom.nextInt(100) >= samplePercent) {
2598 return;
2599 }
2600 }
2601 }
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -07002602 String blockingPackage = AppGlobals.getInitialPackage();
Brad Fitzpatricka63730d2010-02-07 22:25:34 -08002603 EventLog.writeEvent(
Brad Fitzpatricka8fbedb2010-04-08 14:08:54 -07002604 EventLogTags.CONTENT_UPDATE_SAMPLE,
Brad Fitzpatricka63730d2010-02-07 22:25:34 -08002605 uri.toString(),
2606 operation,
2607 selection != null ? selection : "",
2608 durationMillis,
2609 blockingPackage != null ? blockingPackage : "",
2610 samplePercent);
2611 }
Fred Quintanaac9385e2009-06-22 18:00:59 -07002612
Jeff Brown825c5132011-10-12 16:11:30 -07002613 private final class CursorWrapperInner extends CrossProcessCursorWrapper {
Gilles Debunne03f02922010-06-09 14:11:45 -07002614 private final IContentProvider mContentProvider;
Jeff Sharkey60cfad82016-01-05 17:30:57 -07002615 private final AtomicBoolean mProviderReleased = new AtomicBoolean();
Jeff Brownbaaf8c32011-10-09 14:07:00 -07002616
2617 private final CloseGuard mCloseGuard = CloseGuard.get();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002618
Jeff Sharkey60cfad82016-01-05 17:30:57 -07002619 CursorWrapperInner(Cursor cursor, IContentProvider contentProvider) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002620 super(cursor);
Jeff Sharkey60cfad82016-01-05 17:30:57 -07002621 mContentProvider = contentProvider;
Jeff Brownbaaf8c32011-10-09 14:07:00 -07002622 mCloseGuard.open("close");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002623 }
2624
2625 @Override
2626 public void close() {
Jeff Sharkey60cfad82016-01-05 17:30:57 -07002627 mCloseGuard.close();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002628 super.close();
Jeff Brownbaaf8c32011-10-09 14:07:00 -07002629
Jeff Sharkey60cfad82016-01-05 17:30:57 -07002630 if (mProviderReleased.compareAndSet(false, true)) {
2631 ContentResolver.this.releaseProvider(mContentProvider);
Jeff Brownbaaf8c32011-10-09 14:07:00 -07002632 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002633 }
2634
2635 @Override
2636 protected void finalize() throws Throwable {
2637 try {
Jeff Sharkey60cfad82016-01-05 17:30:57 -07002638 mCloseGuard.warnIfOpen();
2639 close();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002640 } finally {
2641 super.finalize();
2642 }
2643 }
2644 }
2645
2646 private final class ParcelFileDescriptorInner extends ParcelFileDescriptor {
Gilles Debunne03f02922010-06-09 14:11:45 -07002647 private final IContentProvider mContentProvider;
Jeff Sharkey60cfad82016-01-05 17:30:57 -07002648 private final AtomicBoolean mProviderReleased = new AtomicBoolean();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002649
2650 ParcelFileDescriptorInner(ParcelFileDescriptor pfd, IContentProvider icp) {
2651 super(pfd);
2652 mContentProvider = icp;
2653 }
2654
2655 @Override
Amith Yamasani487c11a2013-09-18 09:16:15 -07002656 public void releaseResources() {
Jeff Sharkey60cfad82016-01-05 17:30:57 -07002657 if (mProviderReleased.compareAndSet(false, true)) {
Dianne Hackborn6ae8d182012-05-23 13:12:42 -07002658 ContentResolver.this.releaseProvider(mContentProvider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002659 }
2660 }
2661 }
2662
Dianne Hackborn231cc602009-04-27 17:10:36 -07002663 /** @hide */
2664 public static final String CONTENT_SERVICE_NAME = "content";
Tom O'Neill0ba1cb02010-01-08 12:53:50 -08002665
Dianne Hackborn231cc602009-04-27 17:10:36 -07002666 /** @hide */
2667 public static IContentService getContentService() {
2668 if (sContentService != null) {
2669 return sContentService;
2670 }
2671 IBinder b = ServiceManager.getService(CONTENT_SERVICE_NAME);
Joe Onorato43a17652011-04-06 19:22:23 -07002672 if (false) Log.v("ContentService", "default service binder = " + b);
Dianne Hackborn231cc602009-04-27 17:10:36 -07002673 sContentService = IContentService.Stub.asInterface(b);
Joe Onorato43a17652011-04-06 19:22:23 -07002674 if (false) Log.v("ContentService", "default service = " + sContentService);
Dianne Hackborn231cc602009-04-27 17:10:36 -07002675 return sContentService;
2676 }
Tom O'Neill0ba1cb02010-01-08 12:53:50 -08002677
Dianne Hackborn35654b62013-01-14 17:38:02 -08002678 /** @hide */
2679 public String getPackageName() {
2680 return mPackageName;
2681 }
2682
Dianne Hackborn231cc602009-04-27 17:10:36 -07002683 private static IContentService sContentService;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002684 private final Context mContext;
Jeff Sharkey60cfad82016-01-05 17:30:57 -07002685
Dianne Hackborn35654b62013-01-14 17:38:02 -08002686 final String mPackageName;
Jeff Sharkey60cfad82016-01-05 17:30:57 -07002687
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002688 private static final String TAG = "ContentResolver";
Nicolas Prevotd85fc722014-04-16 19:52:08 +01002689
2690 /** @hide */
2691 public int resolveUserId(Uri uri) {
2692 return ContentProvider.getUserIdFromUri(uri, mContext.getUserId());
2693 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002694}