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