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 com.android.cts.stub.R; 20 21 22 import android.accounts.Account; 23 import android.content.ContentProviderClient; 24 import android.content.ContentResolver; 25 import android.content.ContentValues; 26 import android.content.Context; 27 import android.content.res.AssetFileDescriptor; 28 import android.cts.util.PollingCheck; 29 import android.database.ContentObserver; 30 import android.database.Cursor; 31 import android.database.sqlite.SQLiteQueryBuilder; 32 import android.net.Uri; 33 import android.os.Bundle; 34 import android.os.CancellationSignal; 35 import android.os.OperationCanceledException; 36 import android.os.ParcelFileDescriptor; 37 import android.os.RemoteException; 38 import android.test.AndroidTestCase; 39 import android.util.Log; 40 41 import java.io.FileInputStream; 42 import java.io.FileNotFoundException; 43 import java.io.IOException; 44 import java.io.InputStream; 45 import java.io.InputStreamReader; 46 import java.io.OutputStream; 47 48 public class ContentResolverTest extends AndroidTestCase { 49 private final static String COLUMN_ID_NAME = "_id"; 50 private final static String COLUMN_KEY_NAME = "key"; 51 private final static String COLUMN_VALUE_NAME = "value"; 52 53 private static final String AUTHORITY = "ctstest"; 54 private static final Uri TABLE1_URI = Uri.parse("content://" + AUTHORITY + "/testtable1/"); 55 private static final Uri TABLE1_CROSS_URI = 56 Uri.parse("content://" + AUTHORITY + "/testtable1/cross"); 57 private static final Uri TABLE2_URI = Uri.parse("content://" + AUTHORITY + "/testtable2/"); 58 private static final Uri SELF_URI = Uri.parse("content://" + AUTHORITY + "/self/"); 59 private static final Uri CRASH_URI = Uri.parse("content://" + AUTHORITY + "/crash/"); 60 61 private static final String REMOTE_AUTHORITY = "remotectstest"; 62 private static final Uri REMOTE_TABLE1_URI = Uri.parse("content://" 63 + REMOTE_AUTHORITY + "/testtable1/"); 64 private static final Uri REMOTE_SELF_URI = Uri.parse("content://" 65 + REMOTE_AUTHORITY + "/self/"); 66 private static final Uri REMOTE_CRASH_URI = Uri.parse("content://" 67 + REMOTE_AUTHORITY + "/crash/"); 68 69 private static final Account ACCOUNT = new Account("cts", "cts"); 70 71 private static final String KEY1 = "key1"; 72 private static final String KEY2 = "key2"; 73 private static final String KEY3 = "key3"; 74 private static final int VALUE1 = 1; 75 private static final int VALUE2 = 2; 76 private static final int VALUE3 = 3; 77 78 private static final String TEST_PACKAGE_NAME = "com.android.cts.stub"; 79 80 private Context mContext; 81 private ContentResolver mContentResolver; 82 private Cursor mCursor; 83 84 @Override 85 protected void setUp() throws Exception { 86 super.setUp(); 87 88 mContext = getContext(); 89 mContentResolver = mContext.getContentResolver(); 90 91 android.provider.Settings.System.putInt(mContentResolver, "__cts_crash_on_launch", 0); 92 93 // add three rows to database when every test case start. 94 ContentValues values = new ContentValues(); 95 96 values.put(COLUMN_KEY_NAME, KEY1); 97 values.put(COLUMN_VALUE_NAME, VALUE1); 98 mContentResolver.insert(TABLE1_URI, values); 99 mContentResolver.insert(REMOTE_TABLE1_URI, values); 100 101 values.put(COLUMN_KEY_NAME, KEY2); 102 values.put(COLUMN_VALUE_NAME, VALUE2); 103 mContentResolver.insert(TABLE1_URI, values); 104 mContentResolver.insert(REMOTE_TABLE1_URI, values); 105 106 values.put(COLUMN_KEY_NAME, KEY3); 107 values.put(COLUMN_VALUE_NAME, VALUE3); 108 mContentResolver.insert(TABLE1_URI, values); 109 mContentResolver.insert(REMOTE_TABLE1_URI, values); 110 } 111 112 @Override 113 protected void tearDown() throws Exception { 114 mContentResolver.delete(TABLE1_URI, null, null); 115 if ( null != mCursor && !mCursor.isClosed() ) { 116 mCursor.close(); 117 } 118 mContentResolver.delete(REMOTE_TABLE1_URI, null, null); 119 if ( null != mCursor && !mCursor.isClosed() ) { 120 mCursor.close(); 121 } 122 super.tearDown(); 123 } 124 125 public void testConstructor() { 126 assertNotNull(mContentResolver); 127 } 128 129 public void testCrashOnLaunch() { 130 // This test is going to make sure that the platform deals correctly 131 // with a content provider process going away while a client is waiting 132 // for it to come up. 133 // First, we need to make sure our provider process is gone. Goodbye! 134 ContentProviderClient client = mContentResolver.acquireContentProviderClient( 135 REMOTE_AUTHORITY); 136 // We are going to do something wrong here... release the client first, 137 // so the act of killing it doesn't kill our own process. 138 client.release(); 139 try { 140 client.delete(REMOTE_SELF_URI, null, null); 141 } catch (RemoteException e) { 142 } 143 // Now make sure the thing is actually gone. 144 boolean gone = true; 145 try { 146 client.getType(REMOTE_TABLE1_URI); 147 gone = false; 148 } catch (RemoteException e) { 149 } 150 if (!gone) { 151 fail("Content provider process is not gone!"); 152 } 153 try { 154 android.provider.Settings.System.putInt(mContentResolver, "__cts_crash_on_launch", 1); 155 String type1 = mContentResolver.getType(REMOTE_TABLE1_URI); 156 assertEquals(android.provider.Settings.System.getInt(mContentResolver, 157 "__cts_crash_on_launch", 0), 0); 158 assertTrue(type1.startsWith(ContentResolver.CURSOR_DIR_BASE_TYPE, 0)); 159 } finally { 160 android.provider.Settings.System.putInt(mContentResolver, "__cts_crash_on_launch", 0); 161 } 162 } 163 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 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 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 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 303 public void testQuery() { 304 mCursor = mContentResolver.query(TABLE1_URI, null, 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 String selection = COLUMN_ID_NAME + "=1"; 322 mCursor = mContentResolver.query(TABLE1_URI, null, selection, null, null); 323 assertNotNull(mCursor); 324 assertEquals(1, mCursor.getCount()); 325 assertEquals(3, mCursor.getColumnCount()); 326 327 mCursor.moveToFirst(); 328 assertEquals(1, mCursor.getInt(mCursor.getColumnIndexOrThrow(COLUMN_ID_NAME))); 329 assertEquals(KEY1, mCursor.getString(mCursor.getColumnIndexOrThrow(COLUMN_KEY_NAME))); 330 assertEquals(VALUE1, mCursor.getInt(mCursor.getColumnIndexOrThrow(COLUMN_VALUE_NAME))); 331 mCursor.close(); 332 333 selection = COLUMN_KEY_NAME + "=\"" + KEY3 + "\""; 334 mCursor = mContentResolver.query(TABLE1_URI, null, selection, null, null); 335 assertNotNull(mCursor); 336 assertEquals(1, mCursor.getCount()); 337 assertEquals(3, mCursor.getColumnCount()); 338 339 mCursor.moveToFirst(); 340 assertEquals(3, mCursor.getInt(mCursor.getColumnIndexOrThrow(COLUMN_ID_NAME))); 341 assertEquals(KEY3, mCursor.getString(mCursor.getColumnIndexOrThrow(COLUMN_KEY_NAME))); 342 assertEquals(VALUE3, mCursor.getInt(mCursor.getColumnIndexOrThrow(COLUMN_VALUE_NAME))); 343 mCursor.close(); 344 345 try { 346 mContentResolver.query(null, null, null, null, null); 347 fail("did not throw NullPointerException when uri is null."); 348 } catch (NullPointerException e) { 349 //expected. 350 } 351 } 352 353 public void testCrashingQuery() { 354 try { 355 android.provider.Settings.System.putInt(mContentResolver, "__cts_crash_on_launch", 1); 356 mCursor = mContentResolver.query(REMOTE_CRASH_URI, null, null, null, null); 357 assertEquals(android.provider.Settings.System.getInt(mContentResolver, 358 "__cts_crash_on_launch", 0), 0); 359 } finally { 360 android.provider.Settings.System.putInt(mContentResolver, "__cts_crash_on_launch", 0); 361 } 362 363 assertNotNull(mCursor); 364 assertEquals(3, mCursor.getCount()); 365 assertEquals(3, mCursor.getColumnCount()); 366 367 mCursor.moveToLast(); 368 assertEquals(3, mCursor.getInt(mCursor.getColumnIndexOrThrow(COLUMN_ID_NAME))); 369 assertEquals(KEY3, mCursor.getString(mCursor.getColumnIndexOrThrow(COLUMN_KEY_NAME))); 370 assertEquals(VALUE3, mCursor.getInt(mCursor.getColumnIndexOrThrow(COLUMN_VALUE_NAME))); 371 372 mCursor.moveToPrevious(); 373 assertEquals(2, mCursor.getInt(mCursor.getColumnIndexOrThrow(COLUMN_ID_NAME))); 374 assertEquals(KEY2, mCursor.getString(mCursor.getColumnIndexOrThrow(COLUMN_KEY_NAME))); 375 assertEquals(VALUE2, mCursor.getInt(mCursor.getColumnIndexOrThrow(COLUMN_VALUE_NAME))); 376 mCursor.close(); 377 } 378 379 public void testCancelableQuery_WhenNotCanceled_ReturnsResultSet() { 380 CancellationSignal cancellationSignal = new CancellationSignal(); 381 382 Cursor cursor = mContentResolver.query(TABLE1_URI, null, null, null, null, 383 cancellationSignal); 384 assertEquals(3, cursor.getCount()); 385 cursor.close(); 386 } 387 388 public void testCancelableQuery_WhenCanceledBeforeQuery_ThrowsImmediately() { 389 CancellationSignal cancellationSignal = new CancellationSignal(); 390 cancellationSignal.cancel(); 391 392 try { 393 mContentResolver.query(TABLE1_URI, null, null, null, null, cancellationSignal); 394 fail("Expected OperationCanceledException"); 395 } catch (OperationCanceledException ex) { 396 // expected 397 } 398 } 399 400 public void testCancelableQuery_WhenCanceledDuringLongRunningQuery_CancelsQueryAndThrows() { 401 // Populate a table with a bunch of integers. 402 mContentResolver.delete(TABLE1_URI, null, null); 403 ContentValues values = new ContentValues(); 404 for (int i = 0; i < 100; i++) { 405 values.put(COLUMN_KEY_NAME, i); 406 values.put(COLUMN_VALUE_NAME, i); 407 mContentResolver.insert(TABLE1_URI, values); 408 } 409 410 for (int i = 0; i < 5; i++) { 411 final CancellationSignal cancellationSignal = new CancellationSignal(); 412 Thread cancellationThread = new Thread() { 413 @Override 414 public void run() { 415 try { 416 Thread.sleep(300); 417 } catch (InterruptedException ex) { 418 } 419 cancellationSignal.cancel(); 420 } 421 }; 422 try { 423 // Build an unsatisfiable 5-way cross-product query over 100 values but 424 // produces no output. This should force SQLite to loop for a long time 425 // as it tests 10^10 combinations. 426 cancellationThread.start(); 427 428 final long startTime = System.nanoTime(); 429 try { 430 mContentResolver.query(TABLE1_CROSS_URI, null, 431 "a.value + b.value + c.value + d.value + e.value > 1000000", 432 null, null, cancellationSignal); 433 fail("Expected OperationCanceledException"); 434 } catch (OperationCanceledException ex) { 435 // expected 436 } 437 438 // We want to confirm that the query really was running and then got 439 // canceled midway. 440 final long waitTime = System.nanoTime() - startTime; 441 if (waitTime > 150 * 1000000L && waitTime < 600 * 1000000L) { 442 return; // success! 443 } 444 } finally { 445 try { 446 cancellationThread.join(); 447 } catch (InterruptedException e) { 448 } 449 } 450 } 451 452 // Occasionally we might miss the timing deadline due to factors in the 453 // environment, but if after several trials we still couldn't demonstrate 454 // that the query was canceled, then the test must be broken. 455 fail("Could not prove that the query actually canceled midway during execution."); 456 } 457 458 public void testOpenInputStream() throws IOException { 459 final Uri uri = Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE + 460 "://" + TEST_PACKAGE_NAME + "/" + R.drawable.pass); 461 462 InputStream is = mContentResolver.openInputStream(uri); 463 assertNotNull(is); 464 is.close(); 465 466 final Uri invalidUri = Uri.parse("abc"); 467 try { 468 mContentResolver.openInputStream(invalidUri); 469 fail("did not throw FileNotFoundException when uri is invalid."); 470 } catch (FileNotFoundException e) { 471 //expected. 472 } 473 } 474 475 public void testOpenOutputStream() throws IOException { 476 Uri uri = Uri.parse(ContentResolver.SCHEME_FILE + "://" + 477 getContext().getCacheDir().getAbsolutePath() + 478 "/temp.jpg"); 479 OutputStream os = mContentResolver.openOutputStream(uri); 480 assertNotNull(os); 481 os.close(); 482 483 os = mContentResolver.openOutputStream(uri, "wa"); 484 assertNotNull(os); 485 os.close(); 486 487 uri = Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE + 488 "://" + TEST_PACKAGE_NAME + "/" + R.raw.testimage); 489 try { 490 mContentResolver.openOutputStream(uri); 491 fail("did not throw FileNotFoundException when scheme is not accepted."); 492 } catch (FileNotFoundException e) { 493 //expected. 494 } 495 496 try { 497 mContentResolver.openOutputStream(uri, "w"); 498 fail("did not throw FileNotFoundException when scheme is not accepted."); 499 } catch (FileNotFoundException e) { 500 //expected. 501 } 502 503 Uri invalidUri = Uri.parse("abc"); 504 try { 505 mContentResolver.openOutputStream(invalidUri); 506 fail("did not throw FileNotFoundException when uri is invalid."); 507 } catch (FileNotFoundException e) { 508 //expected. 509 } 510 511 try { 512 mContentResolver.openOutputStream(invalidUri, "w"); 513 fail("did not throw FileNotFoundException when uri is invalid."); 514 } catch (FileNotFoundException e) { 515 //expected. 516 } 517 } 518 519 public void testOpenAssetFileDescriptor() throws IOException { 520 Uri uri = Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE + 521 "://" + TEST_PACKAGE_NAME + "/" + R.raw.testimage); 522 523 AssetFileDescriptor afd = mContentResolver.openAssetFileDescriptor(uri, "r"); 524 assertNotNull(afd); 525 afd.close(); 526 527 try { 528 mContentResolver.openAssetFileDescriptor(uri, "d"); 529 fail("did not throw FileNotFoundException when mode is unknown."); 530 } catch (FileNotFoundException e) { 531 //expected. 532 } 533 534 Uri invalidUri = Uri.parse("abc"); 535 try { 536 mContentResolver.openAssetFileDescriptor(invalidUri, "r"); 537 fail("did not throw FileNotFoundException when uri is invalid."); 538 } catch (FileNotFoundException e) { 539 //expected. 540 } 541 } 542 543 private String consumeAssetFileDescriptor(AssetFileDescriptor afd) 544 throws IOException { 545 FileInputStream stream = null; 546 try { 547 stream = afd.createInputStream(); 548 InputStreamReader reader = new InputStreamReader(stream, "UTF-8"); 549 550 // Got it... copy the stream into a local string and return it. 551 StringBuilder builder = new StringBuilder(128); 552 char[] buffer = new char[8192]; 553 int len; 554 while ((len=reader.read(buffer)) > 0) { 555 builder.append(buffer, 0, len); 556 } 557 return builder.toString(); 558 559 } finally { 560 if (stream != null) { 561 try { 562 stream.close(); 563 } catch (IOException e) { 564 } 565 } 566 } 567 568 } 569 570 public void testCrashingOpenAssetFileDescriptor() throws IOException { 571 AssetFileDescriptor afd = null; 572 try { 573 android.provider.Settings.System.putInt(mContentResolver, "__cts_crash_on_launch", 1); 574 afd = mContentResolver.openAssetFileDescriptor(REMOTE_CRASH_URI, "rw"); 575 assertEquals(android.provider.Settings.System.getInt(mContentResolver, 576 "__cts_crash_on_launch", 0), 0); 577 assertNotNull(afd); 578 String str = consumeAssetFileDescriptor(afd); 579 afd = null; 580 assertEquals(str, "This is the openAssetFile test data!"); 581 } finally { 582 android.provider.Settings.System.putInt(mContentResolver, "__cts_crash_on_launch", 0); 583 if (afd != null) { 584 afd.close(); 585 } 586 } 587 588 // Make sure a content provider crash at this point won't hurt us. 589 ContentProviderClient uClient = mContentResolver.acquireUnstableContentProviderClient( 590 REMOTE_AUTHORITY); 591 // Kill it. Note that a bug at this point where it causes our own 592 // process to be killed will result in the entire test failing. 593 try { 594 Log.i("ContentResolverTest", 595 "Killing remote client -- if test process goes away, that is why!"); 596 uClient.delete(REMOTE_SELF_URI, null, null); 597 } catch (RemoteException e) { 598 } 599 uClient.release(); 600 } 601 602 public void testCrashingOpenTypedAssetFileDescriptor() throws IOException { 603 AssetFileDescriptor afd = null; 604 try { 605 android.provider.Settings.System.putInt(mContentResolver, "__cts_crash_on_launch", 1); 606 afd = mContentResolver.openTypedAssetFileDescriptor( 607 REMOTE_CRASH_URI, "text/plain", null); 608 assertEquals(android.provider.Settings.System.getInt(mContentResolver, 609 "__cts_crash_on_launch", 0), 0); 610 assertNotNull(afd); 611 String str = consumeAssetFileDescriptor(afd); 612 afd = null; 613 assertEquals(str, "This is the openTypedAssetFile test data!"); 614 } finally { 615 android.provider.Settings.System.putInt(mContentResolver, "__cts_crash_on_launch", 0); 616 if (afd != null) { 617 afd.close(); 618 } 619 } 620 621 // Make sure a content provider crash at this point won't hurt us. 622 ContentProviderClient uClient = mContentResolver.acquireUnstableContentProviderClient( 623 REMOTE_AUTHORITY); 624 // Kill it. Note that a bug at this point where it causes our own 625 // process to be killed will result in the entire test failing. 626 try { 627 Log.i("ContentResolverTest", 628 "Killing remote client -- if test process goes away, that is why!"); 629 uClient.delete(REMOTE_SELF_URI, null, null); 630 } catch (RemoteException e) { 631 } 632 uClient.release(); 633 } 634 635 public void testOpenFileDescriptor() throws IOException { 636 Uri uri = Uri.parse(ContentResolver.SCHEME_FILE + "://" + 637 getContext().getCacheDir().getAbsolutePath() + 638 "/temp.jpg"); 639 ParcelFileDescriptor pfd = mContentResolver.openFileDescriptor(uri, "w"); 640 assertNotNull(pfd); 641 pfd.close(); 642 643 try { 644 mContentResolver.openFileDescriptor(uri, "d"); 645 fail("did not throw IllegalArgumentException when mode is unknown."); 646 } catch (IllegalArgumentException e) { 647 //expected. 648 } 649 650 Uri invalidUri = Uri.parse("abc"); 651 try { 652 mContentResolver.openFileDescriptor(invalidUri, "w"); 653 fail("did not throw FileNotFoundException when uri is invalid."); 654 } catch (FileNotFoundException e) { 655 //expected. 656 } 657 658 uri = Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE + 659 "://" + TEST_PACKAGE_NAME + "/" + R.raw.testimage); 660 try { 661 mContentResolver.openFileDescriptor(uri, "w"); 662 fail("did not throw FileNotFoundException when scheme is not accepted."); 663 } catch (FileNotFoundException e) { 664 //expected. 665 } 666 } 667 668 public void testInsert() { 669 String key4 = "key4"; 670 String key5 = "key5"; 671 int value4 = 4; 672 int value5 = 5; 673 String key4Selection = COLUMN_KEY_NAME + "=\"" + key4 + "\""; 674 675 mCursor = mContentResolver.query(TABLE1_URI, null, key4Selection, null, null); 676 assertEquals(0, mCursor.getCount()); 677 mCursor.close(); 678 679 ContentValues values = new ContentValues(); 680 values.put(COLUMN_KEY_NAME, key4); 681 values.put(COLUMN_VALUE_NAME, value4); 682 Uri uri = mContentResolver.insert(TABLE1_URI, values); 683 assertNotNull(uri); 684 685 mCursor = mContentResolver.query(TABLE1_URI, null, key4Selection, null, null); 686 assertNotNull(mCursor); 687 assertEquals(1, mCursor.getCount()); 688 689 mCursor.moveToFirst(); 690 assertEquals(4, mCursor.getInt(mCursor.getColumnIndexOrThrow(COLUMN_ID_NAME))); 691 assertEquals(key4, mCursor.getString(mCursor.getColumnIndexOrThrow(COLUMN_KEY_NAME))); 692 assertEquals(value4, mCursor.getInt(mCursor.getColumnIndexOrThrow(COLUMN_VALUE_NAME))); 693 mCursor.close(); 694 695 values.put(COLUMN_KEY_NAME, key5); 696 values.put(COLUMN_VALUE_NAME, value5); 697 uri = mContentResolver.insert(TABLE1_URI, values); 698 assertNotNull(uri); 699 700 // check returned uri 701 mCursor = mContentResolver.query(uri, null, null, null, null); 702 assertNotNull(mCursor); 703 assertEquals(1, mCursor.getCount()); 704 705 mCursor.moveToLast(); 706 assertEquals(5, mCursor.getInt(mCursor.getColumnIndexOrThrow(COLUMN_ID_NAME))); 707 assertEquals(key5, mCursor.getString(mCursor.getColumnIndexOrThrow(COLUMN_KEY_NAME))); 708 assertEquals(value5, mCursor.getInt(mCursor.getColumnIndexOrThrow(COLUMN_VALUE_NAME))); 709 mCursor.close(); 710 711 try { 712 mContentResolver.insert(null, values); 713 fail("did not throw NullPointerException when uri is null."); 714 } catch (NullPointerException e) { 715 //expected. 716 } 717 } 718 719 public void testBulkInsert() { 720 String key4 = "key4"; 721 String key5 = "key5"; 722 int value4 = 4; 723 int value5 = 5; 724 725 mCursor = mContentResolver.query(TABLE1_URI, null, null, null, null); 726 assertNotNull(mCursor); 727 assertEquals(3, mCursor.getCount()); 728 mCursor.close(); 729 730 ContentValues[] cvs = new ContentValues[2]; 731 cvs[0] = new ContentValues(); 732 cvs[0].put(COLUMN_KEY_NAME, key4); 733 cvs[0].put(COLUMN_VALUE_NAME, value4); 734 735 cvs[1] = new ContentValues(); 736 cvs[1].put(COLUMN_KEY_NAME, key5); 737 cvs[1].put(COLUMN_VALUE_NAME, value5); 738 739 assertEquals(2, mContentResolver.bulkInsert(TABLE1_URI, cvs)); 740 mCursor = mContentResolver.query(TABLE1_URI, null, null, null, null); 741 assertNotNull(mCursor); 742 assertEquals(5, mCursor.getCount()); 743 744 mCursor.moveToLast(); 745 assertEquals(5, mCursor.getInt(mCursor.getColumnIndexOrThrow(COLUMN_ID_NAME))); 746 assertEquals(key5, mCursor.getString(mCursor.getColumnIndexOrThrow(COLUMN_KEY_NAME))); 747 assertEquals(value5, mCursor.getInt(mCursor.getColumnIndexOrThrow(COLUMN_VALUE_NAME))); 748 749 mCursor.moveToPrevious(); 750 assertEquals(4, mCursor.getInt(mCursor.getColumnIndexOrThrow(COLUMN_ID_NAME))); 751 assertEquals(key4, mCursor.getString(mCursor.getColumnIndexOrThrow(COLUMN_KEY_NAME))); 752 assertEquals(value4, mCursor.getInt(mCursor.getColumnIndexOrThrow(COLUMN_VALUE_NAME))); 753 mCursor.close(); 754 755 try { 756 mContentResolver.bulkInsert(null, cvs); 757 fail("did not throw NullPointerException when uri is null."); 758 } catch (NullPointerException e) { 759 //expected. 760 } 761 } 762 763 public void testDelete() { 764 mCursor = mContentResolver.query(TABLE1_URI, null, null, null, null); 765 assertNotNull(mCursor); 766 assertEquals(3, mCursor.getCount()); 767 mCursor.close(); 768 769 assertEquals(3, mContentResolver.delete(TABLE1_URI, null, null)); 770 mCursor = mContentResolver.query(TABLE1_URI, null, null, null, null); 771 assertNotNull(mCursor); 772 assertEquals(0, mCursor.getCount()); 773 mCursor.close(); 774 775 // add three rows to database. 776 ContentValues values = new ContentValues(); 777 values.put(COLUMN_KEY_NAME, KEY1); 778 values.put(COLUMN_VALUE_NAME, VALUE1); 779 mContentResolver.insert(TABLE1_URI, values); 780 781 values.put(COLUMN_KEY_NAME, KEY2); 782 values.put(COLUMN_VALUE_NAME, VALUE2); 783 mContentResolver.insert(TABLE1_URI, values); 784 785 values.put(COLUMN_KEY_NAME, KEY3); 786 values.put(COLUMN_VALUE_NAME, VALUE3); 787 mContentResolver.insert(TABLE1_URI, values); 788 789 // test delete row using selection 790 String selection = COLUMN_ID_NAME + "=2"; 791 assertEquals(1, mContentResolver.delete(TABLE1_URI, selection, null)); 792 793 mCursor = mContentResolver.query(TABLE1_URI, null, null, null, null); 794 assertNotNull(mCursor); 795 assertEquals(2, mCursor.getCount()); 796 797 mCursor.moveToFirst(); 798 assertEquals(1, mCursor.getInt(mCursor.getColumnIndexOrThrow(COLUMN_ID_NAME))); 799 assertEquals(KEY1, mCursor.getString(mCursor.getColumnIndexOrThrow(COLUMN_KEY_NAME))); 800 assertEquals(VALUE1, mCursor.getInt(mCursor.getColumnIndexOrThrow(COLUMN_VALUE_NAME))); 801 802 mCursor.moveToNext(); 803 assertEquals(3, mCursor.getInt(mCursor.getColumnIndexOrThrow(COLUMN_ID_NAME))); 804 assertEquals(KEY3, mCursor.getString(mCursor.getColumnIndexOrThrow(COLUMN_KEY_NAME))); 805 assertEquals(VALUE3, mCursor.getInt(mCursor.getColumnIndexOrThrow(COLUMN_VALUE_NAME))); 806 mCursor.close(); 807 808 selection = COLUMN_VALUE_NAME + "=3"; 809 assertEquals(1, mContentResolver.delete(TABLE1_URI, selection, null)); 810 811 mCursor = mContentResolver.query(TABLE1_URI, null, null, null, null); 812 assertNotNull(mCursor); 813 assertEquals(1, mCursor.getCount()); 814 815 mCursor.moveToFirst(); 816 assertEquals(1, mCursor.getInt(mCursor.getColumnIndexOrThrow(COLUMN_ID_NAME))); 817 assertEquals(KEY1, mCursor.getString(mCursor.getColumnIndexOrThrow(COLUMN_KEY_NAME))); 818 assertEquals(VALUE1, mCursor.getInt(mCursor.getColumnIndexOrThrow(COLUMN_VALUE_NAME))); 819 mCursor.close(); 820 821 selection = COLUMN_KEY_NAME + "=\"" + KEY1 + "\""; 822 assertEquals(1, mContentResolver.delete(TABLE1_URI, selection, null)); 823 824 mCursor = mContentResolver.query(TABLE1_URI, null, null, null, null); 825 assertNotNull(mCursor); 826 assertEquals(0, mCursor.getCount()); 827 mCursor.close(); 828 829 try { 830 mContentResolver.delete(null, null, null); 831 fail("did not throw NullPointerException when uri is null."); 832 } catch (NullPointerException e) { 833 //expected. 834 } 835 } 836 837 public void testUpdate() { 838 ContentValues values = new ContentValues(); 839 String key10 = "key10"; 840 String key20 = "key20"; 841 int value10 = 10; 842 int value20 = 20; 843 844 values.put(COLUMN_KEY_NAME, key10); 845 values.put(COLUMN_VALUE_NAME, value10); 846 847 // test update all the rows. 848 assertEquals(3, mContentResolver.update(TABLE1_URI, values, null, null)); 849 mCursor = mContentResolver.query(TABLE1_URI, null, null, null, null); 850 assertNotNull(mCursor); 851 assertEquals(3, mCursor.getCount()); 852 853 mCursor.moveToFirst(); 854 assertEquals(1, mCursor.getInt(mCursor.getColumnIndexOrThrow(COLUMN_ID_NAME))); 855 assertEquals(key10, mCursor.getString(mCursor.getColumnIndexOrThrow(COLUMN_KEY_NAME))); 856 assertEquals(value10, mCursor.getInt(mCursor.getColumnIndexOrThrow(COLUMN_VALUE_NAME))); 857 858 mCursor.moveToNext(); 859 assertEquals(2, mCursor.getInt(mCursor.getColumnIndexOrThrow(COLUMN_ID_NAME))); 860 assertEquals(key10, mCursor.getString(mCursor.getColumnIndexOrThrow(COLUMN_KEY_NAME))); 861 assertEquals(value10, mCursor.getInt(mCursor.getColumnIndexOrThrow(COLUMN_VALUE_NAME))); 862 863 mCursor.moveToLast(); 864 assertEquals(3, mCursor.getInt(mCursor.getColumnIndexOrThrow(COLUMN_ID_NAME))); 865 assertEquals(key10, mCursor.getString(mCursor.getColumnIndexOrThrow(COLUMN_KEY_NAME))); 866 assertEquals(value10, mCursor.getInt(mCursor.getColumnIndexOrThrow(COLUMN_VALUE_NAME))); 867 mCursor.close(); 868 869 // test update one row using selection. 870 String selection = COLUMN_ID_NAME + "=1"; 871 values.put(COLUMN_KEY_NAME, key20); 872 values.put(COLUMN_VALUE_NAME, value20); 873 874 assertEquals(1, mContentResolver.update(TABLE1_URI, values, selection, null)); 875 mCursor = mContentResolver.query(TABLE1_URI, null, null, null, null); 876 assertNotNull(mCursor); 877 assertEquals(3, mCursor.getCount()); 878 879 mCursor.moveToFirst(); 880 assertEquals(1, mCursor.getInt(mCursor.getColumnIndexOrThrow(COLUMN_ID_NAME))); 881 assertEquals(key20, mCursor.getString(mCursor.getColumnIndexOrThrow(COLUMN_KEY_NAME))); 882 assertEquals(value20, mCursor.getInt(mCursor.getColumnIndexOrThrow(COLUMN_VALUE_NAME))); 883 884 mCursor.moveToNext(); 885 assertEquals(2, mCursor.getInt(mCursor.getColumnIndexOrThrow(COLUMN_ID_NAME))); 886 assertEquals(key10, mCursor.getString(mCursor.getColumnIndexOrThrow(COLUMN_KEY_NAME))); 887 assertEquals(value10, mCursor.getInt(mCursor.getColumnIndexOrThrow(COLUMN_VALUE_NAME))); 888 889 mCursor.moveToLast(); 890 assertEquals(3, mCursor.getInt(mCursor.getColumnIndexOrThrow(COLUMN_ID_NAME))); 891 assertEquals(key10, mCursor.getString(mCursor.getColumnIndexOrThrow(COLUMN_KEY_NAME))); 892 assertEquals(value10, mCursor.getInt(mCursor.getColumnIndexOrThrow(COLUMN_VALUE_NAME))); 893 mCursor.close(); 894 895 try { 896 mContentResolver.update(null, values, null, null); 897 fail("did not throw NullPointerException when uri is null."); 898 } catch (NullPointerException e) { 899 //expected. 900 } 901 902 // javadoc says it will throw NullPointerException when values are null, 903 // but actually, it throws IllegalArgumentException here. 904 try { 905 mContentResolver.update(TABLE1_URI, null, null, null); 906 fail("did not throw IllegalArgumentException when values are null."); 907 } catch (IllegalArgumentException e) { 908 //expected. 909 } 910 } 911 912 public void testRegisterContentObserver() { 913 final MockContentObserver mco = new MockContentObserver(); 914 915 mContentResolver.registerContentObserver(TABLE1_URI, true, mco); 916 assertFalse(mco.hadOnChanged()); 917 918 ContentValues values = new ContentValues(); 919 values.put(COLUMN_KEY_NAME, "key10"); 920 values.put(COLUMN_VALUE_NAME, 10); 921 mContentResolver.update(TABLE1_URI, values, null, null); 922 new PollingCheck() { 923 @Override 924 protected boolean check() { 925 return mco.hadOnChanged(); 926 } 927 }.run(); 928 929 mco.reset(); 930 mContentResolver.unregisterContentObserver(mco); 931 assertFalse(mco.hadOnChanged()); 932 mContentResolver.update(TABLE1_URI, values, null, null); 933 934 assertFalse(mco.hadOnChanged()); 935 936 try { 937 mContentResolver.registerContentObserver(null, false, mco); 938 fail("did not throw NullPointerException or IllegalArgumentException when uri is null."); 939 } catch (NullPointerException e) { 940 //expected. 941 } catch (IllegalArgumentException e) { 942 // also expected 943 } 944 945 try { 946 mContentResolver.registerContentObserver(TABLE1_URI, false, null); 947 fail("did not throw NullPointerException when register null content observer."); 948 } catch (NullPointerException e) { 949 //expected. 950 } 951 952 try { 953 mContentResolver.unregisterContentObserver(null); 954 fail("did not throw NullPointerException when unregister null content observer."); 955 } catch (NullPointerException e) { 956 //expected. 957 } 958 } 959 960 public void testNotifyChange1() { 961 final MockContentObserver mco = new MockContentObserver(); 962 963 mContentResolver.registerContentObserver(TABLE1_URI, true, mco); 964 assertFalse(mco.hadOnChanged()); 965 966 mContentResolver.notifyChange(TABLE1_URI, mco); 967 new PollingCheck() { 968 @Override 969 protected boolean check() { 970 return mco.hadOnChanged(); 971 } 972 }.run(); 973 974 mContentResolver.unregisterContentObserver(mco); 975 } 976 977 public void testNotifyChange2() { 978 final MockContentObserver mco = new MockContentObserver(); 979 980 mContentResolver.registerContentObserver(TABLE1_URI, true, mco); 981 assertFalse(mco.hadOnChanged()); 982 983 mContentResolver.notifyChange(TABLE1_URI, mco, false); 984 new PollingCheck() { 985 @Override 986 protected boolean check() { 987 return mco.hadOnChanged(); 988 } 989 }.run(); 990 991 mContentResolver.unregisterContentObserver(mco); 992 } 993 994 public void testStartCancelSync() { 995 Bundle extras = new Bundle(); 996 997 extras.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true); 998 999 ContentResolver.requestSync(ACCOUNT, AUTHORITY, extras); 1000 //FIXME: how to get the result to assert. 1001 1002 ContentResolver.cancelSync(ACCOUNT, AUTHORITY); 1003 //FIXME: how to assert. 1004 } 1005 1006 public void testStartSyncFailure() { 1007 try { 1008 ContentResolver.requestSync(null, null, null); 1009 fail("did not throw IllegalArgumentException when extras is null."); 1010 } catch (IllegalArgumentException e) { 1011 //expected. 1012 } 1013 } 1014 1015 public void testValidateSyncExtrasBundle() { 1016 Bundle extras = new Bundle(); 1017 extras.putInt("Integer", 20); 1018 extras.putLong("Long", 10l); 1019 extras.putBoolean("Boolean", true); 1020 extras.putFloat("Float", 5.5f); 1021 extras.putDouble("Double", 2.5); 1022 extras.putString("String", "cts"); 1023 extras.putCharSequence("CharSequence", null); 1024 1025 ContentResolver.validateSyncExtrasBundle(extras); 1026 1027 extras.putChar("Char", 'a'); // type Char is invalid 1028 try { 1029 ContentResolver.validateSyncExtrasBundle(extras); 1030 fail("did not throw IllegalArgumentException when extras is invalide."); 1031 } catch (IllegalArgumentException e) { 1032 //expected. 1033 } 1034 } 1035 1036 private class MockContentObserver extends ContentObserver { 1037 private boolean mHadOnChanged = false; 1038 1039 public MockContentObserver() { 1040 super(null); 1041 } 1042 1043 @Override 1044 public boolean deliverSelfNotifications() { 1045 return true; 1046 } 1047 1048 @Override 1049 public synchronized void onChange(boolean selfChange) { 1050 super.onChange(selfChange); 1051 mHadOnChanged = true; 1052 } 1053 1054 public synchronized boolean hadOnChanged() { 1055 return mHadOnChanged; 1056 } 1057 1058 public synchronized void reset() { 1059 mHadOnChanged = false; 1060 } 1061 } 1062 } 1063