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