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