1 /*
2  * Copyright (C) 2008 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 
17 package android.content.cts;
18 
19 import android.accounts.Account;
20 import android.content.ContentProviderClient;
21 import android.content.ContentResolver;
22 import android.content.ContentResolver.MimeTypeInfo;
23 import android.content.ContentValues;
24 import android.content.Context;
25 import android.content.res.AssetFileDescriptor;
26 import android.database.ContentObserver;
27 import android.database.Cursor;
28 import android.net.Uri;
29 import android.os.Bundle;
30 import android.os.CancellationSignal;
31 import android.os.OperationCanceledException;
32 import android.os.ParcelFileDescriptor;
33 import android.os.RemoteException;
34 import android.platform.test.annotations.AppModeFull;
35 import android.test.AndroidTestCase;
36 import android.util.Log;
37 
38 import androidx.test.InstrumentationRegistry;
39 
40 import com.android.compatibility.common.util.PollingCheck;
41 import com.android.internal.util.ArrayUtils;
42 
43 import java.io.FileInputStream;
44 import java.io.FileNotFoundException;
45 import java.io.IOException;
46 import java.io.InputStream;
47 import java.io.InputStreamReader;
48 import java.io.OutputStream;
49 import java.util.concurrent.CountDownLatch;
50 import java.util.concurrent.TimeUnit;
51 
52 public class ContentResolverTest extends AndroidTestCase {
53     private final static String COLUMN_ID_NAME = "_id";
54     private final static String COLUMN_KEY_NAME = "key";
55     private final static String COLUMN_VALUE_NAME = "value";
56 
57     private static final String AUTHORITY = "ctstest";
58     private static final Uri TABLE1_URI = Uri.parse("content://" + AUTHORITY + "/testtable1/");
59     private static final Uri TABLE1_CROSS_URI =
60             Uri.parse("content://" + AUTHORITY + "/testtable1/cross");
61     private static final Uri TABLE2_URI = Uri.parse("content://" + AUTHORITY + "/testtable2/");
62 
63     private static final Uri LEVEL1_URI = Uri.parse("content://" + AUTHORITY + "/level/");
64     private static final Uri LEVEL2_URI = Uri.parse("content://" + AUTHORITY + "/level/child");
65     private static final Uri LEVEL3_URI = Uri.parse("content://" + AUTHORITY
66             + "/level/child/grandchild/");
67 
68     private static final String REMOTE_AUTHORITY = "remotectstest";
69     private static final Uri REMOTE_TABLE1_URI = Uri.parse("content://"
70                 + REMOTE_AUTHORITY + "/testtable1/");
71     private static final Uri REMOTE_CRASH_URI = Uri.parse("content://"
72             + REMOTE_AUTHORITY + "/crash/");
73     private static final Uri REMOTE_HANG_URI = Uri.parse("content://"
74             + REMOTE_AUTHORITY + "/hang/");
75 
76     private static final Account ACCOUNT = new Account("cts", "cts");
77 
78     private static final String KEY1 = "key1";
79     private static final String KEY2 = "key2";
80     private static final String KEY3 = "key3";
81     private static final int VALUE1 = 1;
82     private static final int VALUE2 = 2;
83     private static final int VALUE3 = 3;
84 
85     private static final String TEST_PACKAGE_NAME = "android.content.cts";
86 
87     private Context mContext;
88     private ContentResolver mContentResolver;
89     private Cursor mCursor;
90 
91     @Override
setUp()92     protected void setUp() throws Exception {
93         super.setUp();
94 
95         mContext = getContext();
96         mContentResolver = mContext.getContentResolver();
97 
98         MockContentProvider.setCrashOnLaunch(mContext, false);
99 
100         // add three rows to database when every test case start.
101         ContentValues values = new ContentValues();
102 
103         values.put(COLUMN_KEY_NAME, KEY1);
104         values.put(COLUMN_VALUE_NAME, VALUE1);
105         mContentResolver.insert(TABLE1_URI, values);
106         mContentResolver.insert(REMOTE_TABLE1_URI, values);
107 
108         values.put(COLUMN_KEY_NAME, KEY2);
109         values.put(COLUMN_VALUE_NAME, VALUE2);
110         mContentResolver.insert(TABLE1_URI, values);
111         mContentResolver.insert(REMOTE_TABLE1_URI, values);
112 
113         values.put(COLUMN_KEY_NAME, KEY3);
114         values.put(COLUMN_VALUE_NAME, VALUE3);
115         mContentResolver.insert(TABLE1_URI, values);
116         mContentResolver.insert(REMOTE_TABLE1_URI, values);
117     }
118 
119     @Override
tearDown()120     protected void tearDown() throws Exception {
121         InstrumentationRegistry.getInstrumentation().getUiAutomation()
122                 .dropShellPermissionIdentity();
123 
124         mContentResolver.delete(TABLE1_URI, null, null);
125         if ( null != mCursor && !mCursor.isClosed() ) {
126             mCursor.close();
127         }
128         mContentResolver.delete(REMOTE_TABLE1_URI, null, null);
129         if ( null != mCursor && !mCursor.isClosed() ) {
130             mCursor.close();
131         }
132         super.tearDown();
133     }
134 
testConstructor()135     public void testConstructor() {
136         assertNotNull(mContentResolver);
137     }
138 
testCrashOnLaunch()139     public void testCrashOnLaunch() {
140         // This test is going to make sure that the platform deals correctly
141         // with a content provider process going away while a client is waiting
142         // for it to come up.
143         // First, we need to make sure our provider process is gone.  Goodbye!
144         ContentProviderClient client = mContentResolver.acquireContentProviderClient(
145                 REMOTE_AUTHORITY);
146         // We are going to do something wrong here...  release the client first,
147         // so the act of killing it doesn't kill our own process.
148         client.release();
149         try {
150             client.delete(REMOTE_CRASH_URI, null, null);
151         } catch (RemoteException e) {
152         }
153         // Now make sure the thing is actually gone.
154         boolean gone = true;
155         try {
156             client.getType(REMOTE_TABLE1_URI);
157             gone = false;
158         } catch (RemoteException e) {
159         }
160         if (!gone) {
161             fail("Content provider process is not gone!");
162         }
163         try {
164             MockContentProvider.setCrashOnLaunch(mContext, true);
165             String type1 = mContentResolver.getType(REMOTE_TABLE1_URI);
166             assertFalse(MockContentProvider.getCrashOnLaunch(mContext));
167             assertTrue(type1.startsWith(ContentResolver.CURSOR_DIR_BASE_TYPE, 0));
168         } finally {
169             MockContentProvider.setCrashOnLaunch(mContext, false);
170         }
171     }
172 
testUnstableToStableRefs()173     public void testUnstableToStableRefs() {
174         // Get an unstable refrence on the remote content provider.
175         ContentProviderClient uClient = mContentResolver.acquireUnstableContentProviderClient(
176                 REMOTE_AUTHORITY);
177         // Verify we can access it.
178         String type1 = mContentResolver.getType(REMOTE_TABLE1_URI);
179         assertTrue(type1.startsWith(ContentResolver.CURSOR_DIR_BASE_TYPE, 0));
180 
181         // Get a stable reference on the remote content provider.
182         ContentProviderClient sClient = mContentResolver.acquireContentProviderClient(
183                 REMOTE_AUTHORITY);
184         // Verify we can still access it.
185         type1 = mContentResolver.getType(REMOTE_TABLE1_URI);
186         assertTrue(type1.startsWith(ContentResolver.CURSOR_DIR_BASE_TYPE, 0));
187 
188         // Release unstable reference.
189         uClient.release();
190         // Verify we can still access it.
191         type1 = mContentResolver.getType(REMOTE_TABLE1_URI);
192         assertTrue(type1.startsWith(ContentResolver.CURSOR_DIR_BASE_TYPE, 0));
193 
194         // Release stable reference, removing last ref.
195         sClient.release();
196         // Kill it.  Note that a bug at this point where it causes our own
197         // process to be killed will result in the entire test failing.
198         try {
199             Log.i("ContentResolverTest",
200                     "Killing remote client -- if test process goes away, that is why!");
201             uClient.delete(REMOTE_CRASH_URI, null, null);
202         } catch (RemoteException e) {
203         }
204         // Make sure the remote client is actually gone.
205         boolean gone = true;
206         try {
207             sClient.getType(REMOTE_TABLE1_URI);
208             gone = false;
209         } catch (RemoteException e) {
210         }
211         if (!gone) {
212             fail("Content provider process is not gone!");
213         }
214     }
215 
testStableToUnstableRefs()216     public void testStableToUnstableRefs() {
217         // Get a stable reference on the remote content provider.
218         ContentProviderClient sClient = mContentResolver.acquireContentProviderClient(
219                 REMOTE_AUTHORITY);
220         // Verify we can still access it.
221         String type1 = mContentResolver.getType(REMOTE_TABLE1_URI);
222         assertTrue(type1.startsWith(ContentResolver.CURSOR_DIR_BASE_TYPE, 0));
223 
224         // Get an unstable refrence on the remote content provider.
225         ContentProviderClient uClient = mContentResolver.acquireUnstableContentProviderClient(
226                 REMOTE_AUTHORITY);
227         // Verify we can access it.
228         type1 = mContentResolver.getType(REMOTE_TABLE1_URI);
229         assertTrue(type1.startsWith(ContentResolver.CURSOR_DIR_BASE_TYPE, 0));
230 
231         // Release stable reference, leaving only an unstable ref.
232         sClient.release();
233 
234         // Kill it.  Note that a bug at this point where it causes our own
235         // process to be killed will result in the entire test failing.
236         try {
237             Log.i("ContentResolverTest",
238                     "Killing remote client -- if test process goes away, that is why!");
239             uClient.delete(REMOTE_CRASH_URI, null, null);
240         } catch (RemoteException e) {
241         }
242         // Make sure the remote client is actually gone.
243         boolean gone = true;
244         try {
245             uClient.getType(REMOTE_TABLE1_URI);
246             gone = false;
247         } catch (RemoteException e) {
248         }
249         if (!gone) {
250             fail("Content provider process is not gone!");
251         }
252 
253         // Release unstable reference.
254         uClient.release();
255     }
256 
testGetType()257     public void testGetType() {
258         String type1 = mContentResolver.getType(TABLE1_URI);
259         assertTrue(type1.startsWith(ContentResolver.CURSOR_DIR_BASE_TYPE, 0));
260 
261         String type2 = mContentResolver.getType(TABLE2_URI);
262         assertTrue(type2.startsWith(ContentResolver.CURSOR_DIR_BASE_TYPE, 0));
263 
264         Uri invalidUri = Uri.parse("abc");
265         assertNull(mContentResolver.getType(invalidUri));
266 
267         try {
268             mContentResolver.getType(null);
269             fail("did not throw NullPointerException when Uri is null.");
270         } catch (NullPointerException e) {
271             //expected.
272         }
273     }
274 
testUnstableGetType()275     public void testUnstableGetType() {
276         // Get an unstable refrence on the remote content provider.
277         ContentProviderClient client = mContentResolver.acquireUnstableContentProviderClient(
278                 REMOTE_AUTHORITY);
279         // Verify we can access it.
280         String type1 = mContentResolver.getType(REMOTE_TABLE1_URI);
281         assertTrue(type1.startsWith(ContentResolver.CURSOR_DIR_BASE_TYPE, 0));
282 
283         // Kill it.  Note that a bug at this point where it causes our own
284         // process to be killed will result in the entire test failing.
285         try {
286             Log.i("ContentResolverTest",
287                     "Killing remote client -- if test process goes away, that is why!");
288             client.delete(REMOTE_CRASH_URI, null, null);
289         } catch (RemoteException e) {
290         }
291         // Make sure the remote client is actually gone.
292         boolean gone = true;
293         try {
294             client.getType(REMOTE_TABLE1_URI);
295             gone = false;
296         } catch (RemoteException e) {
297         }
298         if (!gone) {
299             fail("Content provider process is not gone!");
300         }
301 
302         // Now the remote client is gone, can we recover?
303         // Release our old reference.
304         client.release();
305         // Get a new reference.
306         client = mContentResolver.acquireUnstableContentProviderClient(REMOTE_AUTHORITY);
307         // Verify we can access it.
308         type1 = mContentResolver.getType(REMOTE_TABLE1_URI);
309         assertTrue(type1.startsWith(ContentResolver.CURSOR_DIR_BASE_TYPE, 0));
310     }
311 
testQuery()312     public void testQuery() {
313         mCursor = mContentResolver.query(TABLE1_URI, null, null, null);
314 
315         assertNotNull(mCursor);
316         assertEquals(3, mCursor.getCount());
317         assertEquals(3, mCursor.getColumnCount());
318 
319         mCursor.moveToLast();
320         assertEquals(3, mCursor.getInt(mCursor.getColumnIndexOrThrow(COLUMN_ID_NAME)));
321         assertEquals(KEY3, mCursor.getString(mCursor.getColumnIndexOrThrow(COLUMN_KEY_NAME)));
322         assertEquals(VALUE3, mCursor.getInt(mCursor.getColumnIndexOrThrow(COLUMN_VALUE_NAME)));
323 
324         mCursor.moveToPrevious();
325         assertEquals(2, mCursor.getInt(mCursor.getColumnIndexOrThrow(COLUMN_ID_NAME)));
326         assertEquals(KEY2, mCursor.getString(mCursor.getColumnIndexOrThrow(COLUMN_KEY_NAME)));
327         assertEquals(VALUE2, mCursor.getInt(mCursor.getColumnIndexOrThrow(COLUMN_VALUE_NAME)));
328         mCursor.close();
329     }
330 
testQuery_WithSqlSelectionArgs()331     public void testQuery_WithSqlSelectionArgs() {
332         Bundle queryArgs = new Bundle();
333         queryArgs.putString(ContentResolver.QUERY_ARG_SQL_SELECTION, COLUMN_ID_NAME + "=?");
334         queryArgs.putStringArray(ContentResolver.QUERY_ARG_SQL_SELECTION_ARGS, new String[] {"1"});
335 
336         mCursor = mContentResolver.query(TABLE1_URI, null, queryArgs, null);
337         assertNotNull(mCursor);
338         assertEquals(1, mCursor.getCount());
339         assertEquals(3, mCursor.getColumnCount());
340 
341         mCursor.moveToFirst();
342         assertEquals(1, mCursor.getInt(mCursor.getColumnIndexOrThrow(COLUMN_ID_NAME)));
343         assertEquals(KEY1, mCursor.getString(mCursor.getColumnIndexOrThrow(COLUMN_KEY_NAME)));
344         assertEquals(VALUE1, mCursor.getInt(mCursor.getColumnIndexOrThrow(COLUMN_VALUE_NAME)));
345         mCursor.close();
346 
347         queryArgs.putString(ContentResolver.QUERY_ARG_SQL_SELECTION, COLUMN_KEY_NAME + "=?");
348         queryArgs.putStringArray(ContentResolver.QUERY_ARG_SQL_SELECTION_ARGS, new String[] {KEY3});
349         mCursor = mContentResolver.query(TABLE1_URI, null, queryArgs, null);
350         assertNotNull(mCursor);
351         assertEquals(1, mCursor.getCount());
352         assertEquals(3, mCursor.getColumnCount());
353 
354         mCursor.moveToFirst();
355         assertEquals(3, mCursor.getInt(mCursor.getColumnIndexOrThrow(COLUMN_ID_NAME)));
356         assertEquals(KEY3, mCursor.getString(mCursor.getColumnIndexOrThrow(COLUMN_KEY_NAME)));
357         assertEquals(VALUE3, mCursor.getInt(mCursor.getColumnIndexOrThrow(COLUMN_VALUE_NAME)));
358         mCursor.close();
359     }
360 
361     /*
362      * NOTE: this test is implicitly coupled to the implementation
363      * of MockContentProvider#query, specifically the facts:
364      *
365      * - it does *not* override the query w/ Bundle methods
366      * - it receives the auto-generated sql format arguments (supplied by the framework)
367      * - it is backed by sqlite and forwards the sql formatted args.
368      */
testQuery_SqlSortingFromBundleArgs()369     public void testQuery_SqlSortingFromBundleArgs() {
370 
371         mContentResolver.delete(TABLE1_URI, null, null);
372         ContentValues values = new ContentValues();
373 
374         values.put(COLUMN_KEY_NAME, "0");
375         values.put(COLUMN_VALUE_NAME, "abc");
376         mContentResolver.insert(TABLE1_URI, values);
377 
378         values.put(COLUMN_KEY_NAME, "1");
379         values.put(COLUMN_VALUE_NAME, "DEF");
380         mContentResolver.insert(TABLE1_URI, values);
381 
382         values.put(COLUMN_KEY_NAME, "2");
383         values.put(COLUMN_VALUE_NAME, "ghi");
384         mContentResolver.insert(TABLE1_URI, values);
385 
386         String[] sortCols = new String[] { COLUMN_VALUE_NAME };
387         Bundle queryArgs = new Bundle();
388         queryArgs.putStringArray(
389                 ContentResolver.QUERY_ARG_SORT_COLUMNS,
390                 sortCols);
391 
392         // Sort ascending...
393         queryArgs.putInt(
394                 ContentResolver.QUERY_ARG_SORT_DIRECTION,
395                 ContentResolver.QUERY_SORT_DIRECTION_ASCENDING);
396 
397         mCursor = mContentResolver.query(TABLE1_URI, sortCols, queryArgs, null);
398         int col = mCursor.getColumnIndexOrThrow(COLUMN_VALUE_NAME);
399 
400         mCursor.moveToNext();
401         assertEquals("DEF", mCursor.getString(col));
402         mCursor.moveToNext();
403         assertEquals("abc", mCursor.getString(col));
404         mCursor.moveToNext();
405         assertEquals("ghi", mCursor.getString(col));
406 
407         mCursor.close();
408 
409         // Nocase collation, descending...
410         queryArgs.putInt(
411                 ContentResolver.QUERY_ARG_SORT_DIRECTION,
412                 ContentResolver.QUERY_SORT_DIRECTION_DESCENDING);
413         queryArgs.putInt(
414                 ContentResolver.QUERY_ARG_SORT_COLLATION,
415                 java.text.Collator.SECONDARY);
416 
417         mCursor = mContentResolver.query(TABLE1_URI, null, queryArgs, null);
418         col = mCursor.getColumnIndexOrThrow(COLUMN_VALUE_NAME);
419 
420         mCursor.moveToNext();
421         assertEquals("ghi", mCursor.getString(col));
422         mCursor.moveToNext();
423         assertEquals("DEF", mCursor.getString(col));
424         mCursor.moveToNext();
425         assertEquals("abc", mCursor.getString(col));
426 
427         mCursor.close();
428     }
429 
430     /**
431      * Verifies that paging information is correctly relayed, and that
432      * honored arguments from a supporting client are returned correctly.
433      */
testQuery_PagedResults()434     public void testQuery_PagedResults() {
435 
436         Bundle queryArgs = new Bundle();
437         queryArgs.putInt(ContentResolver.QUERY_ARG_OFFSET, 10);
438         queryArgs.putInt(ContentResolver.QUERY_ARG_LIMIT, 3);
439         queryArgs.putInt(TestPagingContentProvider.RECORD_COUNT, 100);
440 
441         mCursor = mContentResolver.query(
442                 TestPagingContentProvider.PAGED_DATA_URI, null, queryArgs, null);
443 
444         Bundle extras = mCursor.getExtras();
445         extras = extras != null ? extras : Bundle.EMPTY;
446 
447         assertEquals(3, mCursor.getCount());
448         assertTrue(extras.containsKey(ContentResolver.EXTRA_TOTAL_COUNT));
449         assertEquals(100, extras.getInt(ContentResolver.EXTRA_TOTAL_COUNT));
450 
451         String[] honoredArgs = extras.getStringArray(ContentResolver.EXTRA_HONORED_ARGS);
452         assertNotNull(honoredArgs);
453         assertTrue(ArrayUtils.contains(honoredArgs, ContentResolver.QUERY_ARG_OFFSET));
454         assertTrue(ArrayUtils.contains(honoredArgs, ContentResolver.QUERY_ARG_LIMIT));
455 
456         int col = mCursor.getColumnIndexOrThrow(TestPagingContentProvider.COLUMN_POS);
457 
458         mCursor.moveToNext();
459         assertEquals(10, mCursor.getInt(col));
460         mCursor.moveToNext();
461         assertEquals(11, mCursor.getInt(col));
462         mCursor.moveToNext();
463         assertEquals(12, mCursor.getInt(col));
464 
465         assertFalse(mCursor.moveToNext());
466 
467         mCursor.close();
468     }
469 
testQuery_NullUriThrows()470     public void testQuery_NullUriThrows() {
471         try {
472             mContentResolver.query(null, null, null, null, null);
473             fail("did not throw NullPointerException when uri is null.");
474         } catch (NullPointerException e) {
475             //expected.
476         }
477     }
478 
testCrashingQuery()479     public void testCrashingQuery() {
480         try {
481             MockContentProvider.setCrashOnLaunch(mContext, true);
482             mCursor = mContentResolver.query(REMOTE_CRASH_URI, null, null, null, null);
483             assertFalse(MockContentProvider.getCrashOnLaunch(mContext));
484         } finally {
485             MockContentProvider.setCrashOnLaunch(mContext, false);
486         }
487 
488         assertNotNull(mCursor);
489         assertEquals(3, mCursor.getCount());
490         assertEquals(3, mCursor.getColumnCount());
491 
492         mCursor.moveToLast();
493         assertEquals(3, mCursor.getInt(mCursor.getColumnIndexOrThrow(COLUMN_ID_NAME)));
494         assertEquals(KEY3, mCursor.getString(mCursor.getColumnIndexOrThrow(COLUMN_KEY_NAME)));
495         assertEquals(VALUE3, mCursor.getInt(mCursor.getColumnIndexOrThrow(COLUMN_VALUE_NAME)));
496 
497         mCursor.moveToPrevious();
498         assertEquals(2, mCursor.getInt(mCursor.getColumnIndexOrThrow(COLUMN_ID_NAME)));
499         assertEquals(KEY2, mCursor.getString(mCursor.getColumnIndexOrThrow(COLUMN_KEY_NAME)));
500         assertEquals(VALUE2, mCursor.getInt(mCursor.getColumnIndexOrThrow(COLUMN_VALUE_NAME)));
501         mCursor.close();
502     }
503 
testCancelableQuery_WhenNotCanceled_ReturnsResultSet()504     public void testCancelableQuery_WhenNotCanceled_ReturnsResultSet() {
505         CancellationSignal cancellationSignal = new CancellationSignal();
506 
507         Cursor cursor = mContentResolver.query(TABLE1_URI, null, null, null, null,
508                 cancellationSignal);
509         assertEquals(3, cursor.getCount());
510         cursor.close();
511     }
512 
testCancelableQuery_WhenCanceledBeforeQuery_ThrowsImmediately()513     public void testCancelableQuery_WhenCanceledBeforeQuery_ThrowsImmediately() {
514         CancellationSignal cancellationSignal = new CancellationSignal();
515         cancellationSignal.cancel();
516 
517         try {
518             mContentResolver.query(TABLE1_URI, null, null, null, null, cancellationSignal);
519             fail("Expected OperationCanceledException");
520         } catch (OperationCanceledException ex) {
521             // expected
522         }
523     }
524 
testCancelableQuery_WhenCanceledDuringLongRunningQuery_CancelsQueryAndThrows()525     public void testCancelableQuery_WhenCanceledDuringLongRunningQuery_CancelsQueryAndThrows() {
526         // Populate a table with a bunch of integers.
527         mContentResolver.delete(TABLE1_URI, null, null);
528         ContentValues values = new ContentValues();
529         for (int i = 0; i < 100; i++) {
530             values.put(COLUMN_KEY_NAME, i);
531             values.put(COLUMN_VALUE_NAME, i);
532             mContentResolver.insert(TABLE1_URI, values);
533         }
534 
535         for (int i = 0; i < 5; i++) {
536             final CancellationSignal cancellationSignal = new CancellationSignal();
537             Thread cancellationThread = new Thread() {
538                 @Override
539                 public void run() {
540                     try {
541                         Thread.sleep(300);
542                     } catch (InterruptedException ex) {
543                     }
544                     cancellationSignal.cancel();
545                 }
546             };
547             try {
548                 // Build an unsatisfiable 5-way cross-product query over 100 values but
549                 // produces no output.  This should force SQLite to loop for a long time
550                 // as it tests 10^10 combinations.
551                 cancellationThread.start();
552 
553                 final long startTime = System.nanoTime();
554                 try {
555                     mContentResolver.query(TABLE1_CROSS_URI, null,
556                             "a.value + b.value + c.value + d.value + e.value > 1000000",
557                             null, null, cancellationSignal);
558                     fail("Expected OperationCanceledException");
559                 } catch (OperationCanceledException ex) {
560                     // expected
561                 }
562 
563                 // We want to confirm that the query really was running and then got
564                 // canceled midway.
565                 final long waitTime = System.nanoTime() - startTime;
566                 if (waitTime > 150 * 1000000L && waitTime < 600 * 1000000L) {
567                     return; // success!
568                 }
569             } finally {
570                 try {
571                     cancellationThread.join();
572                 } catch (InterruptedException e) {
573                 }
574             }
575         }
576 
577         // Occasionally we might miss the timing deadline due to factors in the
578         // environment, but if after several trials we still couldn't demonstrate
579         // that the query was canceled, then the test must be broken.
580         fail("Could not prove that the query actually canceled midway during execution.");
581     }
582 
testOpenInputStream()583     public void testOpenInputStream() throws IOException {
584         final Uri uri = Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE +
585                 "://" + TEST_PACKAGE_NAME + "/" + R.drawable.pass);
586 
587         InputStream is = mContentResolver.openInputStream(uri);
588         assertNotNull(is);
589         is.close();
590 
591         final Uri invalidUri = Uri.parse("abc");
592         try {
593             mContentResolver.openInputStream(invalidUri);
594             fail("did not throw FileNotFoundException when uri is invalid.");
595         } catch (FileNotFoundException e) {
596             //expected.
597         }
598     }
599 
testOpenOutputStream()600     public void testOpenOutputStream() throws IOException {
601         Uri uri = Uri.parse(ContentResolver.SCHEME_FILE + "://" +
602                 getContext().getCacheDir().getAbsolutePath() +
603                 "/temp.jpg");
604         OutputStream os = mContentResolver.openOutputStream(uri);
605         assertNotNull(os);
606         os.close();
607 
608         os = mContentResolver.openOutputStream(uri, "wa");
609         assertNotNull(os);
610         os.close();
611 
612         uri = Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE +
613                 "://" + TEST_PACKAGE_NAME + "/" + R.raw.testimage);
614         try {
615             mContentResolver.openOutputStream(uri);
616             fail("did not throw FileNotFoundException when scheme is not accepted.");
617         } catch (FileNotFoundException e) {
618             //expected.
619         }
620 
621         try {
622             mContentResolver.openOutputStream(uri, "w");
623             fail("did not throw FileNotFoundException when scheme is not accepted.");
624         } catch (FileNotFoundException e) {
625             //expected.
626         }
627 
628         Uri invalidUri = Uri.parse("abc");
629         try {
630             mContentResolver.openOutputStream(invalidUri);
631             fail("did not throw FileNotFoundException when uri is invalid.");
632         } catch (FileNotFoundException e) {
633             //expected.
634         }
635 
636         try {
637             mContentResolver.openOutputStream(invalidUri, "w");
638             fail("did not throw FileNotFoundException when uri is invalid.");
639         } catch (FileNotFoundException e) {
640             //expected.
641         }
642     }
643 
testOpenAssetFileDescriptor()644     public void testOpenAssetFileDescriptor() throws IOException {
645         Uri uri = Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE +
646                 "://" + TEST_PACKAGE_NAME + "/" + R.raw.testimage);
647 
648         AssetFileDescriptor afd = mContentResolver.openAssetFileDescriptor(uri, "r");
649         assertNotNull(afd);
650         afd.close();
651 
652         try {
653             mContentResolver.openAssetFileDescriptor(uri, "d");
654             fail("did not throw FileNotFoundException when mode is unknown.");
655         } catch (FileNotFoundException e) {
656             //expected.
657         }
658 
659         Uri invalidUri = Uri.parse("abc");
660         try {
661             mContentResolver.openAssetFileDescriptor(invalidUri, "r");
662             fail("did not throw FileNotFoundException when uri is invalid.");
663         } catch (FileNotFoundException e) {
664             //expected.
665         }
666     }
667 
consumeAssetFileDescriptor(AssetFileDescriptor afd)668     private String consumeAssetFileDescriptor(AssetFileDescriptor afd)
669             throws IOException {
670         FileInputStream stream = null;
671         try {
672             stream = afd.createInputStream();
673             InputStreamReader reader = new InputStreamReader(stream, "UTF-8");
674 
675             // Got it...  copy the stream into a local string and return it.
676             StringBuilder builder = new StringBuilder(128);
677             char[] buffer = new char[8192];
678             int len;
679             while ((len=reader.read(buffer)) > 0) {
680                 builder.append(buffer, 0, len);
681             }
682             return builder.toString();
683 
684         } finally {
685             if (stream != null) {
686                 try {
687                     stream.close();
688                 } catch (IOException e) {
689                 }
690             }
691         }
692 
693     }
694 
testCrashingOpenAssetFileDescriptor()695     public void testCrashingOpenAssetFileDescriptor() throws IOException {
696         AssetFileDescriptor afd = null;
697         try {
698             MockContentProvider.setCrashOnLaunch(mContext, true);
699             afd = mContentResolver.openAssetFileDescriptor(REMOTE_CRASH_URI, "rw");
700             assertFalse(MockContentProvider.getCrashOnLaunch(mContext));
701             assertNotNull(afd);
702             String str = consumeAssetFileDescriptor(afd);
703             afd = null;
704             assertEquals(str, "This is the openAssetFile test data!");
705         } finally {
706             MockContentProvider.setCrashOnLaunch(mContext, false);
707             if (afd != null) {
708                 afd.close();
709             }
710         }
711 
712         // Make sure a content provider crash at this point won't hurt us.
713         ContentProviderClient uClient = mContentResolver.acquireUnstableContentProviderClient(
714                 REMOTE_AUTHORITY);
715         // Kill it.  Note that a bug at this point where it causes our own
716         // process to be killed will result in the entire test failing.
717         try {
718             Log.i("ContentResolverTest",
719                     "Killing remote client -- if test process goes away, that is why!");
720             uClient.delete(REMOTE_CRASH_URI, null, null);
721         } catch (RemoteException e) {
722         }
723         uClient.release();
724     }
725 
testCrashingOpenTypedAssetFileDescriptor()726     public void testCrashingOpenTypedAssetFileDescriptor() throws IOException {
727         AssetFileDescriptor afd = null;
728         try {
729             MockContentProvider.setCrashOnLaunch(mContext, true);
730             afd = mContentResolver.openTypedAssetFileDescriptor(
731                     REMOTE_CRASH_URI, "text/plain", null);
732             assertFalse(MockContentProvider.getCrashOnLaunch(mContext));
733             assertNotNull(afd);
734             String str = consumeAssetFileDescriptor(afd);
735             afd = null;
736             assertEquals(str, "This is the openTypedAssetFile test data!");
737         } finally {
738             MockContentProvider.setCrashOnLaunch(mContext, false);
739             if (afd != null) {
740                 afd.close();
741             }
742         }
743 
744         // Make sure a content provider crash at this point won't hurt us.
745         ContentProviderClient uClient = mContentResolver.acquireUnstableContentProviderClient(
746                 REMOTE_AUTHORITY);
747         // Kill it.  Note that a bug at this point where it causes our own
748         // process to be killed will result in the entire test failing.
749         try {
750             Log.i("ContentResolverTest",
751                     "Killing remote client -- if test process goes away, that is why!");
752             uClient.delete(REMOTE_CRASH_URI, null, null);
753         } catch (RemoteException e) {
754         }
755         uClient.release();
756     }
757 
testOpenFileDescriptor()758     public void testOpenFileDescriptor() throws IOException {
759         Uri uri = Uri.parse(ContentResolver.SCHEME_FILE + "://" +
760                 getContext().getCacheDir().getAbsolutePath() +
761                 "/temp.jpg");
762         ParcelFileDescriptor pfd = mContentResolver.openFileDescriptor(uri, "w");
763         assertNotNull(pfd);
764         pfd.close();
765 
766         try {
767             mContentResolver.openFileDescriptor(uri, "d");
768             fail("did not throw IllegalArgumentException when mode is unknown.");
769         } catch (IllegalArgumentException e) {
770             //expected.
771         }
772 
773         Uri invalidUri = Uri.parse("abc");
774         try {
775             mContentResolver.openFileDescriptor(invalidUri, "w");
776             fail("did not throw FileNotFoundException when uri is invalid.");
777         } catch (FileNotFoundException e) {
778             //expected.
779         }
780 
781         uri = Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE +
782                 "://" + TEST_PACKAGE_NAME + "/" + R.raw.testimage);
783         try {
784             mContentResolver.openFileDescriptor(uri, "w");
785             fail("did not throw FileNotFoundException when scheme is not accepted.");
786         } catch (FileNotFoundException e) {
787             //expected.
788         }
789     }
790 
testInsert()791     public void testInsert() {
792         String key4 = "key4";
793         String key5 = "key5";
794         int value4 = 4;
795         int value5 = 5;
796         String key4Selection = COLUMN_KEY_NAME + "=\"" + key4 + "\"";
797 
798         mCursor = mContentResolver.query(TABLE1_URI, null, key4Selection, null, null);
799         assertEquals(0, mCursor.getCount());
800         mCursor.close();
801 
802         ContentValues values = new ContentValues();
803         values.put(COLUMN_KEY_NAME, key4);
804         values.put(COLUMN_VALUE_NAME, value4);
805         Uri uri = mContentResolver.insert(TABLE1_URI, values);
806         assertNotNull(uri);
807 
808         mCursor = mContentResolver.query(TABLE1_URI, null, key4Selection, null, null);
809         assertNotNull(mCursor);
810         assertEquals(1, mCursor.getCount());
811 
812         mCursor.moveToFirst();
813         assertEquals(4, mCursor.getInt(mCursor.getColumnIndexOrThrow(COLUMN_ID_NAME)));
814         assertEquals(key4, mCursor.getString(mCursor.getColumnIndexOrThrow(COLUMN_KEY_NAME)));
815         assertEquals(value4, mCursor.getInt(mCursor.getColumnIndexOrThrow(COLUMN_VALUE_NAME)));
816         mCursor.close();
817 
818         values.put(COLUMN_KEY_NAME, key5);
819         values.put(COLUMN_VALUE_NAME, value5);
820         uri = mContentResolver.insert(TABLE1_URI, values);
821         assertNotNull(uri);
822 
823         // check returned uri
824         mCursor = mContentResolver.query(uri, null, null, null, null);
825         assertNotNull(mCursor);
826         assertEquals(1, mCursor.getCount());
827 
828         mCursor.moveToLast();
829         assertEquals(5, mCursor.getInt(mCursor.getColumnIndexOrThrow(COLUMN_ID_NAME)));
830         assertEquals(key5, mCursor.getString(mCursor.getColumnIndexOrThrow(COLUMN_KEY_NAME)));
831         assertEquals(value5, mCursor.getInt(mCursor.getColumnIndexOrThrow(COLUMN_VALUE_NAME)));
832         mCursor.close();
833 
834         try {
835             mContentResolver.insert(null, values);
836             fail("did not throw NullPointerException when uri is null.");
837         } catch (NullPointerException e) {
838             //expected.
839         }
840     }
841 
testBulkInsert()842     public void testBulkInsert() {
843         String key4 = "key4";
844         String key5 = "key5";
845         int value4 = 4;
846         int value5 = 5;
847 
848         mCursor = mContentResolver.query(TABLE1_URI, null, null, null, null);
849         assertNotNull(mCursor);
850         assertEquals(3, mCursor.getCount());
851         mCursor.close();
852 
853         ContentValues[] cvs = new ContentValues[2];
854         cvs[0] = new ContentValues();
855         cvs[0].put(COLUMN_KEY_NAME, key4);
856         cvs[0].put(COLUMN_VALUE_NAME, value4);
857 
858         cvs[1] = new ContentValues();
859         cvs[1].put(COLUMN_KEY_NAME, key5);
860         cvs[1].put(COLUMN_VALUE_NAME, value5);
861 
862         assertEquals(2, mContentResolver.bulkInsert(TABLE1_URI, cvs));
863         mCursor = mContentResolver.query(TABLE1_URI, null, null, null, null);
864         assertNotNull(mCursor);
865         assertEquals(5, mCursor.getCount());
866 
867         mCursor.moveToLast();
868         assertEquals(5, mCursor.getInt(mCursor.getColumnIndexOrThrow(COLUMN_ID_NAME)));
869         assertEquals(key5, mCursor.getString(mCursor.getColumnIndexOrThrow(COLUMN_KEY_NAME)));
870         assertEquals(value5, mCursor.getInt(mCursor.getColumnIndexOrThrow(COLUMN_VALUE_NAME)));
871 
872         mCursor.moveToPrevious();
873         assertEquals(4, mCursor.getInt(mCursor.getColumnIndexOrThrow(COLUMN_ID_NAME)));
874         assertEquals(key4, mCursor.getString(mCursor.getColumnIndexOrThrow(COLUMN_KEY_NAME)));
875         assertEquals(value4, mCursor.getInt(mCursor.getColumnIndexOrThrow(COLUMN_VALUE_NAME)));
876         mCursor.close();
877 
878         try {
879             mContentResolver.bulkInsert(null, cvs);
880             fail("did not throw NullPointerException when uri is null.");
881         } catch (NullPointerException e) {
882             //expected.
883         }
884     }
885 
testDelete()886     public void testDelete() {
887         mCursor = mContentResolver.query(TABLE1_URI, null, null, null, null);
888         assertNotNull(mCursor);
889         assertEquals(3, mCursor.getCount());
890         mCursor.close();
891 
892         assertEquals(3, mContentResolver.delete(TABLE1_URI, null, null));
893         mCursor = mContentResolver.query(TABLE1_URI, null, null, null, null);
894         assertNotNull(mCursor);
895         assertEquals(0, mCursor.getCount());
896         mCursor.close();
897 
898         // add three rows to database.
899         ContentValues values = new ContentValues();
900         values.put(COLUMN_KEY_NAME, KEY1);
901         values.put(COLUMN_VALUE_NAME, VALUE1);
902         mContentResolver.insert(TABLE1_URI, values);
903 
904         values.put(COLUMN_KEY_NAME, KEY2);
905         values.put(COLUMN_VALUE_NAME, VALUE2);
906         mContentResolver.insert(TABLE1_URI, values);
907 
908         values.put(COLUMN_KEY_NAME, KEY3);
909         values.put(COLUMN_VALUE_NAME, VALUE3);
910         mContentResolver.insert(TABLE1_URI, values);
911 
912         // test delete row using selection
913         String selection = COLUMN_ID_NAME + "=2";
914         assertEquals(1, mContentResolver.delete(TABLE1_URI, selection, null));
915 
916         mCursor = mContentResolver.query(TABLE1_URI, null, null, null, null);
917         assertNotNull(mCursor);
918         assertEquals(2, mCursor.getCount());
919 
920         mCursor.moveToFirst();
921         assertEquals(1, mCursor.getInt(mCursor.getColumnIndexOrThrow(COLUMN_ID_NAME)));
922         assertEquals(KEY1, mCursor.getString(mCursor.getColumnIndexOrThrow(COLUMN_KEY_NAME)));
923         assertEquals(VALUE1, mCursor.getInt(mCursor.getColumnIndexOrThrow(COLUMN_VALUE_NAME)));
924 
925         mCursor.moveToNext();
926         assertEquals(3, mCursor.getInt(mCursor.getColumnIndexOrThrow(COLUMN_ID_NAME)));
927         assertEquals(KEY3, mCursor.getString(mCursor.getColumnIndexOrThrow(COLUMN_KEY_NAME)));
928         assertEquals(VALUE3, mCursor.getInt(mCursor.getColumnIndexOrThrow(COLUMN_VALUE_NAME)));
929         mCursor.close();
930 
931         selection = COLUMN_VALUE_NAME + "=3";
932         assertEquals(1, mContentResolver.delete(TABLE1_URI, selection, null));
933 
934         mCursor = mContentResolver.query(TABLE1_URI, null, null, null, null);
935         assertNotNull(mCursor);
936         assertEquals(1, mCursor.getCount());
937 
938         mCursor.moveToFirst();
939         assertEquals(1, mCursor.getInt(mCursor.getColumnIndexOrThrow(COLUMN_ID_NAME)));
940         assertEquals(KEY1, mCursor.getString(mCursor.getColumnIndexOrThrow(COLUMN_KEY_NAME)));
941         assertEquals(VALUE1, mCursor.getInt(mCursor.getColumnIndexOrThrow(COLUMN_VALUE_NAME)));
942         mCursor.close();
943 
944         selection = COLUMN_KEY_NAME + "=\"" + KEY1 + "\"";
945         assertEquals(1, mContentResolver.delete(TABLE1_URI, selection, null));
946 
947         mCursor = mContentResolver.query(TABLE1_URI, null, null, null, null);
948         assertNotNull(mCursor);
949         assertEquals(0, mCursor.getCount());
950         mCursor.close();
951 
952         try {
953             mContentResolver.delete(null, null, null);
954             fail("did not throw NullPointerException when uri is null.");
955         } catch (NullPointerException e) {
956             //expected.
957         }
958     }
959 
testUpdate()960     public void testUpdate() {
961         ContentValues values = new ContentValues();
962         String key10 = "key10";
963         String key20 = "key20";
964         int value10 = 10;
965         int value20 = 20;
966 
967         values.put(COLUMN_KEY_NAME, key10);
968         values.put(COLUMN_VALUE_NAME, value10);
969 
970         // test update all the rows.
971         assertEquals(3, mContentResolver.update(TABLE1_URI, values, null, null));
972         mCursor = mContentResolver.query(TABLE1_URI, null, null, null, null);
973         assertNotNull(mCursor);
974         assertEquals(3, mCursor.getCount());
975 
976         mCursor.moveToFirst();
977         assertEquals(1, mCursor.getInt(mCursor.getColumnIndexOrThrow(COLUMN_ID_NAME)));
978         assertEquals(key10, mCursor.getString(mCursor.getColumnIndexOrThrow(COLUMN_KEY_NAME)));
979         assertEquals(value10, mCursor.getInt(mCursor.getColumnIndexOrThrow(COLUMN_VALUE_NAME)));
980 
981         mCursor.moveToNext();
982         assertEquals(2, mCursor.getInt(mCursor.getColumnIndexOrThrow(COLUMN_ID_NAME)));
983         assertEquals(key10, mCursor.getString(mCursor.getColumnIndexOrThrow(COLUMN_KEY_NAME)));
984         assertEquals(value10, mCursor.getInt(mCursor.getColumnIndexOrThrow(COLUMN_VALUE_NAME)));
985 
986         mCursor.moveToLast();
987         assertEquals(3, mCursor.getInt(mCursor.getColumnIndexOrThrow(COLUMN_ID_NAME)));
988         assertEquals(key10, mCursor.getString(mCursor.getColumnIndexOrThrow(COLUMN_KEY_NAME)));
989         assertEquals(value10, mCursor.getInt(mCursor.getColumnIndexOrThrow(COLUMN_VALUE_NAME)));
990         mCursor.close();
991 
992         // test update one row using selection.
993         String selection = COLUMN_ID_NAME + "=1";
994         values.put(COLUMN_KEY_NAME, key20);
995         values.put(COLUMN_VALUE_NAME, value20);
996 
997         assertEquals(1, mContentResolver.update(TABLE1_URI, values, selection, null));
998         mCursor = mContentResolver.query(TABLE1_URI, null, null, null, null);
999         assertNotNull(mCursor);
1000         assertEquals(3, mCursor.getCount());
1001 
1002         mCursor.moveToFirst();
1003         assertEquals(1, mCursor.getInt(mCursor.getColumnIndexOrThrow(COLUMN_ID_NAME)));
1004         assertEquals(key20, mCursor.getString(mCursor.getColumnIndexOrThrow(COLUMN_KEY_NAME)));
1005         assertEquals(value20, mCursor.getInt(mCursor.getColumnIndexOrThrow(COLUMN_VALUE_NAME)));
1006 
1007         mCursor.moveToNext();
1008         assertEquals(2, mCursor.getInt(mCursor.getColumnIndexOrThrow(COLUMN_ID_NAME)));
1009         assertEquals(key10, mCursor.getString(mCursor.getColumnIndexOrThrow(COLUMN_KEY_NAME)));
1010         assertEquals(value10, mCursor.getInt(mCursor.getColumnIndexOrThrow(COLUMN_VALUE_NAME)));
1011 
1012         mCursor.moveToLast();
1013         assertEquals(3, mCursor.getInt(mCursor.getColumnIndexOrThrow(COLUMN_ID_NAME)));
1014         assertEquals(key10, mCursor.getString(mCursor.getColumnIndexOrThrow(COLUMN_KEY_NAME)));
1015         assertEquals(value10, mCursor.getInt(mCursor.getColumnIndexOrThrow(COLUMN_VALUE_NAME)));
1016         mCursor.close();
1017 
1018         try {
1019             mContentResolver.update(null, values, null, null);
1020             fail("did not throw NullPointerException when uri is null.");
1021         } catch (NullPointerException e) {
1022             //expected.
1023         }
1024 
1025         // javadoc says it will throw NullPointerException when values are null,
1026         // but actually, it throws IllegalArgumentException here.
1027         try {
1028             mContentResolver.update(TABLE1_URI, null, null, null);
1029             fail("did not throw IllegalArgumentException when values are null.");
1030         } catch (IllegalArgumentException e) {
1031             //expected.
1032         }
1033     }
1034 
testRefresh_DefaultImplReturnsFalse()1035     public void testRefresh_DefaultImplReturnsFalse() {
1036         boolean refreshed = mContentResolver.refresh(TABLE1_URI, null, null);
1037         assertFalse(refreshed);
1038         MockContentProvider.assertRefreshed(TABLE1_URI);
1039     }
1040 
testRefresh_ReturnsProviderValue()1041     public void testRefresh_ReturnsProviderValue() {
1042         try {
1043             MockContentProvider.setRefreshReturnValue(true);
1044             boolean refreshed = mContentResolver.refresh(TABLE1_URI, null, null);
1045             assertTrue(refreshed);
1046             MockContentProvider.assertRefreshed(TABLE1_URI);
1047         } finally {
1048             MockContentProvider.setRefreshReturnValue(false);
1049         }
1050     }
1051 
testRefresh_NullUriThrowsImmediately()1052     public void testRefresh_NullUriThrowsImmediately() {
1053         try {
1054             mContentResolver.refresh(null, null, null);
1055             fail("did not throw NullPointerException when uri is null.");
1056         } catch (NullPointerException e) {
1057             //expected.
1058         }
1059     }
1060 
testRefresh_CancellableThrowsImmediately()1061     public void testRefresh_CancellableThrowsImmediately() {
1062         CancellationSignal cancellationSignal = new CancellationSignal();
1063         cancellationSignal.cancel();
1064 
1065         try {
1066             mContentResolver.refresh(TABLE1_URI, null, cancellationSignal);
1067             fail("Expected OperationCanceledException");
1068         } catch (OperationCanceledException ex) {
1069             // expected
1070         }
1071     }
1072 
testRegisterContentObserver()1073     public void testRegisterContentObserver() {
1074         final MockContentObserver mco = new MockContentObserver();
1075 
1076         mContentResolver.registerContentObserver(TABLE1_URI, true, mco);
1077         assertFalse(mco.hadOnChanged());
1078 
1079         ContentValues values = new ContentValues();
1080         values.put(COLUMN_KEY_NAME, "key10");
1081         values.put(COLUMN_VALUE_NAME, 10);
1082         mContentResolver.update(TABLE1_URI, values, null, null);
1083         new PollingCheck() {
1084             @Override
1085             protected boolean check() {
1086                 return mco.hadOnChanged();
1087             }
1088         }.run();
1089 
1090         mco.reset();
1091         mContentResolver.unregisterContentObserver(mco);
1092         assertFalse(mco.hadOnChanged());
1093         mContentResolver.update(TABLE1_URI, values, null, null);
1094 
1095         assertFalse(mco.hadOnChanged());
1096 
1097         try {
1098             mContentResolver.registerContentObserver(null, false, mco);
1099             fail("did not throw NullPointerException or IllegalArgumentException when uri is null.");
1100         } catch (NullPointerException e) {
1101             //expected.
1102         } catch (IllegalArgumentException e) {
1103             // also expected
1104         }
1105 
1106         try {
1107             mContentResolver.registerContentObserver(TABLE1_URI, false, null);
1108             fail("did not throw NullPointerException when register null content observer.");
1109         } catch (NullPointerException e) {
1110             //expected.
1111         }
1112 
1113         try {
1114             mContentResolver.unregisterContentObserver(null);
1115             fail("did not throw NullPointerException when unregister null content observer.");
1116         } catch (NullPointerException e) {
1117             //expected.
1118         }
1119     }
1120 
testRegisterContentObserverDescendantBehavior()1121     public void testRegisterContentObserverDescendantBehavior() throws Exception {
1122         final MockContentObserver mco1 = new MockContentObserver();
1123         final MockContentObserver mco2 = new MockContentObserver();
1124 
1125         // Register one content observer with notifyDescendants set to false, and
1126         // another with true.
1127         mContentResolver.registerContentObserver(LEVEL2_URI, false, mco1);
1128         mContentResolver.registerContentObserver(LEVEL2_URI, true, mco2);
1129 
1130         // Initially nothing has happened.
1131         assertFalse(mco1.hadOnChanged());
1132         assertFalse(mco2.hadOnChanged());
1133 
1134         // Fire a change with the exact URI.
1135         // Should signal both observers due to exact match, notifyDescendants doesn't matter.
1136         mContentResolver.notifyChange(LEVEL2_URI, null);
1137         Thread.sleep(200);
1138         assertTrue(mco1.hadOnChanged());
1139         assertTrue(mco2.hadOnChanged());
1140         mco1.reset();
1141         mco2.reset();
1142 
1143         // Fire a change with a descendant URI.
1144         // Should only signal observer with notifyDescendants set to true.
1145         mContentResolver.notifyChange(LEVEL3_URI, null);
1146         Thread.sleep(200);
1147         assertFalse(mco1.hadOnChanged());
1148         assertTrue(mco2.hadOnChanged());
1149         mco2.reset();
1150 
1151         // Fire a change with an ancestor URI.
1152         // Should signal both observers due to ancestry, notifyDescendants doesn't matter.
1153         mContentResolver.notifyChange(LEVEL1_URI, null);
1154         Thread.sleep(200);
1155         assertTrue(mco1.hadOnChanged());
1156         assertTrue(mco2.hadOnChanged());
1157         mco1.reset();
1158         mco2.reset();
1159 
1160         // Fire a change with an unrelated URI.
1161         // Should signal neither observer.
1162         mContentResolver.notifyChange(TABLE1_URI, null);
1163         Thread.sleep(200);
1164         assertFalse(mco1.hadOnChanged());
1165         assertFalse(mco2.hadOnChanged());
1166     }
1167 
testNotifyChange1()1168     public void testNotifyChange1() {
1169         final MockContentObserver mco = new MockContentObserver();
1170 
1171         mContentResolver.registerContentObserver(TABLE1_URI, true, mco);
1172         assertFalse(mco.hadOnChanged());
1173 
1174         mContentResolver.notifyChange(TABLE1_URI, mco);
1175         new PollingCheck() {
1176             @Override
1177             protected boolean check() {
1178                 return mco.hadOnChanged();
1179             }
1180         }.run();
1181 
1182         mContentResolver.unregisterContentObserver(mco);
1183     }
1184 
testNotifyChange2()1185     public void testNotifyChange2() {
1186         final MockContentObserver mco = new MockContentObserver();
1187 
1188         mContentResolver.registerContentObserver(TABLE1_URI, true, mco);
1189         assertFalse(mco.hadOnChanged());
1190 
1191         mContentResolver.notifyChange(TABLE1_URI, mco, false);
1192         new PollingCheck() {
1193             @Override
1194             protected boolean check() {
1195                 return mco.hadOnChanged();
1196             }
1197         }.run();
1198 
1199         mContentResolver.unregisterContentObserver(mco);
1200     }
1201 
testStartCancelSync()1202     public void testStartCancelSync() {
1203         Bundle extras = new Bundle();
1204 
1205         extras.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true);
1206 
1207         ContentResolver.requestSync(ACCOUNT, AUTHORITY, extras);
1208         //FIXME: how to get the result to assert.
1209 
1210         ContentResolver.cancelSync(ACCOUNT, AUTHORITY);
1211         //FIXME: how to assert.
1212     }
1213 
testStartSyncFailure()1214     public void testStartSyncFailure() {
1215         try {
1216             ContentResolver.requestSync(null, null, null);
1217             fail("did not throw IllegalArgumentException when extras is null.");
1218         } catch (IllegalArgumentException e) {
1219             //expected.
1220         }
1221     }
1222 
testValidateSyncExtrasBundle()1223     public void testValidateSyncExtrasBundle() {
1224         Bundle extras = new Bundle();
1225         extras.putInt("Integer", 20);
1226         extras.putLong("Long", 10l);
1227         extras.putBoolean("Boolean", true);
1228         extras.putFloat("Float", 5.5f);
1229         extras.putDouble("Double", 2.5);
1230         extras.putString("String", "cts");
1231         extras.putCharSequence("CharSequence", null);
1232 
1233         ContentResolver.validateSyncExtrasBundle(extras);
1234 
1235         extras.putChar("Char", 'a'); // type Char is invalid
1236         try {
1237             ContentResolver.validateSyncExtrasBundle(extras);
1238             fail("did not throw IllegalArgumentException when extras is invalide.");
1239         } catch (IllegalArgumentException e) {
1240             //expected.
1241         }
1242     }
1243 
1244     @AppModeFull
testHangRecover()1245     public void testHangRecover() throws Exception {
1246         InstrumentationRegistry.getInstrumentation().getUiAutomation()
1247                 .adoptShellPermissionIdentity(android.Manifest.permission.REMOVE_TASKS);
1248 
1249         final CountDownLatch latch = new CountDownLatch(1);
1250         new Thread(() -> {
1251             final ContentProviderClient client = mContentResolver
1252                     .acquireUnstableContentProviderClient(REMOTE_AUTHORITY);
1253             client.setDetectNotResponding(2_000);
1254             try {
1255                 client.query(REMOTE_HANG_URI, null, null, null);
1256                 fail("Funky, we somehow returned?");
1257             } catch (RemoteException e) {
1258                 latch.countDown();
1259             }
1260         }).start();
1261 
1262         // The remote process should have been killed after the ANR was detected
1263         // above, causing our pending call to return and release our latch above
1264         // within 10 seconds; if our Binder thread hasn't been freed, then we
1265         // fail with a timeout.
1266         latch.await(10, TimeUnit.SECONDS);
1267     }
1268 
testGetTypeInfo()1269     public void testGetTypeInfo() throws Exception {
1270         for (String mimeType : new String[] {
1271                 "image/png",
1272                 "IMage/PnG",
1273                 "image/x-custom",
1274                 "application/x-flac",
1275                 "application/rdf+xml",
1276                 "x-custom/x-custom",
1277         }) {
1278             final MimeTypeInfo ti = mContentResolver.getTypeInfo(mimeType);
1279             assertNotNull(ti);
1280             assertNotNull(ti.getLabel());
1281             assertNotNull(ti.getContentDescription());
1282             assertNotNull(ti.getIcon());
1283         }
1284     }
1285 
testGetTypeInfo_Invalid()1286     public void testGetTypeInfo_Invalid() throws Exception {
1287         try {
1288             mContentResolver.getTypeInfo(null);
1289             fail("Expected exception for null");
1290         } catch (NullPointerException expected) {
1291         }
1292     }
1293 
testWrapContentProvider()1294     public void testWrapContentProvider() throws Exception {
1295         try (ContentProviderClient local = getContext().getContentResolver()
1296                 .acquireContentProviderClient(AUTHORITY)) {
1297             final ContentResolver resolver = ContentResolver.wrap(local.getLocalContentProvider());
1298             assertNotNull(resolver.getType(TABLE1_URI));
1299             try {
1300                 resolver.getType(REMOTE_TABLE1_URI);
1301                 fail();
1302             } catch (SecurityException | IllegalArgumentException expected) {
1303             }
1304         }
1305     }
1306 
testWrapContentProviderClient()1307     public void testWrapContentProviderClient() throws Exception {
1308         try (ContentProviderClient remote = getContext().getContentResolver()
1309                 .acquireContentProviderClient(REMOTE_AUTHORITY)) {
1310             final ContentResolver resolver = ContentResolver.wrap(remote);
1311             assertNotNull(resolver.getType(REMOTE_TABLE1_URI));
1312             try {
1313                 resolver.getType(TABLE1_URI);
1314                 fail();
1315             } catch (SecurityException | IllegalArgumentException expected) {
1316             }
1317         }
1318     }
1319 
1320     @AppModeFull
testContentResolverCaching()1321     public void testContentResolverCaching() throws Exception {
1322         InstrumentationRegistry.getInstrumentation().getUiAutomation().adoptShellPermissionIdentity(
1323                 android.Manifest.permission.CACHE_CONTENT,
1324                 android.Manifest.permission.INTERACT_ACROSS_USERS_FULL);
1325 
1326         Bundle cached = new Bundle();
1327         cached.putString("key", "value");
1328         mContentResolver.putCache(TABLE1_URI, cached);
1329 
1330         Bundle response = mContentResolver.getCache(TABLE1_URI);
1331         assertEquals("value", response.getString("key"));
1332 
1333         ContentValues values = new ContentValues();
1334         values.put(COLUMN_KEY_NAME, "key10");
1335         values.put(COLUMN_VALUE_NAME, 10);
1336         mContentResolver.update(TABLE1_URI, values, null, null);
1337 
1338         response = mContentResolver.getCache(TABLE1_URI);
1339         assertNull(response);
1340     }
1341 
1342     private class MockContentObserver extends ContentObserver {
1343         private boolean mHadOnChanged = false;
1344 
MockContentObserver()1345         public MockContentObserver() {
1346             super(null);
1347         }
1348 
1349         @Override
deliverSelfNotifications()1350         public boolean deliverSelfNotifications() {
1351             return true;
1352         }
1353 
1354         @Override
onChange(boolean selfChange)1355         public synchronized void onChange(boolean selfChange) {
1356             super.onChange(selfChange);
1357             mHadOnChanged = true;
1358         }
1359 
hadOnChanged()1360         public synchronized boolean hadOnChanged() {
1361             return mHadOnChanged;
1362         }
1363 
reset()1364         public synchronized void reset() {
1365             mHadOnChanged = false;
1366         }
1367     }
1368 }
1369