1 /* 2 * Copyright (C) 2013 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 android.annotation.SuppressLint; 20 import android.app.Activity; 21 import android.app.Notification; 22 import android.provider.Settings.Secure; 23 import android.util.Log; 24 import android.view.View; 25 import android.view.ViewGroup; 26 27 import com.android.cts.verifier.R; 28 29 import org.json.JSONException; 30 import org.json.JSONObject; 31 32 import java.util.ArrayList; 33 import java.util.HashSet; 34 import java.util.List; 35 import java.util.Set; 36 import java.util.UUID; 37 38 import static com.android.cts.verifier.notifications.MockListener.*; 39 40 public class NotificationListenerVerifierActivity extends InteractiveVerifierActivity 41 implements Runnable { 42 private static final String TAG = "NoListenerVerifier"; 43 44 private String mTag1; 45 private String mTag2; 46 private String mTag3; 47 private int mIcon1; 48 private int mIcon2; 49 private int mIcon3; 50 private int mId1; 51 private int mId2; 52 private int mId3; 53 private long mWhen1; 54 private long mWhen2; 55 private long mWhen3; 56 private int mFlag1; 57 private int mFlag2; 58 private int mFlag3; 59 60 @Override getTitleResource()61 int getTitleResource() { 62 return R.string.nls_test; 63 } 64 65 @Override getInstructionsResource()66 int getInstructionsResource() { 67 return R.string.nls_info; 68 } 69 70 // Test Setup 71 72 @Override createTestItems()73 protected List<InteractiveTestCase> createTestItems() { 74 List<InteractiveTestCase> tests = new ArrayList<>(9); 75 tests.add(new IsEnabledTest()); 76 tests.add(new ServiceStartedTest()); 77 tests.add(new NotificationRecievedTest()); 78 tests.add(new DataIntactTest()); 79 tests.add(new DismissOneTest()); 80 tests.add(new DismissAllTest()); 81 tests.add(new IsDisabledTest()); 82 tests.add(new ServiceStoppedTest()); 83 tests.add(new NotificationNotReceivedTest()); 84 return tests; 85 } 86 87 @SuppressLint("NewApi") sendNotifications()88 private void sendNotifications() { 89 mTag1 = UUID.randomUUID().toString(); 90 mTag2 = UUID.randomUUID().toString(); 91 mTag3 = UUID.randomUUID().toString(); 92 93 mNm.cancelAll(); 94 95 mWhen1 = System.currentTimeMillis() + 1; 96 mWhen2 = System.currentTimeMillis() + 2; 97 mWhen3 = System.currentTimeMillis() + 3; 98 99 mIcon1 = R.drawable.ic_stat_alice; 100 mIcon2 = R.drawable.ic_stat_bob; 101 mIcon3 = R.drawable.ic_stat_charlie; 102 103 mId1 = NOTIFICATION_ID + 1; 104 mId2 = NOTIFICATION_ID + 2; 105 mId3 = NOTIFICATION_ID + 3; 106 107 mPackageString = "com.android.cts.verifier"; 108 109 Notification n1 = new Notification.Builder(mContext) 110 .setContentTitle("ClearTest 1") 111 .setContentText(mTag1.toString()) 112 .setPriority(Notification.PRIORITY_LOW) 113 .setSmallIcon(mIcon1) 114 .setWhen(mWhen1) 115 .setDeleteIntent(makeIntent(1, mTag1)) 116 .setOnlyAlertOnce(true) 117 .build(); 118 mNm.notify(mTag1, mId1, n1); 119 mFlag1 = Notification.FLAG_ONLY_ALERT_ONCE; 120 121 Notification n2 = new Notification.Builder(mContext) 122 .setContentTitle("ClearTest 2") 123 .setContentText(mTag2.toString()) 124 .setPriority(Notification.PRIORITY_HIGH) 125 .setSmallIcon(mIcon2) 126 .setWhen(mWhen2) 127 .setDeleteIntent(makeIntent(2, mTag2)) 128 .setAutoCancel(true) 129 .build(); 130 mNm.notify(mTag2, mId2, n2); 131 mFlag2 = Notification.FLAG_AUTO_CANCEL; 132 133 Notification n3 = new Notification.Builder(mContext) 134 .setContentTitle("ClearTest 3") 135 .setContentText(mTag3.toString()) 136 .setPriority(Notification.PRIORITY_LOW) 137 .setSmallIcon(mIcon3) 138 .setWhen(mWhen3) 139 .setDeleteIntent(makeIntent(3, mTag3)) 140 .setAutoCancel(true) 141 .setOnlyAlertOnce(true) 142 .build(); 143 mNm.notify(mTag3, mId3, n3); 144 mFlag3 = Notification.FLAG_ONLY_ALERT_ONCE | Notification.FLAG_AUTO_CANCEL; 145 } 146 147 // Tests 148 149 private class NotificationRecievedTest extends InteractiveTestCase { 150 @Override inflate(ViewGroup parent)151 View inflate(ViewGroup parent) { 152 return createAutoItem(parent, R.string.nls_note_received); 153 154 } 155 156 @Override setUp()157 void setUp() { 158 sendNotifications(); 159 status = READY; 160 // wait for notifications to move through the system 161 delay(); 162 } 163 164 @Override test()165 void test() { 166 MockListener.probeListenerPosted(mContext, 167 new MockListener.StringListResultCatcher() { 168 @Override 169 public void accept(List<String> result) { 170 if (result != null && result.size() > 0 && result.contains(mTag1)) { 171 status = PASS; 172 } else { 173 logFail(); 174 status = FAIL; 175 } 176 next(); 177 } 178 }); 179 delay(); // in case the catcher never returns 180 } 181 } 182 183 private class DataIntactTest extends InteractiveTestCase { 184 @Override inflate(ViewGroup parent)185 View inflate(ViewGroup parent) { 186 return createAutoItem(parent, R.string.nls_payload_intact); 187 } 188 189 @Override test()190 void test() { 191 MockListener.probeListenerPayloads(mContext, 192 new MockListener.StringListResultCatcher() { 193 @Override 194 public void accept(List<String> result) { 195 Set<String> found = new HashSet<String>(); 196 if (result == null || result.size() == 0) { 197 status = FAIL; 198 return; 199 } 200 boolean pass = true; 201 for (String payloadData : result) { 202 try { 203 JSONObject payload = new JSONObject(payloadData); 204 pass &= checkEquals(mPackageString, 205 payload.getString(JSON_PACKAGE), 206 "data integrity test: notification package (%s, %s)"); 207 String tag = payload.getString(JSON_TAG); 208 if (mTag1.equals(tag)) { 209 found.add(mTag1); 210 pass &= checkEquals(mIcon1, payload.getInt(JSON_ICON), 211 "data integrity test: notification icon (%d, %d)"); 212 pass &= checkFlagSet(mFlag1, payload.getInt(JSON_FLAGS), 213 "data integrity test: notification flags (%d, %d)"); 214 pass &= checkEquals(mId1, payload.getInt(JSON_ID), 215 "data integrity test: notification ID (%d, %d)"); 216 pass &= checkEquals(mWhen1, payload.getLong(JSON_WHEN), 217 "data integrity test: notification when (%d, %d)"); 218 } else if (mTag2.equals(tag)) { 219 found.add(mTag2); 220 pass &= checkEquals(mIcon2, payload.getInt(JSON_ICON), 221 "data integrity test: notification icon (%d, %d)"); 222 pass &= checkFlagSet(mFlag2, payload.getInt(JSON_FLAGS), 223 "data integrity test: notification flags (%d, %d)"); 224 pass &= checkEquals(mId2, payload.getInt(JSON_ID), 225 "data integrity test: notification ID (%d, %d)"); 226 pass &= checkEquals(mWhen2, payload.getLong(JSON_WHEN), 227 "data integrity test: notification when (%d, %d)"); 228 } else if (mTag3.equals(tag)) { 229 found.add(mTag3); 230 pass &= checkEquals(mIcon3, payload.getInt(JSON_ICON), 231 "data integrity test: notification icon (%d, %d)"); 232 pass &= checkFlagSet(mFlag3, payload.getInt(JSON_FLAGS), 233 "data integrity test: notification flags (%d, %d)"); 234 pass &= checkEquals(mId3, payload.getInt(JSON_ID), 235 "data integrity test: notification ID (%d, %d)"); 236 pass &= checkEquals(mWhen3, payload.getLong(JSON_WHEN), 237 "data integrity test: notification when (%d, %d)"); 238 } else { 239 pass = false; 240 logFail("unexpected notification tag: " + tag); 241 } 242 } catch (JSONException e) { 243 pass = false; 244 Log.e(TAG, "failed to unpack data from mocklistener", e); 245 } 246 } 247 248 pass &= found.size() == 3; 249 status = pass ? PASS : FAIL; 250 next(); 251 } 252 }); 253 delay(); // in case the catcher never returns 254 } 255 256 @Override tearDown()257 void tearDown() { 258 mNm.cancelAll(); 259 MockListener.resetListenerData(mContext); 260 delay(); 261 } 262 } 263 264 private class DismissOneTest extends InteractiveTestCase { 265 @Override inflate(ViewGroup parent)266 View inflate(ViewGroup parent) { 267 return createAutoItem(parent, R.string.nls_clear_one); 268 } 269 270 @Override setUp()271 void setUp() { 272 sendNotifications(); 273 status = READY; 274 delay(); 275 } 276 277 @Override test()278 void test() { 279 if (status == READY) { 280 MockListener.clearOne(mContext, mTag1, mId1); 281 status = RETEST; 282 } else { 283 MockListener.probeListenerRemoved(mContext, 284 new MockListener.StringListResultCatcher() { 285 @Override 286 public void accept(List<String> result) { 287 if (result != null && result.size() != 0 288 && result.contains(mTag1) 289 && !result.contains(mTag2) 290 && !result.contains(mTag3)) { 291 status = PASS; 292 } else { 293 logFail(); 294 status = FAIL; 295 } 296 next(); 297 } 298 }); 299 } 300 delay(); 301 } 302 303 @Override tearDown()304 void tearDown() { 305 mNm.cancelAll(); 306 MockListener.resetListenerData(mContext); 307 delay(); 308 } 309 } 310 311 private class DismissAllTest extends InteractiveTestCase { 312 @Override inflate(ViewGroup parent)313 View inflate(ViewGroup parent) { 314 return createAutoItem(parent, R.string.nls_clear_all); 315 } 316 317 @Override setUp()318 void setUp() { 319 sendNotifications(); 320 status = READY; 321 delay(); 322 } 323 324 @Override test()325 void test() { 326 if (status == READY) { 327 MockListener.clearAll(mContext); 328 status = RETEST; 329 } else { 330 MockListener.probeListenerRemoved(mContext, 331 new MockListener.StringListResultCatcher() { 332 @Override 333 public void accept(List<String> result) { 334 if (result != null && result.size() != 0 335 && result.contains(mTag1) 336 && result.contains(mTag2) 337 && result.contains(mTag3)) { 338 status = PASS; 339 } else { 340 logFail(); 341 status = FAIL; 342 } 343 next(); 344 } 345 }); 346 } 347 delay(); // in case the catcher never returns 348 } 349 350 @Override tearDown()351 void tearDown() { 352 mNm.cancelAll(); 353 MockListener.resetListenerData(mContext); 354 delay(); 355 } 356 } 357 358 private class IsDisabledTest extends InteractiveTestCase { 359 @Override inflate(ViewGroup parent)360 View inflate(ViewGroup parent) { 361 return createNlsSettingsItem(parent, R.string.nls_disable_service); 362 } 363 364 @Override autoStart()365 boolean autoStart() { 366 return true; 367 } 368 369 @Override test()370 void test() { 371 String listeners = Secure.getString(getContentResolver(), 372 ENABLED_NOTIFICATION_LISTENERS); 373 if (listeners == null || !listeners.contains(LISTENER_PATH)) { 374 status = PASS; 375 } else { 376 status = WAIT_FOR_USER; 377 } 378 next(); 379 } 380 381 @Override tearDown()382 void tearDown() { 383 MockListener.resetListenerData(mContext); 384 delay(); 385 } 386 } 387 388 private class ServiceStoppedTest extends InteractiveTestCase { 389 @Override inflate(ViewGroup parent)390 View inflate(ViewGroup parent) { 391 return createAutoItem(parent, R.string.nls_service_stopped); 392 } 393 394 @Override test()395 void test() { 396 MockListener.probeListenerStatus(mContext, 397 new MockListener.StatusCatcher() { 398 @Override 399 public void accept(int result) { 400 if (result == Activity.RESULT_OK) { 401 logFail(); 402 status = FAIL; 403 } else { 404 status = PASS; 405 } 406 next(); 407 } 408 }); 409 delay(); // in case the catcher never returns 410 } 411 412 @Override tearDown()413 void tearDown() { 414 // wait for intent to move through the system 415 delay(); 416 } 417 } 418 419 private class NotificationNotReceivedTest extends InteractiveTestCase { 420 @Override inflate(ViewGroup parent)421 View inflate(ViewGroup parent) { 422 return createAutoItem(parent, R.string.nls_note_missed); 423 424 } 425 426 @Override setUp()427 void setUp() { 428 sendNotifications(); 429 status = READY; 430 delay(); 431 } 432 433 @Override test()434 void test() { 435 MockListener.probeListenerPosted(mContext, 436 new MockListener.StringListResultCatcher() { 437 @Override 438 public void accept(List<String> result) { 439 if (result == null || result.size() == 0) { 440 status = PASS; 441 } else { 442 logFail(); 443 status = FAIL; 444 } 445 next(); 446 } 447 }); 448 delay(); // in case the catcher never returns 449 } 450 451 @Override tearDown()452 void tearDown() { 453 mNm.cancelAll(); 454 MockListener.resetListenerData(mContext); 455 delay(); 456 } 457 } 458 } 459