1 /* 2 * Copyright (C) 2014 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.cts.verifier.notifications; 18 19 import static com.android.cts.verifier.notifications.MockListener.JSON_AMBIENT; 20 import static com.android.cts.verifier.notifications.MockListener.JSON_MATCHES_ZEN_FILTER; 21 import static com.android.cts.verifier.notifications.MockListener.JSON_TAG; 22 23 import android.app.Activity; 24 import android.app.Notification; 25 import android.content.ContentProviderOperation; 26 import android.content.Intent; 27 import android.content.OperationApplicationException; 28 import android.database.Cursor; 29 import android.net.Uri; 30 import android.os.Bundle; 31 import android.os.RemoteException; 32 import android.provider.ContactsContract; 33 import android.provider.ContactsContract.CommonDataKinds.Email; 34 import android.provider.ContactsContract.CommonDataKinds.Phone; 35 import android.provider.ContactsContract.CommonDataKinds.StructuredName; 36 import android.provider.Settings.Secure; 37 import android.service.notification.NotificationListenerService; 38 import android.util.Log; 39 import com.android.cts.verifier.R; 40 import com.android.cts.verifier.nfc.TagVerifierActivity; 41 import org.json.JSONException; 42 import org.json.JSONObject; 43 44 import java.util.ArrayList; 45 import java.util.HashSet; 46 import java.util.List; 47 import java.util.Set; 48 49 public class NotificationAttentionManagementVerifierActivity 50 extends NotificationListenerVerifierActivity { 51 private static final String TAG = TagVerifierActivity.class.getSimpleName(); 52 private static final String ALICE = "Alice"; 53 private static final String ALICE_PHONE = "+16175551212"; 54 private static final String ALICE_EMAIL = "alice@_foo._bar"; 55 private static final String BOB = "Bob"; 56 private static final String BOB_PHONE = "+16505551212";; 57 private static final String BOB_EMAIL = "bob@_foo._bar"; 58 private static final String CHARLIE = "Charlie"; 59 private static final String CHARLIE_PHONE = "+13305551212"; 60 private static final String CHARLIE_EMAIL = "charlie@_foo._bar"; 61 private static final int MODE_NONE = 0; 62 private static final int MODE_URI = 1; 63 private static final int MODE_PHONE = 2; 64 private static final int MODE_EMAIL = 3; 65 private static final int DELAYED_SETUP = CLEARED; 66 67 private Uri mAliceUri; 68 private Uri mBobUri; 69 private Uri mCharlieUri; 70 71 @Override onCreate(Bundle savedInstanceState)72 protected void onCreate(Bundle savedInstanceState) { 73 super.onCreate(savedInstanceState, R.layout.nls_main); 74 setInfoResources(R.string.attention_test, R.string.attention_info, -1); 75 } 76 77 // Test Setup 78 79 @Override createTestItems()80 protected void createTestItems() { 81 createNlsSettingsItem(R.string.nls_enable_service); 82 createAutoItem(R.string.nls_service_started); 83 createAutoItem(R.string.attention_create_contacts); 84 createRetryItem(R.string.attention_filter_none); 85 createAutoItem(R.string.attention_all_are_filtered); 86 createRetryItem(R.string.attention_filter_all); 87 createAutoItem(R.string.attention_none_are_filtered); 88 createAutoItem(R.string.attention_default_order); 89 createAutoItem(R.string.attention_interruption_order); 90 createAutoItem(R.string.attention_priority_order); 91 createAutoItem(R.string.attention_ambient_bit); 92 createAutoItem(R.string.attention_lookup_order); 93 createAutoItem(R.string.attention_email_order); 94 createAutoItem(R.string.attention_phone_order); 95 createRetryItem(R.string.attention_filter_priority); 96 createAutoItem(R.string.attention_some_are_filtered); 97 createAutoItem(R.string.attention_delete_contacts); 98 } 99 100 // Test management 101 102 @Override updateStateMachine()103 protected void updateStateMachine() { 104 switch (mState) { 105 case 0: 106 testIsEnabled(mState); 107 break; 108 case 1: 109 testIsStarted(mState); 110 break; 111 case 2: 112 testInsertContacts(mState); 113 break; 114 case 3: 115 testModeNone(mState); 116 break; 117 case 4: 118 testNoneInterceptsAll(mState); 119 break; 120 case 5: 121 testModeAll(mState); 122 break; 123 case 6: 124 testAllInterceptsNothing(mState); 125 break; 126 case 7: 127 testDefaultOrder(mState); 128 break; 129 case 8: 130 testInterruptionOrder(mState); 131 break; 132 case 9: 133 testPrioritytOrder(mState); 134 break; 135 case 10: 136 testAmbientBits(mState); 137 break; 138 case 11: 139 testLookupUriOrder(mState); 140 break; 141 case 12: 142 testEmailOrder(mState); 143 break; 144 case 13: 145 testPhoneOrder(mState); 146 break; 147 case 14: 148 testModePriority(mState); 149 break; 150 case 15: 151 testPriorityInterceptsSome(mState); 152 break; 153 case 16: 154 testDeleteContacts(mState); 155 break; 156 case 17: 157 getPassButton().setEnabled(true); 158 mNm.cancelAll(); 159 break; 160 } 161 } 162 163 // usePriorities true: B, C, A 164 // usePriorities false: 165 // MODE_NONE: C, B, A 166 // otherwise: A, B ,C sendNotifications(int annotationMode, boolean usePriorities, boolean noisy)167 private void sendNotifications(int annotationMode, boolean usePriorities, boolean noisy) { 168 // TODO(cwren) Fixes flakey tests due to bug 17644321. Remove this line when it is fixed. 169 int baseId = NOTIFICATION_ID + (noisy ? 3 : 0); 170 171 // C, B, A when sorted by time. Times must be in the past. 172 long whenA = System.currentTimeMillis() - 4000000L; 173 long whenB = System.currentTimeMillis() - 2000000L; 174 long whenC = System.currentTimeMillis() - 1000000L; 175 176 // B, C, A when sorted by priorities 177 int priorityA = usePriorities ? Notification.PRIORITY_MIN : Notification.PRIORITY_DEFAULT; 178 int priorityB = usePriorities ? Notification.PRIORITY_MAX : Notification.PRIORITY_DEFAULT; 179 int priorityC = usePriorities ? Notification.PRIORITY_LOW : Notification.PRIORITY_DEFAULT; 180 181 Notification.Builder alice = new Notification.Builder(mContext) 182 .setContentTitle(ALICE) 183 .setContentText(ALICE) 184 .setSmallIcon(R.drawable.fs_good) 185 .setPriority(priorityA) 186 .setCategory(Notification.CATEGORY_MESSAGE) 187 .setWhen(whenA); 188 alice.setDefaults(noisy ? Notification.DEFAULT_SOUND | Notification.DEFAULT_VIBRATE : 0); 189 addPerson(annotationMode, alice, mAliceUri, ALICE_PHONE, ALICE_EMAIL); 190 mNm.notify(ALICE, baseId + 1, alice.build()); 191 192 Notification.Builder bob = new Notification.Builder(mContext) 193 .setContentTitle(BOB) 194 .setContentText(BOB) 195 .setSmallIcon(R.drawable.fs_warning) 196 .setPriority(priorityB) 197 .setCategory(Notification.CATEGORY_MESSAGE) 198 .setWhen(whenB); 199 addPerson(annotationMode, bob, mBobUri, BOB_PHONE, BOB_EMAIL); 200 mNm.notify(BOB, baseId + 2, bob.build()); 201 202 Notification.Builder charlie = new Notification.Builder(mContext) 203 .setContentTitle(CHARLIE) 204 .setContentText(CHARLIE) 205 .setSmallIcon(R.drawable.fs_error) 206 .setPriority(priorityC) 207 .setCategory(Notification.CATEGORY_MESSAGE) 208 .setWhen(whenC); 209 addPerson(annotationMode, charlie, mCharlieUri, CHARLIE_PHONE, CHARLIE_EMAIL); 210 mNm.notify(CHARLIE, baseId + 3, charlie.build()); 211 } 212 addPerson(int mode, Notification.Builder note, Uri uri, String phone, String email)213 private void addPerson(int mode, Notification.Builder note, 214 Uri uri, String phone, String email) { 215 if (mode == MODE_URI && uri != null) { 216 note.addPerson(uri.toString()); 217 } else if (mode == MODE_PHONE) { 218 note.addPerson(Uri.fromParts("tel", phone, null).toString()); 219 } else if (mode == MODE_EMAIL) { 220 note.addPerson(Uri.fromParts("mailto", email, null).toString()); 221 } 222 } 223 224 // Tests 225 testIsEnabled(int i)226 private void testIsEnabled(int i) { 227 // no setup required 228 Intent settings = new Intent("android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS"); 229 if (settings.resolveActivity(mPackageManager) == null) { 230 logWithStack("failed testIsEnabled: no settings activity"); 231 mStatus[i] = FAIL; 232 } else { 233 // TODO: find out why Secure.ENABLED_NOTIFICATION_LISTENERS is hidden 234 String listeners = Secure.getString(getContentResolver(), 235 "enabled_notification_listeners"); 236 if (listeners != null && listeners.contains(LISTENER_PATH)) { 237 mStatus[i] = PASS; 238 } else { 239 mStatus[i] = WAIT_FOR_USER; 240 } 241 } 242 next(); 243 } 244 testIsStarted(final int i)245 private void testIsStarted(final int i) { 246 if (mStatus[i] == SETUP) { 247 mStatus[i] = READY; 248 // wait for the service to start 249 delay(); 250 } else { 251 MockListener.probeListenerStatus(mContext, 252 new MockListener.StatusCatcher() { 253 @Override 254 public void accept(int result) { 255 if (result == Activity.RESULT_OK) { 256 mStatus[i] = PASS; 257 } else { 258 logWithStack("failed testIsStarted: " + result); 259 mStatus[i] = FAIL; 260 } 261 next(); 262 } 263 }); 264 } 265 } 266 testModeAll(final int i)267 private void testModeAll(final int i) { 268 if (mStatus[i] == READY || mStatus[i] == SETUP) { 269 MockListener.probeFilter(mContext, 270 new MockListener.IntegerResultCatcher() { 271 @Override 272 public void accept(int mode) { 273 if (mode == NotificationListenerService.INTERRUPTION_FILTER_ALL) { 274 mStatus[i] = PASS; 275 } else { 276 logWithStack("waiting testModeAll: " + mode); 277 mStatus[i] = WAIT_FOR_USER; 278 } 279 next(); 280 } 281 }); 282 } 283 } 284 testModePriority(final int i)285 private void testModePriority(final int i) { 286 if (mStatus[i] == READY || mStatus[i] == SETUP) { 287 MockListener.probeFilter(mContext, 288 new MockListener.IntegerResultCatcher() { 289 @Override 290 public void accept(int mode) { 291 if (mode == NotificationListenerService.INTERRUPTION_FILTER_PRIORITY) { 292 mStatus[i] = PASS; 293 } else { 294 logWithStack("waiting testModePriority: " + mode); 295 mStatus[i] = WAIT_FOR_USER; 296 } 297 next(); 298 } 299 }); 300 } 301 } 302 testModeNone(final int i)303 private void testModeNone(final int i) { 304 if (mStatus[i] == READY || mStatus[i] == SETUP) { 305 MockListener.probeFilter(mContext, 306 new MockListener.IntegerResultCatcher() { 307 @Override 308 public void accept(int mode) { 309 if (mode == NotificationListenerService.INTERRUPTION_FILTER_NONE) { 310 mStatus[i] = PASS; 311 } else { 312 logWithStack("waiting testModeNone: " + mode); 313 mStatus[i] = WAIT_FOR_USER; 314 } 315 next(); 316 } 317 }); 318 } 319 } 320 321 insertSingleContact(String name, String phone, String email, boolean starred)322 private void insertSingleContact(String name, String phone, String email, boolean starred) { 323 final ArrayList<ContentProviderOperation> operationList = 324 new ArrayList<ContentProviderOperation>(); 325 ContentProviderOperation.Builder builder = 326 ContentProviderOperation.newInsert(ContactsContract.RawContacts.CONTENT_URI); 327 builder.withValue(ContactsContract.RawContacts.STARRED, starred ? 1 : 0); 328 operationList.add(builder.build()); 329 330 builder = ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI); 331 builder.withValueBackReference(StructuredName.RAW_CONTACT_ID, 0); 332 builder.withValue(ContactsContract.Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE); 333 builder.withValue(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME, name); 334 operationList.add(builder.build()); 335 336 if (phone != null) { 337 builder = ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI); 338 builder.withValueBackReference(Phone.RAW_CONTACT_ID, 0); 339 builder.withValue(ContactsContract.Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE); 340 builder.withValue(Phone.TYPE, Phone.TYPE_MOBILE); 341 builder.withValue(Phone.NUMBER, phone); 342 builder.withValue(ContactsContract.Data.IS_PRIMARY, 1); 343 operationList.add(builder.build()); 344 } 345 if (email != null) { 346 builder = ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI); 347 builder.withValueBackReference(Email.RAW_CONTACT_ID, 0); 348 builder.withValue(ContactsContract.Data.MIMETYPE, Email.CONTENT_ITEM_TYPE); 349 builder.withValue(Email.TYPE, Email.TYPE_HOME); 350 builder.withValue(Email.DATA, email); 351 operationList.add(builder.build()); 352 } 353 354 try { 355 mContext.getContentResolver().applyBatch(ContactsContract.AUTHORITY, operationList); 356 } catch (RemoteException e) { 357 Log.e(TAG, String.format("%s: %s", e.toString(), e.getMessage())); 358 } catch (OperationApplicationException e) { 359 Log.e(TAG, String.format("%s: %s", e.toString(), e.getMessage())); 360 } 361 } 362 lookupContact(String phone)363 private Uri lookupContact(String phone) { 364 Cursor c = null; 365 try { 366 Uri phoneUri = Uri.withAppendedPath(ContactsContract.PhoneLookup.CONTENT_FILTER_URI, 367 Uri.encode(phone)); 368 String[] projection = new String[] { ContactsContract.Contacts._ID, 369 ContactsContract.Contacts.LOOKUP_KEY }; 370 c = mContext.getContentResolver().query(phoneUri, projection, null, null, null); 371 if (c != null && c.getCount() > 0) { 372 c.moveToFirst(); 373 int lookupIdx = c.getColumnIndex(ContactsContract.Contacts.LOOKUP_KEY); 374 int idIdx = c.getColumnIndex(ContactsContract.Contacts._ID); 375 String lookupKey = c.getString(lookupIdx); 376 long contactId = c.getLong(idIdx); 377 return ContactsContract.Contacts.getLookupUri(contactId, lookupKey); 378 } 379 } catch (Throwable t) { 380 Log.w(TAG, "Problem getting content resolver or performing contacts query.", t); 381 } finally { 382 if (c != null) { 383 c.close(); 384 } 385 } 386 return null; 387 } 388 testInsertContacts(final int i)389 private void testInsertContacts(final int i) { 390 if (mStatus[i] == SETUP) { 391 insertSingleContact(ALICE, ALICE_PHONE, ALICE_EMAIL, true); 392 insertSingleContact(BOB, BOB_PHONE, BOB_EMAIL, false); 393 // charlie is not in contacts 394 mStatus[i] = READY; 395 // wait for insertions to move through the system 396 delay(); 397 } else { 398 mAliceUri = lookupContact(ALICE_PHONE); 399 mBobUri = lookupContact(BOB_PHONE); 400 mCharlieUri = lookupContact(CHARLIE_PHONE); 401 402 mStatus[i] = PASS; 403 if (mAliceUri == null) { mStatus[i] = FAIL; } 404 if (mBobUri == null) { mStatus[i] = FAIL; } 405 if (mCharlieUri != null) { mStatus[i] = FAIL; } 406 next(); 407 } 408 } 409 410 // ordered by time: C, B, A testDefaultOrder(final int i)411 private void testDefaultOrder(final int i) { 412 if (mStatus[i] == SETUP) { 413 mNm.cancelAll(); 414 MockListener.resetListenerData(this); 415 mStatus[i] = CLEARED; 416 // wait for intent to move through the system 417 delay(); 418 } else if (mStatus[i] == CLEARED) { 419 sendNotifications(MODE_NONE, false, false); 420 mStatus[i] = READY; 421 // wait for notifications to move through the system 422 delay(); 423 } else { 424 MockListener.probeListenerOrder(mContext, 425 new MockListener.StringListResultCatcher() { 426 @Override 427 public void accept(List<String> orderedKeys) { 428 int rankA = findTagInKeys(ALICE, orderedKeys); 429 int rankB = findTagInKeys(BOB, orderedKeys); 430 int rankC = findTagInKeys(CHARLIE, orderedKeys); 431 if (rankC < rankB && rankB < rankA) { 432 mStatus[i] = PASS; 433 } else { 434 logWithStack("failed testDefaultOrder : " 435 + rankA + ", " + rankB + ", " + rankC); 436 mStatus[i] = FAIL; 437 } 438 next(); 439 } 440 }); 441 } 442 } 443 444 // ordered by priority: B, C, A testPrioritytOrder(final int i)445 private void testPrioritytOrder(final int i) { 446 if (mStatus[i] == SETUP) { 447 mNm.cancelAll(); 448 MockListener.resetListenerData(this); 449 mStatus[i] = CLEARED; 450 // wait for intent to move through the system 451 delay(); 452 } else if (mStatus[i] == CLEARED) { 453 sendNotifications(MODE_PHONE, true, false); 454 mStatus[i] = READY; 455 // wait for notifications to move through the system 456 delay(); 457 } else { 458 MockListener.probeListenerOrder(mContext, 459 new MockListener.StringListResultCatcher() { 460 @Override 461 public void accept(List<String> orderedKeys) { 462 int rankA = findTagInKeys(ALICE, orderedKeys); 463 int rankB = findTagInKeys(BOB, orderedKeys); 464 int rankC = findTagInKeys(CHARLIE, orderedKeys); 465 if (rankB < rankC && rankC < rankA) { 466 mStatus[i] = PASS; 467 } else { 468 logWithStack("failed testPrioritytOrder : " 469 + rankA + ", " + rankB + ", " + rankC); 470 mStatus[i] = FAIL; 471 } 472 next(); 473 } 474 }); 475 } 476 } 477 478 // B & C above the fold, A below testAmbientBits(final int i)479 private void testAmbientBits(final int i) { 480 if (mStatus[i] == SETUP) { 481 mNm.cancelAll(); 482 MockListener.resetListenerData(this); 483 mStatus[i] = CLEARED; 484 // wait for intent to move through the system 485 delay(); 486 } else if (mStatus[i] == CLEARED) { 487 sendNotifications(MODE_PHONE, true, false); 488 mStatus[i] = READY; 489 // wait for notifications to move through the system 490 delay(); 491 } else { 492 MockListener.probeListenerPayloads(mContext, 493 new MockListener.StringListResultCatcher() { 494 @Override 495 public void accept(List<String> result) { 496 boolean pass = false; 497 Set<String> found = new HashSet<String>(); 498 if (result != null && result.size() > 0) { 499 pass = true; 500 for (String payloadData : result) { 501 try { 502 JSONObject payload = new JSONObject(payloadData); 503 String tag = payload.getString(JSON_TAG); 504 if (found.contains(tag)) { 505 // multiple entries for same notification! 506 pass = false; 507 } else if (ALICE.equals(tag)) { 508 found.add(ALICE); 509 pass &= payload.getBoolean(JSON_AMBIENT); 510 } else if (BOB.equals(tag)) { 511 found.add(BOB); 512 pass &= !payload.getBoolean(JSON_AMBIENT); 513 } else if (CHARLIE.equals(tag)) { 514 found.add(CHARLIE); 515 pass &= !payload.getBoolean(JSON_AMBIENT); 516 } 517 } catch (JSONException e) { 518 pass = false; 519 Log.e(TAG, "failed to unpack data from mocklistener", e); 520 } 521 } 522 } 523 pass &= found.size() == 3; 524 mStatus[i] = pass ? PASS : FAIL; 525 next(); 526 } 527 }); 528 } 529 } 530 531 // ordered by contact affinity: A, B, C testLookupUriOrder(final int i)532 private void testLookupUriOrder(final int i) { 533 if (mStatus[i] == SETUP) { 534 mNm.cancelAll(); 535 MockListener.resetListenerData(this); 536 mStatus[i] = CLEARED; 537 // wait for intent to move through the system 538 delay(); 539 } else if (mStatus[i] == CLEARED) { 540 sendNotifications(MODE_URI, false, false); 541 mStatus[i] = READY; 542 // wait for notifications to move through the system 543 delay(); 544 } else { 545 MockListener.probeListenerOrder(mContext, 546 new MockListener.StringListResultCatcher() { 547 @Override 548 public void accept(List<String> orderedKeys) { 549 int rankA = findTagInKeys(ALICE, orderedKeys); 550 int rankB = findTagInKeys(BOB, orderedKeys); 551 int rankC = findTagInKeys(CHARLIE, orderedKeys); 552 if (rankA < rankB && rankB < rankC) { 553 mStatus[i] = PASS; 554 } else { 555 logWithStack("failed testLookupUriOrder : " 556 + rankA + ", " + rankB + ", " + rankC); 557 mStatus[i] = FAIL; 558 } 559 next(); 560 } 561 }); 562 } 563 } 564 565 // ordered by contact affinity: A, B, C testEmailOrder(final int i)566 private void testEmailOrder(final int i) { 567 if (mStatus[i] == SETUP) { 568 mNm.cancelAll(); 569 MockListener.resetListenerData(this); 570 mStatus[i] = DELAYED_SETUP; 571 // wait for intent to move through the system 572 delay(); 573 } else if (mStatus[i] == DELAYED_SETUP) { 574 sendNotifications(MODE_EMAIL, false, false); 575 mStatus[i] = READY; 576 // wait for notifications to move through the system 577 delay(); 578 } else { 579 MockListener.probeListenerOrder(mContext, 580 new MockListener.StringListResultCatcher() { 581 @Override 582 public void accept(List<String> orderedKeys) { 583 int rankA = findTagInKeys(ALICE, orderedKeys); 584 int rankB = findTagInKeys(BOB, orderedKeys); 585 int rankC = findTagInKeys(CHARLIE, orderedKeys); 586 if (rankA < rankB && rankB < rankC) { 587 mStatus[i] = PASS; 588 } else { 589 logWithStack("failed testEmailOrder : " 590 + rankA + ", " + rankB + ", " + rankC); 591 mStatus[i] = FAIL; 592 } 593 next(); 594 } 595 }); 596 } 597 } 598 599 // ordered by contact affinity: A, B, C testPhoneOrder(final int i)600 private void testPhoneOrder(final int i) { 601 if (mStatus[i] == SETUP) { 602 mNm.cancelAll(); 603 MockListener.resetListenerData(this); 604 mStatus[i] = CLEARED; 605 // wait for intent to move through the system 606 delay(); 607 } else if (mStatus[i] == CLEARED) { 608 sendNotifications(MODE_PHONE, false, false); 609 mStatus[i] = READY; 610 // wait for notifications to move through the system 611 delay(); 612 } else { 613 MockListener.probeListenerOrder(mContext, 614 new MockListener.StringListResultCatcher() { 615 @Override 616 public void accept(List<String> orderedKeys) { 617 int rankA = findTagInKeys(ALICE, orderedKeys); 618 int rankB = findTagInKeys(BOB, orderedKeys); 619 int rankC = findTagInKeys(CHARLIE, orderedKeys); 620 if (rankA < rankB && rankB < rankC) { 621 mStatus[i] = PASS; 622 } else { 623 logWithStack("failed testPhoneOrder : " 624 + rankA + ", " + rankB + ", " + rankC); 625 mStatus[i] = FAIL; 626 } 627 next(); 628 } 629 }); 630 } 631 } 632 633 // A starts at the top then falls to the bottom testInterruptionOrder(final int i)634 private void testInterruptionOrder(final int i) { 635 if (mStatus[i] == SETUP) { 636 mNm.cancelAll(); 637 MockListener.resetListenerData(this); 638 mStatus[i] = CLEARED; 639 // wait for intent to move through the system 640 delay(); 641 } else if (mStatus[i] == CLEARED) { 642 sendNotifications(MODE_NONE, false, true); 643 mStatus[i] = READY; 644 // wait for notifications to move through the system 645 delay(); 646 } else if (mStatus[i] == READY) { 647 MockListener.probeListenerOrder(mContext, 648 new MockListener.StringListResultCatcher() { 649 @Override 650 public void accept(List<String> orderedKeys) { 651 int rankA = findTagInKeys(ALICE, orderedKeys); 652 int rankB = findTagInKeys(BOB, orderedKeys); 653 int rankC = findTagInKeys(CHARLIE, orderedKeys); 654 if (rankA < rankB && rankA < rankC) { 655 mStatus[i] = RETRY; 656 delay(12000); 657 } else { 658 logWithStack("noisy notification did not sort to top."); 659 mStatus[i] = FAIL; 660 next(); 661 } 662 } 663 }); 664 } else if (mStatus[i] == RETRY) { 665 MockListener.probeListenerOrder(mContext, 666 new MockListener.StringListResultCatcher() { 667 @Override 668 public void accept(List<String> orderedKeys) { 669 int rankA = findTagInKeys(ALICE, orderedKeys); 670 int rankB = findTagInKeys(BOB, orderedKeys); 671 int rankC = findTagInKeys(CHARLIE, orderedKeys); 672 if (rankA > rankB && rankA > rankC) { 673 mStatus[i] = PASS; 674 } else { 675 logWithStack("noisy notification did not fade back into the list."); 676 mStatus[i] = FAIL; 677 } 678 next(); 679 } 680 }); 681 } 682 } 683 684 // Nothing should be filtered when mode is ALL testAllInterceptsNothing(final int i)685 private void testAllInterceptsNothing(final int i) { 686 if (mStatus[i] == SETUP) { 687 mNm.cancelAll(); 688 MockListener.resetListenerData(this); 689 mStatus[i] = CLEARED; 690 // wait for intent to move through the system 691 delay(); 692 } else if (mStatus[i] == CLEARED) { 693 sendNotifications(MODE_URI, false, false); 694 mStatus[i] = READY; 695 // wait for notifications to move through the system 696 delay(); 697 } else { 698 MockListener.probeListenerPayloads(mContext, 699 new MockListener.StringListResultCatcher() { 700 @Override 701 public void accept(List<String> result) { 702 boolean pass = false; 703 Set<String> found = new HashSet<String>(); 704 if (result != null && result.size() > 0) { 705 pass = true; 706 for (String payloadData : result) { 707 try { 708 JSONObject payload = new JSONObject(payloadData); 709 String tag = payload.getString(JSON_TAG); 710 if (found.contains(tag)) { 711 // multiple entries for same notification! 712 pass = false; 713 } else if (ALICE.equals(tag)) { 714 found.add(ALICE); 715 pass &= payload.getBoolean(JSON_MATCHES_ZEN_FILTER); 716 } else if (BOB.equals(tag)) { 717 found.add(BOB); 718 pass &= payload.getBoolean(JSON_MATCHES_ZEN_FILTER); 719 } else if (CHARLIE.equals(tag)) { 720 found.add(CHARLIE); 721 pass &= payload.getBoolean(JSON_MATCHES_ZEN_FILTER); 722 } 723 } catch (JSONException e) { 724 pass = false; 725 Log.e(TAG, "failed to unpack data from mocklistener", e); 726 } 727 } 728 } 729 pass &= found.size() == 3; 730 mStatus[i] = pass ? PASS : FAIL; 731 next(); 732 } 733 }); 734 } 735 } 736 737 // A should be filtered when mode is Priority/Starred. testPriorityInterceptsSome(final int i)738 private void testPriorityInterceptsSome(final int i) { 739 if (mStatus[i] == SETUP) { 740 mNm.cancelAll(); 741 MockListener.resetListenerData(this); 742 mStatus[i] = CLEARED; 743 // wait for intent to move through the system 744 delay(); 745 } else if (mStatus[i] == CLEARED) { 746 sendNotifications(MODE_URI, false, false); 747 mStatus[i] = READY; 748 // wait for notifications to move through the system 749 delay(); 750 } else { 751 MockListener.probeListenerPayloads(mContext, 752 new MockListener.StringListResultCatcher() { 753 @Override 754 public void accept(List<String> result) { 755 boolean pass = false; 756 Set<String> found = new HashSet<String>(); 757 if (result != null && result.size() > 0) { 758 pass = true; 759 for (String payloadData : result) { 760 try { 761 JSONObject payload = new JSONObject(payloadData); 762 String tag = payload.getString(JSON_TAG); 763 if (found.contains(tag)) { 764 // multiple entries for same notification! 765 pass = false; 766 } else if (ALICE.equals(tag)) { 767 found.add(ALICE); 768 pass &= payload.getBoolean(JSON_MATCHES_ZEN_FILTER); 769 } else if (BOB.equals(tag)) { 770 found.add(BOB); 771 pass &= !payload.getBoolean(JSON_MATCHES_ZEN_FILTER); 772 } else if (CHARLIE.equals(tag)) { 773 found.add(CHARLIE); 774 pass &= !payload.getBoolean(JSON_MATCHES_ZEN_FILTER); 775 } 776 } catch (JSONException e) { 777 pass = false; 778 Log.e(TAG, "failed to unpack data from mocklistener", e); 779 } 780 } 781 } 782 pass &= found.size() == 3; 783 mStatus[i] = pass ? PASS : FAIL; 784 next(); 785 } 786 }); 787 } 788 } 789 790 // Nothing should get through when mode is None. testNoneInterceptsAll(final int i)791 private void testNoneInterceptsAll(final int i) { 792 if (mStatus[i] == SETUP) { 793 mNm.cancelAll(); 794 MockListener.resetListenerData(this); 795 mStatus[i] = CLEARED; 796 // wait for intent to move through the system 797 delay(); 798 } else if (mStatus[i] == CLEARED) { 799 sendNotifications(MODE_URI, false, false); 800 mStatus[i] = READY; 801 // wait for notifications to move through the system 802 delay(); 803 } else { 804 MockListener.probeListenerPayloads(mContext, 805 new MockListener.StringListResultCatcher() { 806 @Override 807 public void accept(List<String> result) { 808 boolean pass = false; 809 Set<String> found = new HashSet<String>(); 810 if (result != null && result.size() > 0) { 811 pass = true; 812 for (String payloadData : result) { 813 try { 814 JSONObject payload = new JSONObject(payloadData); 815 String tag = payload.getString(JSON_TAG); 816 if (found.contains(tag)) { 817 // multiple entries for same notification! 818 pass = false; 819 } else if (ALICE.equals(tag)) { 820 found.add(ALICE); 821 pass &= !payload.getBoolean(JSON_MATCHES_ZEN_FILTER); 822 } else if (BOB.equals(tag)) { 823 found.add(BOB); 824 pass &= !payload.getBoolean(JSON_MATCHES_ZEN_FILTER); 825 } else if (CHARLIE.equals(tag)) { 826 found.add(CHARLIE); 827 pass &= !payload.getBoolean(JSON_MATCHES_ZEN_FILTER); 828 } 829 } catch (JSONException e) { 830 pass = false; 831 Log.e(TAG, "failed to unpack data from mocklistener", e); 832 } 833 } 834 } 835 pass &= found.size() == 3; 836 mStatus[i] = pass ? PASS : FAIL; 837 next(); 838 } 839 }); 840 } 841 } 842 843 /** Search a list of notification keys for a givcen tag. */ findTagInKeys(String tag, List<String> orderedKeys)844 private int findTagInKeys(String tag, List<String> orderedKeys) { 845 for (int i = 0; i < orderedKeys.size(); i++) { 846 if (orderedKeys.get(i).contains(tag)) { 847 return i; 848 } 849 } 850 return -1; 851 } 852 testDeleteContacts(final int i)853 private void testDeleteContacts(final int i) { 854 if (mStatus[i] == SETUP) { 855 final ArrayList<ContentProviderOperation> operationList = 856 new ArrayList<ContentProviderOperation>(); 857 operationList.add(ContentProviderOperation.newDelete(mAliceUri).build()); 858 operationList.add(ContentProviderOperation.newDelete(mBobUri).build()); 859 try { 860 mContext.getContentResolver().applyBatch(ContactsContract.AUTHORITY, operationList); 861 mStatus[i] = READY; 862 } catch (RemoteException e) { 863 Log.e(TAG, String.format("%s: %s", e.toString(), e.getMessage())); 864 mStatus[i] = FAIL; 865 } catch (OperationApplicationException e) { 866 Log.e(TAG, String.format("%s: %s", e.toString(), e.getMessage())); 867 mStatus[i] = FAIL; 868 } 869 // wait for deletions to move through the system 870 delay(3000); 871 } else if (mStatus[i] == READY) { 872 mAliceUri = lookupContact(ALICE_PHONE); 873 mBobUri = lookupContact(BOB_PHONE); 874 mCharlieUri = lookupContact(CHARLIE_PHONE); 875 876 mStatus[i] = PASS; 877 if (mAliceUri != null) { mStatus[i] = FAIL; } 878 if (mBobUri != null) { mStatus[i] = FAIL; } 879 if (mCharlieUri != null) { mStatus[i] = FAIL; } 880 next(); 881 } 882 } 883 } 884