1 /* 2 * Copyright (C) 2011 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 com.android.providers.contacts; 18 19 import android.content.ContentUris; 20 import android.content.ContentValues; 21 import android.database.Cursor; 22 import android.net.Uri; 23 import android.os.BatteryStats.Uid.Proc; 24 import android.os.ParcelFileDescriptor; 25 import android.os.Process; 26 import android.provider.CallLog; 27 import android.provider.CallLog.Calls; 28 import android.provider.VoicemailContract; 29 import android.provider.VoicemailContract.Status; 30 import android.provider.VoicemailContract.Voicemails; 31 import android.test.MoreAsserts; 32 import android.test.suitebuilder.annotation.SmallTest; 33 34 import com.android.common.io.MoreCloseables; 35 36 import java.io.FileNotFoundException; 37 import java.io.IOException; 38 import java.io.InputStream; 39 import java.io.OutputStream; 40 import java.util.Arrays; 41 import java.util.List; 42 43 /** 44 * Unit tests for {@link VoicemailContentProvider}. 45 * 46 * Run the test like this: 47 * <code> 48 * runtest -c com.android.providers.contacts.VoicemailProviderTest contactsprov 49 * </code> 50 */ 51 // TODO: Test that calltype and voicemail_uri are auto populated by the provider. 52 @SmallTest 53 public class VoicemailProviderTest extends BaseVoicemailProviderTest { 54 /** Fields specific to call_log provider that should not be exposed by voicemail provider. */ 55 private static final String[] CALLLOG_PROVIDER_SPECIFIC_COLUMNS = { 56 Calls.CACHED_NAME, 57 Calls.CACHED_NUMBER_LABEL, 58 Calls.CACHED_NUMBER_TYPE, 59 Calls.TYPE, 60 Calls.VOICEMAIL_URI, 61 Calls.COUNTRY_ISO 62 }; 63 /** Total number of columns exposed by voicemail provider. */ 64 private static final int NUM_VOICEMAIL_FIELDS = 24; 65 66 @Override setUp()67 protected void setUp() throws Exception { 68 super.setUp(); 69 setUpForOwnPermission(); 70 addProvider(CallLogProviderTestable.class, CallLog.AUTHORITY); 71 } 72 73 /** Returns the appropriate /voicemail URI. */ voicemailUri()74 private Uri voicemailUri() { 75 return mUseSourceUri ? 76 Voicemails.buildSourceUri(mActor.packageName) : Voicemails.CONTENT_URI; 77 } 78 79 /** Returns the appropriate /status URI. */ statusUri()80 private Uri statusUri() { 81 return mUseSourceUri ? 82 Status.buildSourceUri(mActor.packageName) : Status.CONTENT_URI; 83 } 84 testInsert()85 public void testInsert() throws Exception { 86 setTimeForTest(1000L); 87 Uri uri = mResolver.insert(voicemailUri(), getTestVoicemailValues()); 88 // We create on purpose a new set of ContentValues here, because the code above modifies 89 // the copy it gets. 90 assertStoredValues(uri, getTestVoicemailValues()); 91 assertSelection(uri, getTestVoicemailValues(), Voicemails._ID, ContentUris.parseId(uri)); 92 assertEquals(1, countFilesInTestDirectory()); 93 94 assertLastModified(uri, 1000); 95 } 96 testInsertReadMessageIsNotNew()97 public void testInsertReadMessageIsNotNew() throws Exception { 98 ContentValues values = getTestReadVoicemailValues(); 99 Uri uri = mResolver.insert(voicemailUri(), values); 100 String[] projection = {Voicemails.NUMBER, Voicemails.DATE, Voicemails.DURATION, 101 Voicemails.TRANSCRIPTION, Voicemails.IS_READ, Voicemails.HAS_CONTENT, 102 Voicemails.SOURCE_DATA, Voicemails.STATE, 103 Voicemails.BACKED_UP, Voicemails.RESTORED, Voicemails.ARCHIVED, 104 Voicemails.IS_OMTP_VOICEMAIL 105 }; 106 Cursor c = mResolver.query(uri, projection, Calls.NEW + "=0", null, 107 null); 108 try { 109 assertEquals("Record count", 1, c.getCount()); 110 c.moveToFirst(); 111 assertEquals(1, countFilesInTestDirectory()); 112 assertCursorValues(c, values); 113 } catch (Error e) { 114 TestUtils.dumpCursor(c); 115 throw e; 116 } finally { 117 c.close(); 118 } 119 } 120 121 // Test to ensure that media content can be written and read back. testFileContent()122 public void testFileContent() throws Exception { 123 Uri uri = insertVoicemail(); 124 OutputStream out = mResolver.openOutputStream(uri); 125 byte[] outBuffer = {0x1, 0x2, 0x3, 0x4}; 126 out.write(outBuffer); 127 out.flush(); 128 out.close(); 129 InputStream in = mResolver.openInputStream(uri); 130 byte[] inBuffer = new byte[4]; 131 int numBytesRead = in.read(inBuffer); 132 assertEquals(numBytesRead, outBuffer.length); 133 MoreAsserts.assertEquals(outBuffer, inBuffer); 134 // No more data should be left. 135 assertEquals(-1, in.read(inBuffer)); 136 in.close(); 137 } 138 testUpdate()139 public void testUpdate() { 140 setTimeForTest(1000L); 141 Uri uri = insertVoicemail(); 142 ContentValues values = new ContentValues(); 143 values.put(Voicemails.NUMBER, "1-800-263-7643"); 144 values.put(Voicemails.DATE, 2000); 145 values.put(Voicemails.DURATION, 40); 146 values.put(Voicemails.TRANSCRIPTION, "Testing 123"); 147 values.put(Voicemails.STATE, 2); 148 values.put(Voicemails.HAS_CONTENT, 1); 149 values.put(Voicemails.SOURCE_DATA, "foo"); 150 values.put(Voicemails.PHONE_ACCOUNT_COMPONENT_NAME, "dummy_name"); 151 values.put(Voicemails.PHONE_ACCOUNT_ID, "dummy_account"); 152 values.put(Voicemails.BACKED_UP, 1); 153 values.put(Voicemails.RESTORED, 1); 154 values.put(Voicemails.ARCHIVED, 1); 155 values.put(Voicemails.IS_OMTP_VOICEMAIL, 1); 156 int count = mResolver.update(uri, values, null, null); 157 assertEquals(1, count); 158 assertStoredValues(uri, values); 159 assertLastModified(uri, 1000); 160 } 161 testUpdateOwnPackageVoicemail_NotDirty()162 public void testUpdateOwnPackageVoicemail_NotDirty() { 163 final Uri uri = mResolver.insert(voicemailUri(), getTestVoicemailValues()); 164 mResolver.update(uri, new ContentValues(), null, null); 165 166 // Updating a package's own voicemail should not make the voicemail dirty. 167 ContentValues values = getTestVoicemailValues(); 168 values.put(Voicemails.DIRTY, "0"); 169 assertStoredValues(uri, values); 170 } 171 testUpdateOwnPackageVoicemail_RemovesDirtyStatus()172 public void testUpdateOwnPackageVoicemail_RemovesDirtyStatus() { 173 ContentValues values = getTestVoicemailValues(); 174 values.put(Voicemails.DIRTY, "1"); 175 final Uri uri = mResolver.insert(voicemailUri(), getTestVoicemailValues()); 176 177 mResolver.update(uri, new ContentValues(), null, null); 178 // At this point, the voicemail should be set back to not dirty. 179 ContentValues newValues = getTestVoicemailValues(); 180 newValues.put(Voicemails.DIRTY, "0"); 181 assertStoredValues(uri, newValues); 182 } 183 testDeleteOwnPackageVoicemail_DeletesRow()184 public void testDeleteOwnPackageVoicemail_DeletesRow() { 185 setUpForFullPermission(); 186 final Uri ownVoicemail = insertVoicemail(); 187 assertEquals(1, getCount(voicemailUri(), null, null)); 188 189 mResolver.delete(ownVoicemail, null, null); 190 191 assertEquals(0, getCount(ownVoicemail, null, null)); 192 } 193 testDeleteOtherPackageVoicemail_SetsDirtyStatus()194 public void testDeleteOtherPackageVoicemail_SetsDirtyStatus() { 195 setUpForFullPermission(); 196 setTimeForTest(1000L); 197 final Uri anotherVoicemail = insertVoicemailForSourcePackage("another-package"); 198 assertEquals(1, getCount(voicemailUri(), null, null)); 199 200 // Clear the mapping for our own UID so that this doesn't look like an internal transaction. 201 mPackageManager.removePackage(Process.myUid()); 202 mResolver.delete(anotherVoicemail, null, null); 203 204 ContentValues values = getTestVoicemailValues(); 205 values.put(Voicemails.DIRTY, "1"); 206 values.put(Voicemails.DELETED, "1"); 207 208 assertEquals(1, getCount(anotherVoicemail, null, null)); 209 assertStoredValues(anotherVoicemail, values); 210 assertLastModified(anotherVoicemail, 1000); 211 } 212 testDelete()213 public void testDelete() { 214 Uri uri = insertVoicemail(); 215 int count = mResolver.delete(voicemailUri(), Voicemails._ID + "=" 216 + ContentUris.parseId(uri), null); 217 assertEquals(1, count); 218 assertEquals(0, getCount(uri, null, null)); 219 } 220 testUpdateAfterDelete_lastModifiedNotChanged()221 public void testUpdateAfterDelete_lastModifiedNotChanged() { 222 setUpForFullPermission(); 223 setTimeForTest(1000L); 224 final Uri anotherVoicemail = insertVoicemailForSourcePackage("another-package"); 225 assertEquals(1, getCount(voicemailUri(), null, null)); 226 227 // Clear the mapping for our own UID so that this doesn't look like an internal transaction. 228 mPackageManager.removePackage(Process.myUid()); 229 mResolver.delete(anotherVoicemail, null, null); 230 assertLastModified(anotherVoicemail, 1000); 231 232 mPackageManager.addPackage(Process.myUid(), mActor.packageName); 233 setTimeForTest(2000L); 234 mResolver.update(anotherVoicemail, new ContentValues(), null, null); 235 assertLastModified(anotherVoicemail, 1000); 236 237 setTimeForTest(3000L); 238 ContentValues values = new ContentValues(); 239 values.put(Voicemails.DELETED, "0"); 240 mResolver.update(anotherVoicemail, values, null, null); 241 assertLastModified(anotherVoicemail, 3000); 242 } 243 testGetType_ItemUri()244 public void testGetType_ItemUri() throws Exception { 245 // Random item uri. 246 assertEquals(Voicemails.ITEM_TYPE, 247 mResolver.getType(ContentUris.withAppendedId(Voicemails.CONTENT_URI, 100))); 248 // Item uri of an inserted voicemail. 249 ContentValues values = getTestVoicemailValues(); 250 values.put(Voicemails.MIME_TYPE, "foo/bar"); 251 Uri uri = mResolver.insert(voicemailUri(), values); 252 assertEquals(Voicemails.ITEM_TYPE, mResolver.getType(uri)); 253 } 254 testGetType_DirUri()255 public void testGetType_DirUri() throws Exception { 256 assertEquals(Voicemails.DIR_TYPE, mResolver.getType(Voicemails.CONTENT_URI)); 257 assertEquals(Voicemails.DIR_TYPE, mResolver.getType(Voicemails.buildSourceUri("foo"))); 258 } 259 260 // Test to ensure that without full permission it is not possible to use the base uri (i.e. with 261 // no package URI specified). testMustUsePackageUriWithoutFullPermission()262 public void testMustUsePackageUriWithoutFullPermission() { 263 setUpForOwnPermission(); 264 EvenMoreAsserts.assertThrows(SecurityException.class, new Runnable() { 265 @Override 266 public void run() { 267 mResolver.insert(Voicemails.CONTENT_URI, getTestVoicemailValues()); 268 } 269 }); 270 271 EvenMoreAsserts.assertThrows(SecurityException.class, new Runnable() { 272 @Override 273 public void run() { 274 mResolver.update(Voicemails.CONTENT_URI, getTestVoicemailValues(), null, null); 275 } 276 }); 277 278 EvenMoreAsserts.assertThrows(SecurityException.class, new Runnable() { 279 @Override 280 public void run() { 281 mResolver.query(Voicemails.CONTENT_URI, null, null, null, null); 282 } 283 }); 284 285 EvenMoreAsserts.assertThrows(SecurityException.class, new Runnable() { 286 @Override 287 public void run() { 288 mResolver.delete(Voicemails.CONTENT_URI, null, null); 289 } 290 }); 291 } 292 testPermissions_InsertAndQuery()293 public void testPermissions_InsertAndQuery() { 294 setUpForFullPermission(); 295 // Insert two records - one each with own and another package. 296 insertVoicemail(); 297 insertVoicemailForSourcePackage("another-package"); 298 assertEquals(2, getCount(voicemailUri(), null, null)); 299 300 // Now give away full permission and check that only 1 message is accessible. 301 setUpForOwnPermission(); 302 assertEquals(1, getCount(voicemailUri(), null, null)); 303 304 // Once again try to insert message for another package. This time 305 // it should fail. 306 EvenMoreAsserts.assertThrows(SecurityException.class, new Runnable() { 307 @Override 308 public void run() { 309 insertVoicemailForSourcePackage("another-package"); 310 } 311 }); 312 313 setUpForNoPermission(); 314 mUseSourceUri = false; 315 // With the READ_ALL_VOICEMAIL permission, we should now be able to read all voicemails 316 mActor.addPermissions(READ_VOICEMAIL_PERMISSION); 317 assertEquals(2, getCount(voicemailUri(), null, null)); 318 319 // An insert for another package should still fail 320 EvenMoreAsserts.assertThrows(SecurityException.class, new Runnable() { 321 @Override 322 public void run() { 323 insertVoicemailForSourcePackage("another-package"); 324 } 325 }); 326 } 327 testPermissions_UpdateAndDelete()328 public void testPermissions_UpdateAndDelete() { 329 setUpForFullPermission(); 330 // Insert two records - one each with own and another package. 331 final Uri ownVoicemail = insertVoicemail(); 332 final Uri anotherVoicemail = insertVoicemailForSourcePackage("another-package"); 333 assertEquals(2, getCount(voicemailUri(), null, null)); 334 335 // Now give away full permission and check that we can update and delete only 336 // the own voicemail. 337 setUpForOwnPermission(); 338 mResolver.update(withSourcePackageParam(ownVoicemail), 339 getTestVoicemailValues(), null, null); 340 mResolver.delete(withSourcePackageParam(ownVoicemail), null, null); 341 342 // However, attempting to update or delete another-package's voicemail should fail. 343 EvenMoreAsserts.assertThrows(SecurityException.class, new Runnable() { 344 @Override 345 public void run() { 346 mResolver.update(anotherVoicemail, null, null, null); 347 } 348 }); 349 EvenMoreAsserts.assertThrows(SecurityException.class, new Runnable() { 350 @Override 351 public void run() { 352 mResolver.delete(anotherVoicemail, null, null); 353 } 354 }); 355 356 // If we have the manage voicemail permission, we should be able to both update voicemails 357 // from all packages. 358 setUpForNoPermission(); 359 mActor.addPermissions(WRITE_VOICEMAIL_PERMISSION); 360 mResolver.update(anotherVoicemail, getTestVoicemailValues(), null, null); 361 362 // Now add the read voicemail permission temporarily to verify that the update actually 363 // worked 364 mActor.addPermissions(READ_VOICEMAIL_PERMISSION); 365 assertStoredValues(anotherVoicemail, getTestVoicemailValues()); 366 mActor.removePermissions(READ_VOICEMAIL_PERMISSION); 367 368 mResolver.delete(anotherVoicemail, null, null); 369 370 // Now add the read voicemail permission temporarily to verify that the voicemail is 371 // deleted. 372 mActor.addPermissions(READ_VOICEMAIL_PERMISSION); 373 374 assertEquals(0, getCount(anotherVoicemail, null, null)); 375 } 376 withSourcePackageParam(Uri uri)377 private Uri withSourcePackageParam(Uri uri) { 378 return uri.buildUpon() 379 .appendQueryParameter(VoicemailContract.PARAM_KEY_SOURCE_PACKAGE, mActor.packageName) 380 .build(); 381 } 382 testUriPermissions()383 public void testUriPermissions() { 384 setUpForFullPermission(); 385 final Uri uri1 = insertVoicemail(); 386 final Uri uri2 = insertVoicemail(); 387 // Give away all permissions before querying. Access to both uris should be denied. 388 setUpForNoPermission(); 389 checkHasNoAccessToUri(uri1); 390 checkHasNoAccessToUri(uri2); 391 392 // Just grant permission to uri1. uri1 should pass but uri2 should still fail. 393 mActor.addUriPermissions(uri1); 394 checkHasReadOnlyAccessToUri(uri1); 395 checkHasNoAccessToUri(uri2); 396 397 // Cleanup. 398 mActor.removeUriPermissions(uri1); 399 } 400 401 /* 402 * Checks that the READ_ALL_VOICEMAIL permission provides read access to a uri. 403 */ testUriPermissions_ReadAccess()404 public void testUriPermissions_ReadAccess() { 405 setUpForFullPermission(); 406 final Uri uri1 = insertVoicemail(); 407 // Give away all permissions before querying. Access should be denied. 408 setUpForNoPermission(); 409 mUseSourceUri = false; 410 checkHasNoAccessToUri(uri1); 411 412 mActor.addPermissions(READ_VOICEMAIL_PERMISSION); 413 checkHasReadAccessToUri(uri1); 414 } 415 416 /* 417 * Checks that the MANAGE_VOICEMAIL permission provides write access to a uri. 418 */ testUriPermissions_WriteAccess()419 public void testUriPermissions_WriteAccess() { 420 setUpForFullPermission(); 421 final Uri uri1 = insertVoicemail(); 422 // Give away all permissions before querying. Access should be denied. 423 setUpForNoPermission(); 424 checkHasNoAccessToUri(uri1); 425 426 mActor.addPermissions(WRITE_VOICEMAIL_PERMISSION); 427 checkHasUpdateAndDeleteAccessToUri(uri1); 428 } 429 checkHasNoAccessToUri(final Uri uri)430 private void checkHasNoAccessToUri(final Uri uri) { 431 checkHasNoReadAccessToUri(uri); 432 checkHasNoWriteAccessToUri(uri); 433 } 434 checkHasReadOnlyAccessToUri(final Uri uri)435 private void checkHasReadOnlyAccessToUri(final Uri uri) { 436 checkHasReadAccessToUri(uri); 437 checkHasNoWriteAccessToUri(uri); 438 } 439 checkHasReadAccessToUri(final Uri uri)440 private void checkHasReadAccessToUri(final Uri uri) { 441 Cursor cursor = null; 442 try { 443 cursor = mResolver.query(uri, null, null ,null, null); 444 assertEquals(1, cursor.getCount()); 445 try { 446 ParcelFileDescriptor fd = mResolver.openFileDescriptor(uri, "r"); 447 assertNotNull(fd); 448 fd.close(); 449 } catch (FileNotFoundException e) { 450 fail(e.getMessage()); 451 } catch (IOException e) { 452 fail(e.getMessage()); 453 } 454 } finally { 455 MoreCloseables.closeQuietly(cursor); 456 } 457 } 458 checkHasNoReadAccessToUri(final Uri uri)459 private void checkHasNoReadAccessToUri(final Uri uri) { 460 EvenMoreAsserts.assertThrows(SecurityException.class, new Runnable() { 461 @Override 462 public void run() { 463 mResolver.query(uri, null, null, null, null); 464 } 465 }); 466 EvenMoreAsserts.assertThrows(SecurityException.class, new Runnable() { 467 @Override 468 public void run() { 469 try { 470 mResolver.openFileDescriptor(uri, "r"); 471 } catch (FileNotFoundException e) { 472 fail(e.getMessage()); 473 } 474 } 475 }); 476 } 477 checkHasUpdateAndDeleteAccessToUri(final Uri uri)478 private void checkHasUpdateAndDeleteAccessToUri(final Uri uri) { 479 mResolver.update(uri, getTestVoicemailValues(), null, null); 480 mResolver.delete(uri, null, null); 481 } 482 checkHasNoWriteAccessToUri(final Uri uri)483 private void checkHasNoWriteAccessToUri(final Uri uri) { 484 EvenMoreAsserts.assertThrows(SecurityException.class, new Runnable() { 485 @Override 486 public void run() { 487 mResolver.update(uri, getTestVoicemailValues(), null, null); 488 } 489 }); 490 EvenMoreAsserts.assertThrows(SecurityException.class, new Runnable() { 491 @Override 492 public void run() { 493 mResolver.delete(uri, null, null); 494 } 495 }); 496 EvenMoreAsserts.assertThrows(SecurityException.class, new Runnable() { 497 @Override 498 public void run() { 499 try { 500 mResolver.openFileDescriptor(uri, "w"); 501 } catch (FileNotFoundException e) { 502 fail(e.getMessage()); 503 } 504 } 505 }); 506 EvenMoreAsserts.assertThrows(SecurityException.class, new Runnable() { 507 @Override 508 public void run() { 509 try { 510 mResolver.openFileDescriptor(uri, "rw"); 511 } catch (FileNotFoundException e) { 512 fail(e.getMessage()); 513 } 514 } 515 }); 516 } 517 518 // Test to ensure that all operations fail when no voicemail permission is granted. testNoPermissions()519 public void testNoPermissions() { 520 setUpForNoPermission(); 521 EvenMoreAsserts.assertThrows(SecurityException.class, new Runnable() { 522 @Override 523 public void run() { 524 mResolver.insert(voicemailUri(), getTestVoicemailValues()); 525 } 526 }); 527 EvenMoreAsserts.assertThrows(SecurityException.class, new Runnable() { 528 @Override 529 public void run() { 530 mResolver.update(voicemailUri(), getTestVoicemailValues(), null, null); 531 } 532 }); 533 EvenMoreAsserts.assertThrows(SecurityException.class, new Runnable() { 534 @Override 535 public void run() { 536 mResolver.query(voicemailUri(), null, null, null, null); 537 } 538 }); 539 EvenMoreAsserts.assertThrows(SecurityException.class, new Runnable() { 540 @Override 541 public void run() { 542 mResolver.delete(voicemailUri(), null, null); 543 } 544 }); 545 } 546 547 // Test to check that none of the call_log provider specific fields are 548 // insertable through voicemail provider. testCannotAccessCallLogSpecificFields_Insert()549 public void testCannotAccessCallLogSpecificFields_Insert() { 550 for (String callLogColumn : CALLLOG_PROVIDER_SPECIFIC_COLUMNS) { 551 final ContentValues values = getTestVoicemailValues(); 552 values.put(callLogColumn, "foo"); 553 EvenMoreAsserts.assertThrows("Column: " + callLogColumn, 554 IllegalArgumentException.class, new Runnable() { 555 @Override 556 public void run() { 557 mResolver.insert(voicemailUri(), values); 558 } 559 }); 560 } 561 } 562 563 // Test to check that none of the call_log provider specific fields are 564 // exposed through voicemail provider query. testCannotAccessCallLogSpecificFields_Query()565 public void testCannotAccessCallLogSpecificFields_Query() { 566 // Query. 567 Cursor cursor = mResolver.query(voicemailUri(), null, null, null, null); 568 List<String> columnNames = Arrays.asList(cursor.getColumnNames()); 569 assertEquals(NUM_VOICEMAIL_FIELDS, columnNames.size()); 570 // None of the call_log provider specific columns should be present. 571 for (String callLogColumn : CALLLOG_PROVIDER_SPECIFIC_COLUMNS) { 572 assertFalse("Unexpected column: '" + callLogColumn + "' returned.", 573 columnNames.contains(callLogColumn)); 574 } 575 } 576 577 // Test to check that none of the call_log provider specific fields are 578 // updatable through voicemail provider. testCannotAccessCallLogSpecificFields_Update()579 public void testCannotAccessCallLogSpecificFields_Update() { 580 for (String callLogColumn : CALLLOG_PROVIDER_SPECIFIC_COLUMNS) { 581 final Uri insertedUri = insertVoicemail(); 582 final ContentValues values = getTestVoicemailValues(); 583 values.put(callLogColumn, "foo"); 584 EvenMoreAsserts.assertThrows("Column: " + callLogColumn, 585 IllegalArgumentException.class, new Runnable() { 586 @Override 587 public void run() { 588 mResolver.update(insertedUri, values, null, null); 589 } 590 }); 591 } 592 } 593 594 // Tests for voicemail status table. 595 testStatusInsert()596 public void testStatusInsert() throws Exception { 597 ContentValues values = getTestStatusValues(); 598 Uri uri = mResolver.insert(statusUri(), values); 599 assertStoredValues(uri, values); 600 assertSelection(uri, values, Status._ID, ContentUris.parseId(uri)); 601 } 602 testStatusUpdate()603 public void testStatusUpdate() throws Exception { 604 Uri uri = insertTestStatusEntry(); 605 ContentValues values = getTestStatusValues(); 606 values.put(Status.DATA_CHANNEL_STATE, Status.DATA_CHANNEL_STATE_NO_CONNECTION); 607 values.put(Status.NOTIFICATION_CHANNEL_STATE, 608 Status.NOTIFICATION_CHANNEL_STATE_MESSAGE_WAITING); 609 values.put(Status.SOURCE_TYPE, 610 "vvm_type_test2"); 611 int count = mResolver.update(uri, values, null, null); 612 assertEquals(1, count); 613 assertStoredValues(uri, values); 614 } 615 testStatusUpsert()616 public void testStatusUpsert() throws Exception { 617 ContentValues values = getTestStatusValues(); 618 mResolver.insert(statusUri(), values); 619 ContentValues values2 = new ContentValues(); 620 values2.put(Status.CONFIGURATION_STATE, Status.CONFIGURATION_STATE_NOT_CONFIGURED); 621 values.put(Status.CONFIGURATION_STATE, Status.CONFIGURATION_STATE_NOT_CONFIGURED); 622 Uri uri = mResolver.insert(statusUri(), values2); 623 assertStoredValues(uri, values); 624 assertSelection(uri, values, Status._ID, ContentUris.parseId(uri)); 625 } 626 testStatusDelete()627 public void testStatusDelete() { 628 Uri uri = insertTestStatusEntry(); 629 int count = mResolver.delete(statusUri(), Status._ID + "=" 630 + ContentUris.parseId(uri), null); 631 assertEquals(1, count); 632 assertEquals(0, getCount(uri, null, null)); 633 } 634 testStatusQuotaInsert()635 public void testStatusQuotaInsert() { 636 ContentValues values = new ContentValues(); 637 values.put(Status.SOURCE_PACKAGE, mActor.packageName); 638 values.put(Status.QUOTA_OCCUPIED, 2); 639 values.put(Status.QUOTA_TOTAL, 13); 640 Uri uri = mResolver.insert(statusUri(), values); 641 assertStoredValues(uri, values); 642 assertSelection(uri, values, Status._ID, ContentUris.parseId(uri)); 643 } 644 testStatusQuotaUpdate()645 public void testStatusQuotaUpdate() { 646 Uri uri = insertTestStatusEntry(); 647 ContentValues values = new ContentValues(); 648 values.put(Status.SOURCE_PACKAGE, mActor.packageName); 649 values.put(Status.QUOTA_OCCUPIED, 2); 650 values.put(Status.QUOTA_TOTAL, 13); 651 int count = mResolver.update(uri, values, null, null); 652 assertEquals(1, count); 653 654 ContentValues refValues = getTestStatusValues(); 655 refValues.put(Status.QUOTA_OCCUPIED, 2); 656 refValues.put(Status.QUOTA_TOTAL, 13); 657 assertStoredValues(uri, refValues); 658 } 659 testStatusQuotaUpsert()660 public void testStatusQuotaUpsert() { 661 Uri uri = insertTestStatusEntry(); 662 ContentValues values = new ContentValues(); 663 values.put(Status.SOURCE_PACKAGE, mActor.packageName); 664 values.put(Status.QUOTA_OCCUPIED, 2); 665 int count = mResolver.update(uri, values, null, null); 666 667 ContentValues values2 = new ContentValues(); 668 values2.put(Status.QUOTA_TOTAL, 13); 669 mResolver.insert(uri, values2); 670 671 ContentValues refValues = getTestStatusValues(); 672 refValues.put(Status.QUOTA_OCCUPIED, 2); 673 refValues.put(Status.QUOTA_TOTAL, 13); 674 assertStoredValues(uri, refValues); 675 } 676 testStatusGetType()677 public void testStatusGetType() throws Exception { 678 // Item URI. 679 Uri uri = insertTestStatusEntry(); 680 assertEquals(Status.ITEM_TYPE, mResolver.getType(uri)); 681 682 // base URIs. 683 assertEquals(Status.DIR_TYPE, mResolver.getType(Status.CONTENT_URI)); 684 assertEquals(Status.DIR_TYPE, mResolver.getType(Status.buildSourceUri("foo"))); 685 } 686 687 // Basic permission checks for the status table. testStatusPermissions()688 public void testStatusPermissions() throws Exception { 689 final ContentValues values = getTestStatusValues(); 690 // Inserting for another package should fail with any of the URIs. 691 values.put(Status.SOURCE_PACKAGE, "another.package"); 692 EvenMoreAsserts.assertThrows(SecurityException.class, new Runnable() { 693 @Override 694 public void run() { 695 mResolver.insert(Status.CONTENT_URI, values); 696 } 697 }); 698 EvenMoreAsserts.assertThrows(SecurityException.class, new Runnable() { 699 @Override 700 public void run() { 701 mResolver.insert(Status.buildSourceUri(mActor.packageName), values); 702 } 703 }); 704 705 // But insertion with own package should succeed with the right uri. 706 values.put(Status.SOURCE_PACKAGE, mActor.packageName); 707 final Uri uri = mResolver.insert(Status.buildSourceUri(mActor.packageName), values); 708 assertNotNull(uri); 709 710 // Updating source_package should not work as well. 711 values.put(Status.SOURCE_PACKAGE, "another.package"); 712 EvenMoreAsserts.assertThrows(SecurityException.class, new Runnable() { 713 @Override 714 public void run() { 715 mResolver.update(uri, values, null, null); 716 } 717 }); 718 } 719 720 // File operation is not supported by /status URI. testStatusFileOperation()721 public void testStatusFileOperation() throws Exception { 722 final Uri uri = insertTestStatusEntry(); 723 EvenMoreAsserts.assertThrows(UnsupportedOperationException.class, new Runnable() { 724 @Override 725 public void run() { 726 try { 727 mResolver.openOutputStream(uri); 728 } catch (FileNotFoundException e) { 729 fail("Unexpected exception " + e); 730 } 731 } 732 }); 733 734 EvenMoreAsserts.assertThrows(UnsupportedOperationException.class, new Runnable() { 735 @Override 736 public void run() { 737 try { 738 mResolver.openInputStream(uri); 739 } catch (FileNotFoundException e) { 740 fail("Unexpected exception " + e); 741 } 742 } 743 }); 744 } 745 746 /** 747 * Inserts a voicemail record with no source package set. The content provider 748 * will detect source package. 749 */ insertVoicemail()750 private Uri insertVoicemail() { 751 return mResolver.insert(voicemailUri(), getTestVoicemailValues()); 752 } 753 754 /** Inserts a voicemail record for the specified source package. */ insertVoicemailForSourcePackage(String sourcePackage)755 private Uri insertVoicemailForSourcePackage(String sourcePackage) { 756 ContentValues values = getTestVoicemailValues(); 757 values.put(Voicemails.SOURCE_PACKAGE, sourcePackage); 758 return mResolver.insert(voicemailUri(), values); 759 } 760 getTestVoicemailValues()761 private ContentValues getTestVoicemailValues() { 762 ContentValues values = new ContentValues(); 763 values.put(Voicemails.NUMBER, "1-800-4664-411"); 764 values.put(Voicemails.DATE, 1000); 765 values.put(Voicemails.DURATION, 30); 766 values.put(Voicemails.TRANSCRIPTION, "Testing 123"); 767 values.put(Voicemails.IS_READ, 0); 768 values.put(Voicemails.HAS_CONTENT, 0); 769 values.put(Voicemails.SOURCE_DATA, "1234"); 770 values.put(Voicemails.STATE, Voicemails.STATE_INBOX); 771 values.put(Voicemails.BACKED_UP, 0); 772 values.put(Voicemails.RESTORED, 0); 773 values.put(Voicemails.ARCHIVED, 0); 774 values.put(Voicemails.IS_OMTP_VOICEMAIL, 0); 775 return values; 776 } 777 getTestReadVoicemailValues()778 private ContentValues getTestReadVoicemailValues() { 779 ContentValues values = getTestVoicemailValues(); 780 values.put(Voicemails.IS_READ, 1); 781 return values; 782 } 783 insertTestStatusEntry()784 private Uri insertTestStatusEntry() { 785 return mResolver.insert(statusUri(), getTestStatusValues()); 786 } 787 getTestStatusValues()788 private ContentValues getTestStatusValues() { 789 ContentValues values = new ContentValues(); 790 values.put(Status.SOURCE_PACKAGE, mActor.packageName); 791 values.put(Status.VOICEMAIL_ACCESS_URI, "tel:901"); 792 values.put(Status.SETTINGS_URI, "com.example.voicemail.source.SettingsActivity"); 793 values.put(Status.CONFIGURATION_STATE, Status.CONFIGURATION_STATE_OK); 794 values.put(Status.DATA_CHANNEL_STATE, Status.DATA_CHANNEL_STATE_OK); 795 values.put(Status.NOTIFICATION_CHANNEL_STATE, Status.NOTIFICATION_CHANNEL_STATE_OK); 796 values.put(Status.SOURCE_TYPE, "vvm_type_test"); 797 return values; 798 } 799 800 } 801