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 android.provider.cts.contacts; 18 19 import android.app.Instrumentation; 20 import android.content.ContentProviderClient; 21 import android.content.ContentResolver; 22 import android.content.ContentValues; 23 import android.content.Context; 24 import android.content.pm.PackageManager; 25 import android.database.Cursor; 26 import android.net.Uri; 27 import android.os.ParcelFileDescriptor; 28 import android.os.RemoteException; 29 import android.provider.VoicemailContract; 30 import android.provider.VoicemailContract.Status; 31 import android.provider.VoicemailContract.Voicemails; 32 import android.test.InstrumentationTestCase; 33 import android.text.TextUtils; 34 import android.util.Log; 35 36 import java.io.BufferedReader; 37 import java.io.FileInputStream; 38 import java.io.InputStream; 39 import java.io.InputStreamReader; 40 import java.nio.charset.StandardCharsets; 41 42 /** 43 * CTS tests for voicemail provider accessed through {@link VoicemailContract}. 44 */ 45 public class VoicemailContractTest extends InstrumentationTestCase { 46 47 private static final String TAG = "VoicemailContractTest"; 48 49 private ContentResolver mContentResolver; 50 private ContentProviderClient mVoicemailProvider; 51 private ContentProviderClient mStatusProvider; 52 private Uri mVoicemailContentUri; 53 private Uri mStatusContentUri; 54 private String mSourcePackageName; 55 56 private String mPreviousDefaultDialer; 57 58 private static final String COMMAND_SET_DEFAULT_DIALER = "telecom set-default-dialer "; 59 private static final String COMMAND_GET_DEFAULT_DIALER = "telecom get-default-dialer"; 60 61 private static final String PACKAGE = "android.provider.cts"; 62 63 private final String FOREIGN_SOURCE = "android.provider.cts.contacts.foreign_source"; 64 65 @Override setUp()66 protected void setUp() throws Exception { 67 super.setUp(); 68 mSourcePackageName = getInstrumentation().getTargetContext().getPackageName(); 69 mVoicemailContentUri = Voicemails.buildSourceUri(mSourcePackageName); 70 mStatusContentUri = Status.buildSourceUri(mSourcePackageName); 71 mContentResolver = getInstrumentation().getTargetContext().getContentResolver(); 72 mVoicemailProvider = mContentResolver.acquireContentProviderClient(mVoicemailContentUri); 73 mStatusProvider = mContentResolver.acquireContentProviderClient(mStatusContentUri); 74 } 75 76 @Override tearDown()77 protected void tearDown() throws Exception { 78 // Clean up, just in case we failed to delete the entry when a test failed. 79 // The cotentUris are specific to this package, so this will delete only the 80 // entries inserted by this package. 81 mStatusProvider.delete(mStatusContentUri, null, null); 82 mVoicemailProvider.delete(mVoicemailContentUri, null, null); 83 if (!TextUtils.isEmpty(mPreviousDefaultDialer)) { 84 setDefaultDialer(getInstrumentation(), mPreviousDefaultDialer); 85 } 86 super.tearDown(); 87 } 88 testVoicemailsTable()89 public void testVoicemailsTable() throws Exception { 90 final String[] VOICEMAILS_PROJECTION = new String[] { 91 Voicemails._ID, 92 Voicemails.NUMBER, 93 Voicemails.DATE, 94 Voicemails.DURATION, 95 Voicemails.NEW, 96 Voicemails.IS_READ, 97 Voicemails.SOURCE_PACKAGE, 98 Voicemails.SOURCE_DATA, 99 Voicemails.HAS_CONTENT, 100 Voicemails.MIME_TYPE, 101 Voicemails.TRANSCRIPTION, 102 Voicemails.PHONE_ACCOUNT_COMPONENT_NAME, 103 Voicemails.PHONE_ACCOUNT_ID, 104 Voicemails.DIRTY, 105 Voicemails.DELETED, 106 Voicemails.LAST_MODIFIED, 107 Voicemails.BACKED_UP, 108 Voicemails.RESTORED, 109 Voicemails.ARCHIVED, 110 Voicemails.IS_OMTP_VOICEMAIL}; 111 final int ID_INDEX = 0; 112 final int NUMBER_INDEX = 1; 113 final int DATE_INDEX = 2; 114 final int DURATION_INDEX = 3; 115 final int NEW_INDEX = 4; 116 final int IS_READ_INDEX = 5; 117 final int SOURCE_PACKAGE_INDEX = 6; 118 final int SOURCE_DATA_INDEX = 7; 119 final int HAS_CONTENT_INDEX = 8; 120 final int MIME_TYPE_INDEX = 9; 121 final int TRANSCRIPTION_INDEX = 10; 122 final int PHONE_ACCOUNT_COMPONENT_NAME_INDEX = 11; 123 final int PHONE_ACCOUNT_ID_INDEX = 12; 124 final int DIRTY_INDEX = 13; 125 final int DELETED_INDEX = 14; 126 final int LAST_MODIFIED_INDEX = 15; 127 final int BACKED_UP_INDEX = 16; 128 final int RESTORED_INDEX = 17; 129 final int ARCHIVED_INDEX = 18; 130 final int IS_OMTP_VOICEMAIL_INDEX = 19; 131 132 String insertCallsNumber = "0123456789"; 133 long insertCallsDuration = 120; 134 String insertSourceData = "internal_id"; 135 String insertMimeType = "audio/mp3"; 136 long insertDate = 1324478862000L; 137 138 String updateCallsNumber = "9876543210"; 139 long updateCallsDuration = 310; 140 String updateSourceData = "another_id"; 141 long updateDate = 1324565262000L; 142 143 // Test: insert 144 ContentValues value = new ContentValues(); 145 value.put(Voicemails.NUMBER, insertCallsNumber); 146 value.put(Voicemails.DATE, insertDate); 147 value.put(Voicemails.DURATION, insertCallsDuration); 148 value.put(Voicemails.NEW, 0); 149 // Source package is expected to be inserted by the provider, if not set. 150 value.put(Voicemails.SOURCE_DATA, insertSourceData); 151 value.put(Voicemails.MIME_TYPE, insertMimeType); 152 value.put(Voicemails.IS_READ, false); 153 value.put(Voicemails.HAS_CONTENT, true); 154 value.put(Voicemails.TRANSCRIPTION, "foo"); 155 value.put(Voicemails.PHONE_ACCOUNT_COMPONENT_NAME, "com.foo"); 156 value.put(Voicemails.PHONE_ACCOUNT_ID, "bar"); 157 value.put(Voicemails.DIRTY, 0); 158 value.put(Voicemails.DELETED, 0); 159 value.put(Voicemails.BACKED_UP, 0); 160 value.put(Voicemails.RESTORED, 0); 161 value.put(Voicemails.ARCHIVED, 0); 162 value.put(Voicemails.IS_OMTP_VOICEMAIL, 0); 163 164 Uri uri = mVoicemailProvider.insert(mVoicemailContentUri, value); 165 Cursor cursor = mVoicemailProvider.query( 166 mVoicemailContentUri, VOICEMAILS_PROJECTION, 167 Voicemails.NUMBER + " = ?", 168 new String[] {insertCallsNumber}, null, null); 169 assertTrue(cursor.moveToNext()); 170 assertEquals(insertCallsNumber, cursor.getString(NUMBER_INDEX)); 171 assertEquals(insertDate, cursor.getLong(DATE_INDEX)); 172 assertEquals(insertCallsDuration, cursor.getLong(DURATION_INDEX)); 173 assertEquals(mSourcePackageName, cursor.getString(SOURCE_PACKAGE_INDEX)); 174 assertEquals(insertSourceData, cursor.getString(SOURCE_DATA_INDEX)); 175 assertEquals(insertMimeType, cursor.getString(MIME_TYPE_INDEX)); 176 assertEquals(0, cursor.getInt(NEW_INDEX)); 177 assertEquals(0, cursor.getInt(IS_READ_INDEX)); 178 assertEquals(1, cursor.getInt(HAS_CONTENT_INDEX)); 179 assertEquals("foo", cursor.getString(TRANSCRIPTION_INDEX)); 180 assertEquals("com.foo", cursor.getString(PHONE_ACCOUNT_COMPONENT_NAME_INDEX)); 181 assertEquals("bar", cursor.getString(PHONE_ACCOUNT_ID_INDEX)); 182 assertEquals(0, cursor.getInt(DIRTY_INDEX)); 183 assertEquals(0, cursor.getInt(DELETED_INDEX)); 184 assertEquals(0, cursor.getInt(BACKED_UP_INDEX)); 185 assertEquals(0, cursor.getInt(RESTORED_INDEX)); 186 assertEquals(0, cursor.getInt(ARCHIVED_INDEX)); 187 assertEquals(0, cursor.getInt(IS_OMTP_VOICEMAIL_INDEX)); 188 int id = cursor.getInt(ID_INDEX); 189 assertEquals(id, Integer.parseInt(uri.getLastPathSegment())); 190 cursor.close(); 191 192 // Test: update 193 value.clear(); 194 value.put(Voicemails.NUMBER, updateCallsNumber); 195 value.put(Voicemails.DATE, updateDate); 196 value.put(Voicemails.DURATION, updateCallsDuration); 197 value.put(Voicemails.SOURCE_DATA, updateSourceData); 198 value.put(Voicemails.NEW, 1); 199 value.put(Voicemails.DIRTY, 1); 200 value.put(Voicemails.DELETED, 1); 201 value.put(Voicemails.BACKED_UP, 1); 202 value.put(Voicemails.RESTORED, 1); 203 value.put(Voicemails.ARCHIVED, 1); 204 value.put(Voicemails.IS_OMTP_VOICEMAIL, 1); 205 206 mVoicemailProvider.update(uri, value, null, null); 207 cursor = mVoicemailProvider.query(mVoicemailContentUri, VOICEMAILS_PROJECTION, 208 Voicemails._ID + " = " + id, null, null, null); 209 assertEquals(1, cursor.getCount()); 210 assertTrue(cursor.moveToNext()); 211 assertEquals(mSourcePackageName, cursor.getString(SOURCE_PACKAGE_INDEX)); 212 assertEquals(updateCallsNumber, cursor.getString(NUMBER_INDEX)); 213 assertEquals(updateDate, cursor.getLong(DATE_INDEX)); 214 assertEquals(updateCallsDuration, cursor.getLong(DURATION_INDEX)); 215 assertEquals(updateSourceData, cursor.getString(SOURCE_DATA_INDEX)); 216 assertEquals(1, cursor.getInt(NEW_INDEX)); 217 assertEquals(1, cursor.getInt(DIRTY_INDEX)); 218 assertEquals(1, cursor.getInt(DELETED_INDEX)); 219 assertEquals(1, cursor.getInt(BACKED_UP_INDEX)); 220 assertEquals(1, cursor.getInt(RESTORED_INDEX)); 221 assertEquals(1, cursor.getInt(ARCHIVED_INDEX)); 222 assertEquals(1, cursor.getInt(IS_OMTP_VOICEMAIL_INDEX)); 223 cursor.close(); 224 225 // Test: delete 226 mVoicemailProvider.delete(mVoicemailContentUri, Voicemails._ID + " = " + id, null); 227 cursor = mVoicemailProvider.query(mVoicemailContentUri, VOICEMAILS_PROJECTION, 228 Voicemails._ID + " = " + id, null, null, null); 229 assertEquals(0, cursor.getCount()); 230 cursor.close(); 231 } 232 testForeignUpdate_dirty()233 public void testForeignUpdate_dirty() throws Exception { 234 if (!hasTelephony(getInstrumentation().getContext())) { 235 Log.d(TAG, "skipping test that requires telephony feature"); 236 return; 237 } 238 // only the default dialer has WRITE_VOICEMAIL permission, which can modify voicemails of 239 // a foreign source package. 240 setTestAsDefaultDialer(); 241 ContentValues values = new ContentValues(); 242 values.put(Voicemails.SOURCE_PACKAGE, FOREIGN_SOURCE); 243 244 Uri uri = mVoicemailProvider.insert(Voicemails.buildSourceUri(FOREIGN_SOURCE), values); 245 246 ContentValues updateValues = new ContentValues(); 247 updateValues.put(Voicemails.IS_READ, "1"); 248 mVoicemailProvider.update(uri, updateValues, null, null); 249 250 try (Cursor cursor = mVoicemailProvider 251 .query(uri, new String[] {Voicemails.DIRTY}, null, null, null)) { 252 cursor.moveToFirst(); 253 assertEquals(1, cursor.getInt(0)); 254 } 255 } 256 testForeignUpdate_retainDirty_notDirty()257 public void testForeignUpdate_retainDirty_notDirty() throws Exception { 258 if (!hasTelephony(getInstrumentation().getContext())) { 259 Log.d(TAG, "skipping test that requires telephony feature"); 260 return; 261 } 262 // only the default dialer has WRITE_VOICEMAIL permission, which can modify voicemails of 263 // a foreign source package. 264 setTestAsDefaultDialer(); 265 ContentValues values = new ContentValues(); 266 values.put(Voicemails.SOURCE_PACKAGE, FOREIGN_SOURCE); 267 268 Uri uri = mVoicemailProvider.insert(Voicemails.buildSourceUri(FOREIGN_SOURCE), values); 269 270 ContentValues newValues = new ContentValues(); 271 newValues.put(Voicemails.TRANSCRIPTION, "foo"); 272 newValues.put(Voicemails.DIRTY, Voicemails.DIRTY_RETAIN); 273 274 mVoicemailProvider.update(uri, newValues, null, null); 275 276 try (Cursor cursor = mVoicemailProvider 277 .query(uri, new String[] {Voicemails.DIRTY}, null, null, null)) { 278 cursor.moveToFirst(); 279 assertEquals(0, cursor.getInt(0)); 280 } 281 } 282 testForeignUpdate_explicitNotDirty()283 public void testForeignUpdate_explicitNotDirty() throws Exception { 284 if (!hasTelephony(getInstrumentation().getContext())) { 285 Log.d(TAG, "skipping test that requires telephony feature"); 286 return; 287 } 288 setTestAsDefaultDialer(); 289 ContentValues values = new ContentValues(); 290 values.put(Voicemails.SOURCE_PACKAGE, FOREIGN_SOURCE); 291 292 Uri uri = mVoicemailProvider.insert(Voicemails.buildSourceUri(FOREIGN_SOURCE), values); 293 294 ContentValues updateValues = new ContentValues(); 295 updateValues.put(Voicemails.DIRTY, 0); 296 mVoicemailProvider.update(uri, updateValues, null, null); 297 298 try (Cursor cursor = mVoicemailProvider 299 .query(uri, new String[] {Voicemails.DIRTY}, null, null, null)) { 300 cursor.moveToFirst(); 301 assertEquals(0, cursor.getInt(0)); 302 } 303 } 304 testForeignUpdate_null_dirty()305 public void testForeignUpdate_null_dirty() throws Exception { 306 if (!hasTelephony(getInstrumentation().getContext())) { 307 Log.d(TAG, "skipping test that requires telephony feature"); 308 return; 309 } 310 setTestAsDefaultDialer(); 311 ContentValues values = new ContentValues(); 312 values.put(Voicemails.SOURCE_PACKAGE, FOREIGN_SOURCE); 313 314 Uri uri = mVoicemailProvider.insert(Voicemails.buildSourceUri(FOREIGN_SOURCE), values); 315 316 ContentValues updateValues = new ContentValues(); 317 updateValues.put(Voicemails.DIRTY, (Integer) null); 318 mVoicemailProvider.update(uri, updateValues, null, null); 319 320 try (Cursor cursor = mVoicemailProvider 321 .query(uri, new String[] {Voicemails.DIRTY}, null, null, null)) { 322 cursor.moveToFirst(); 323 assertEquals(1, cursor.getInt(0)); 324 } 325 } 326 testForeignUpdate_NotNormalized_normalized()327 public void testForeignUpdate_NotNormalized_normalized() throws Exception { 328 if (!hasTelephony(getInstrumentation().getContext())) { 329 Log.d(TAG, "skipping test that requires telephony feature"); 330 return; 331 } 332 setTestAsDefaultDialer(); 333 ContentValues values = new ContentValues(); 334 values.put(Voicemails.SOURCE_PACKAGE, FOREIGN_SOURCE); 335 336 Uri uri = mVoicemailProvider.insert(Voicemails.buildSourceUri(FOREIGN_SOURCE), values); 337 338 ContentValues updateValues = new ContentValues(); 339 updateValues.put(Voicemails.DIRTY, 2); 340 mVoicemailProvider.update(uri, updateValues, null, null); 341 342 try (Cursor cursor = mVoicemailProvider 343 .query(uri, new String[] {Voicemails.DIRTY}, null, null, null)) { 344 cursor.moveToFirst(); 345 assertEquals(1, cursor.getInt(0)); 346 } 347 } 348 testLocalUpdate_notDirty()349 public void testLocalUpdate_notDirty() throws Exception { 350 351 ContentValues values = new ContentValues(); 352 values.put(Voicemails.DIRTY, 1); 353 354 Uri uri = mVoicemailProvider.insert(Voicemails.buildSourceUri(mSourcePackageName), values); 355 356 ContentValues updateValues = new ContentValues(); 357 updateValues.put(Voicemails.IS_READ, "1"); 358 mVoicemailProvider.update(uri, updateValues, null, null); 359 360 try (Cursor cursor = mVoicemailProvider 361 .query(uri, new String[] {Voicemails.DIRTY}, null, null, null)) { 362 cursor.moveToFirst(); 363 assertEquals(cursor.getInt(0), 0); 364 } 365 } 366 testLocalUpdate_retainDirty_dirty()367 public void testLocalUpdate_retainDirty_dirty() throws Exception { 368 369 ContentValues values = new ContentValues(); 370 values.put(Voicemails.DIRTY, 1); 371 372 Uri uri = mVoicemailProvider.insert(Voicemails.buildSourceUri(mSourcePackageName), values); 373 374 ContentValues newValues = new ContentValues(); 375 newValues.put(Voicemails.TRANSCRIPTION, "foo"); 376 newValues.put(Voicemails.DIRTY, Voicemails.DIRTY_RETAIN); 377 378 mVoicemailProvider.update(uri, newValues, null, null); 379 380 try (Cursor cursor = mVoicemailProvider 381 .query(uri, new String[] {Voicemails.DIRTY}, null, null, null)) { 382 cursor.moveToFirst(); 383 assertEquals(cursor.getInt(0), 1); 384 } 385 } 386 387 // Data column should be automatically generated during insert. testInsert_doesNotUpdateDataColumn()388 public void testInsert_doesNotUpdateDataColumn() throws Exception { 389 390 final String newFilePath = "my/new/file/path"; 391 final ContentValues value = buildContentValuesForNewVoicemail(); 392 value.put(Voicemails._DATA, newFilePath); 393 mVoicemailProvider.insert(mVoicemailContentUri, value); 394 395 assertDataNotEquals(newFilePath); 396 } 397 testDataColumnUpdate_throwsIllegalArgumentException()398 public void testDataColumnUpdate_throwsIllegalArgumentException() throws Exception { 399 400 final ContentValues value = buildContentValuesForNewVoicemail(); 401 final Uri uri = mVoicemailProvider.insert(mVoicemailContentUri, value); 402 403 // Test: update 404 final String newFilePath = "another/file/path"; 405 406 value.clear(); 407 value.put(Voicemails._DATA, newFilePath); 408 try { 409 mVoicemailProvider.update(uri, value, null, null); 410 fail("IllegalArgumentException expected but not thrown."); 411 } catch (IllegalArgumentException e) { 412 // pass 413 } 414 415 assertDataNotEquals(newFilePath); 416 } 417 assertDataNotEquals(String newFilePath)418 private void assertDataNotEquals(String newFilePath) throws RemoteException { 419 // Make sure data value is not actually updated. 420 final Cursor cursor = mVoicemailProvider.query(mVoicemailContentUri, 421 new String[] {Voicemails._DATA}, null, null, null); 422 cursor.moveToNext(); 423 final String data = cursor.getString(0); 424 assertFalse(data.equals(newFilePath)); 425 } 426 buildContentValuesForNewVoicemail()427 private ContentValues buildContentValuesForNewVoicemail() { 428 final String insertCallsNumber = "0123456789"; 429 final long insertCallsDuration = 120; 430 final String insertSourceData = "internal_id"; 431 final String insertMimeType = "audio/mp3"; 432 final long insertDate = 1324478862000L; 433 434 ContentValues value = new ContentValues(); 435 value.put(Voicemails.NUMBER, insertCallsNumber); 436 value.put(Voicemails.DATE, insertDate); 437 value.put(Voicemails.DURATION, insertCallsDuration); 438 // Source package is expected to be inserted by the provider, if not set. 439 value.put(Voicemails.SOURCE_DATA, insertSourceData); 440 value.put(Voicemails.MIME_TYPE, insertMimeType); 441 value.put(Voicemails.IS_READ, false); 442 value.put(Voicemails.HAS_CONTENT, true); 443 444 return value; 445 } 446 testStatusTable()447 public void testStatusTable() throws Exception { 448 final String[] STATUS_PROJECTION = new String[] { 449 Status._ID, Status.SOURCE_PACKAGE, Status.CONFIGURATION_STATE, 450 Status.DATA_CHANNEL_STATE, Status.NOTIFICATION_CHANNEL_STATE, 451 Status.SETTINGS_URI, Status.VOICEMAIL_ACCESS_URI, 452 Status.QUOTA_OCCUPIED, Status.QUOTA_TOTAL}; 453 final int ID_INDEX = 0; 454 final int SOURCE_PACKAGE_INDEX = 1; 455 final int CONFIGURATION_STATE_INDEX = 2; 456 final int DATA_CHANNEL_STATE_INDEX = 3; 457 final int NOTIFICATION_CHANNEL_STATE_INDEX = 4; 458 final int SETTINGS_URI_INDEX = 5; 459 final int VOICEMAIL_ACCESS_URI_INDEX = 6; 460 final int QUOTA_OCCUPIED_INDEX = 7; 461 final int QUOTA_TOTAL_INDEX = 8; 462 463 int insertConfigurationState = Status.CONFIGURATION_STATE_OK; 464 int insertDataChannelState = Status.DATA_CHANNEL_STATE_OK; 465 int insertNotificationChannelState = Status.NOTIFICATION_CHANNEL_STATE_OK; 466 String insertSettingsUri = "settings_uri"; 467 String insertVoicemailAccessUri = "tel:901"; 468 int quotaOccupied = 7; 469 int quotaTotal = 42; 470 471 int updateDataChannelState = Status.DATA_CHANNEL_STATE_NO_CONNECTION; 472 int updateNotificationChannelState = Status.NOTIFICATION_CHANNEL_STATE_MESSAGE_WAITING; 473 String updateSettingsUri = "settings_uri_2"; 474 int updateQuotaOccupied = 1337; 475 int updateQuotaTotal = 2187; 476 477 // Test: insert 478 ContentValues value = new ContentValues(); 479 value.put(Status.CONFIGURATION_STATE, insertConfigurationState); 480 value.put(Status.DATA_CHANNEL_STATE, insertDataChannelState); 481 value.put(Status.NOTIFICATION_CHANNEL_STATE, insertNotificationChannelState); 482 value.put(Status.SETTINGS_URI, insertSettingsUri); 483 value.put(Status.VOICEMAIL_ACCESS_URI, insertVoicemailAccessUri); 484 value.put(Status.QUOTA_OCCUPIED, quotaOccupied); 485 value.put(Status.QUOTA_TOTAL, quotaTotal); 486 487 Uri uri = mStatusProvider.insert(mStatusContentUri, value); 488 Cursor cursor = mStatusProvider.query( 489 mStatusContentUri, STATUS_PROJECTION, null, null, null, null); 490 assertTrue(cursor.moveToNext()); 491 assertEquals(mSourcePackageName, cursor.getString(SOURCE_PACKAGE_INDEX)); 492 assertEquals(insertConfigurationState, cursor.getInt(CONFIGURATION_STATE_INDEX)); 493 assertEquals(insertDataChannelState, cursor.getInt(DATA_CHANNEL_STATE_INDEX)); 494 assertEquals(insertNotificationChannelState, 495 cursor.getInt(NOTIFICATION_CHANNEL_STATE_INDEX)); 496 assertEquals(insertSettingsUri, cursor.getString(SETTINGS_URI_INDEX)); 497 assertEquals(insertVoicemailAccessUri, cursor.getString(VOICEMAIL_ACCESS_URI_INDEX)); 498 assertEquals(quotaOccupied, cursor.getInt(QUOTA_OCCUPIED_INDEX)); 499 assertEquals(quotaTotal, cursor.getInt(QUOTA_TOTAL_INDEX)); 500 int id = cursor.getInt(ID_INDEX); 501 assertEquals(id, Integer.parseInt(uri.getLastPathSegment())); 502 cursor.close(); 503 504 // Test: update 505 value.clear(); 506 value.put(Status.DATA_CHANNEL_STATE, updateDataChannelState); 507 value.put(Status.NOTIFICATION_CHANNEL_STATE, updateNotificationChannelState); 508 value.put(Status.SETTINGS_URI, updateSettingsUri); 509 value.put(Status.QUOTA_OCCUPIED, updateQuotaOccupied); 510 value.put(Status.QUOTA_TOTAL, updateQuotaTotal); 511 512 mStatusProvider.update(uri, value, null, null); 513 cursor = mStatusProvider.query(mStatusContentUri, STATUS_PROJECTION, 514 Voicemails._ID + " = " + id, null, null, null); 515 assertEquals(1, cursor.getCount()); 516 assertTrue(cursor.moveToNext()); 517 assertEquals(mSourcePackageName, cursor.getString(SOURCE_PACKAGE_INDEX)); 518 assertEquals(updateDataChannelState, cursor.getInt(DATA_CHANNEL_STATE_INDEX)); 519 assertEquals(updateNotificationChannelState, 520 cursor.getInt(NOTIFICATION_CHANNEL_STATE_INDEX)); 521 assertEquals(updateSettingsUri, cursor.getString(SETTINGS_URI_INDEX)); 522 assertEquals(updateQuotaOccupied, cursor.getInt(QUOTA_OCCUPIED_INDEX)); 523 assertEquals(updateQuotaTotal, cursor.getInt(QUOTA_TOTAL_INDEX)); 524 cursor.close(); 525 526 // Test: delete 527 mStatusProvider.delete(mStatusContentUri, Voicemails._ID + " = " + id, null); 528 cursor = mStatusProvider.query(mStatusContentUri, STATUS_PROJECTION, 529 Voicemails._ID + " = " + id, null, null, null); 530 assertEquals(0, cursor.getCount()); 531 cursor.close(); 532 } 533 testVoicemailTablePermissions()534 public void testVoicemailTablePermissions() throws Exception { 535 ContentValues value = new ContentValues(); 536 value.put(Voicemails.NUMBER, "0123456789"); 537 value.put(Voicemails.SOURCE_PACKAGE, "some.other.package"); 538 try { 539 mVoicemailProvider.insert(mVoicemailContentUri, value); 540 fail("Expected SecurityException. None thrown."); 541 } catch (SecurityException e) { 542 // Expected result. 543 } 544 } 545 testStatusTablePermissions()546 public void testStatusTablePermissions() throws Exception { 547 ContentValues value = new ContentValues(); 548 value.put(Status.CONFIGURATION_STATE, Status.CONFIGURATION_STATE_OK); 549 value.put(Status.SOURCE_PACKAGE, "some.other.package"); 550 try { 551 mStatusProvider.insert(mStatusContentUri, value); 552 fail("Expected SecurityException. None thrown."); 553 } catch (SecurityException e) { 554 // Expected result. 555 } 556 } 557 hasTelephony(Context context)558 private static boolean hasTelephony(Context context) { 559 final PackageManager packageManager = context.getPackageManager(); 560 return packageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY) && 561 packageManager.hasSystemFeature(PackageManager.FEATURE_CONNECTION_SERVICE); 562 } 563 setTestAsDefaultDialer()564 private void setTestAsDefaultDialer() throws Exception { 565 assertTrue(mPreviousDefaultDialer == null); 566 mPreviousDefaultDialer = getDefaultDialer(getInstrumentation()); 567 setDefaultDialer(getInstrumentation(), PACKAGE); 568 } 569 setDefaultDialer(Instrumentation instrumentation, String packageName)570 private static String setDefaultDialer(Instrumentation instrumentation, String packageName) 571 throws Exception { 572 return executeShellCommand(instrumentation, COMMAND_SET_DEFAULT_DIALER + packageName); 573 } 574 getDefaultDialer(Instrumentation instrumentation)575 private static String getDefaultDialer(Instrumentation instrumentation) throws Exception { 576 return executeShellCommand(instrumentation, COMMAND_GET_DEFAULT_DIALER); 577 } 578 579 /** 580 * Executes the given shell command and returns the output in a string. Note that even if we 581 * don't care about the output, we have to read the stream completely to make the command 582 * execute. 583 */ executeShellCommand(Instrumentation instrumentation, String command)584 private static String executeShellCommand(Instrumentation instrumentation, 585 String command) throws Exception { 586 final ParcelFileDescriptor parcelFileDescriptor = 587 instrumentation.getUiAutomation().executeShellCommand(command); 588 BufferedReader bufferedReader = null; 589 try (InputStream in = new FileInputStream(parcelFileDescriptor.getFileDescriptor())) { 590 bufferedReader = new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8)); 591 String string = null; 592 StringBuilder out = new StringBuilder(); 593 while ((string = bufferedReader.readLine()) != null) { 594 out.append(string); 595 } 596 return out.toString(); 597 } finally { 598 if (bufferedReader != null) { 599 closeQuietly(bufferedReader); 600 } 601 closeQuietly(parcelFileDescriptor); 602 } 603 } 604 closeQuietly(AutoCloseable closeable)605 private static void closeQuietly(AutoCloseable closeable) { 606 if (closeable != null) { 607 try { 608 closeable.close(); 609 } catch (RuntimeException rethrown) { 610 throw rethrown; 611 } catch (Exception ignored) { 612 // Quietly. 613 } 614 } 615 } 616 } 617