• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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