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