1 /* 2 * Copyright (C) 2015 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 com.android.cts.verifier.R; 20 21 import android.app.ActivityManager; 22 import android.app.AutomaticZenRule; 23 import android.app.NotificationManager; 24 import android.content.ComponentName; 25 import android.content.Context; 26 import android.content.Intent; 27 import android.net.Uri; 28 import android.provider.Settings; 29 import android.text.TextUtils; 30 import android.util.Log; 31 import android.view.View; 32 import android.view.ViewGroup; 33 34 import java.util.ArrayList; 35 import java.util.List; 36 import java.util.Map; 37 import java.util.Objects; 38 39 public class ConditionProviderVerifierActivity extends InteractiveVerifierActivity 40 implements Runnable { 41 protected static final String CP_PACKAGE = "com.android.cts.verifier"; 42 protected static final String CP_PATH = CP_PACKAGE + 43 "/com.android.cts.verifier.notifications.MockConditionProvider"; 44 45 @Override 46 protected int getTitleResource() { 47 return R.string.cp_test; 48 } 49 50 @Override 51 protected int getInstructionsResource() { 52 return R.string.cp_info; 53 } 54 55 // Test Setup 56 57 @Override 58 protected List<InteractiveTestCase> createTestItems() { 59 List<InteractiveTestCase> tests = new ArrayList<>(9); 60 ActivityManager am = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE); 61 if (am.isLowRamDevice()) { 62 tests.add(new CannotBeEnabledTest()); 63 tests.add(new ServiceStoppedTest()); 64 } else { 65 tests.add(new IsEnabledTest()); 66 tests.add(new ServiceStartedTest()); 67 tests.add(new CreateAutomaticZenRuleTest()); 68 tests.add(new UpdateAutomaticZenRuleTest()); 69 tests.add(new GetAutomaticZenRuleTest()); 70 tests.add(new GetAutomaticZenRulesTest()); 71 tests.add(new SubscribeAutomaticZenRuleTest()); 72 tests.add(new DeleteAutomaticZenRuleTest()); 73 tests.add(new UnsubscribeAutomaticZenRuleTest()); 74 tests.add(new RequestUnbindTest()); 75 tests.add(new RequestBindTest()); 76 tests.add(new IsDisabledTest()); 77 tests.add(new ServiceStoppedTest()); 78 } 79 return tests; 80 } 81 82 protected class IsEnabledTest extends InteractiveTestCase { 83 @Override 84 protected View inflate(ViewGroup parent) { 85 return createSettingsItem(parent, R.string.cp_enable_service); 86 } 87 88 @Override 89 boolean autoStart() { 90 return true; 91 } 92 93 @Override 94 protected void test() { 95 Intent settings = new Intent(Settings.ACTION_NOTIFICATION_POLICY_ACCESS_SETTINGS); 96 if (settings.resolveActivity(mPackageManager) == null) { 97 logFail("no settings activity"); 98 status = FAIL; 99 } else { 100 if (mNm.isNotificationPolicyAccessGranted()) { 101 status = PASS; 102 } else { 103 status = WAIT_FOR_USER; 104 } 105 next(); 106 } 107 } 108 109 protected void tearDown() { 110 // wait for the service to start 111 delay(); 112 } 113 114 @Override 115 protected Intent getIntent() { 116 return new Intent(Settings.ACTION_NOTIFICATION_POLICY_ACCESS_SETTINGS); 117 } 118 } 119 120 protected class CannotBeEnabledTest extends InteractiveTestCase { 121 @Override 122 protected View inflate(ViewGroup parent) { 123 return createNlsSettingsItem(parent, R.string.cp_cannot_enable_service); 124 } 125 126 @Override 127 boolean autoStart() { 128 return true; 129 } 130 131 @Override 132 protected void test() { 133 mNm.cancelAll(); 134 Intent settings = new Intent(Settings.ACTION_NOTIFICATION_POLICY_ACCESS_SETTINGS); 135 if (settings.resolveActivity(mPackageManager) == null) { 136 logFail("no settings activity"); 137 status = FAIL; 138 } else { 139 if (mNm.isNotificationPolicyAccessGranted()) { 140 status = FAIL; 141 } else { 142 status = PASS; 143 } 144 next(); 145 } 146 } 147 148 protected void tearDown() { 149 // wait for the service to start 150 delay(); 151 } 152 153 @Override 154 protected Intent getIntent() { 155 return new Intent(Settings.ACTION_NOTIFICATION_POLICY_ACCESS_SETTINGS); 156 } 157 } 158 159 protected class ServiceStartedTest extends InteractiveTestCase { 160 int mRetries = 5; 161 @Override 162 protected View inflate(ViewGroup parent) { 163 return createAutoItem(parent, R.string.cp_service_started); 164 } 165 166 @Override 167 protected void test() { 168 if (MockConditionProvider.getInstance().isConnected() 169 && MockConditionProvider.getInstance().isBound()) { 170 status = PASS; 171 next(); 172 } else { 173 if (--mRetries > 0) { 174 status = RETEST; 175 next(); 176 } else { 177 logFail(); 178 status = FAIL; 179 } 180 } 181 } 182 } 183 184 private class RequestUnbindTest extends InteractiveTestCase { 185 int mRetries = 5; 186 187 @Override 188 protected View inflate(ViewGroup parent) { 189 return createAutoItem(parent, R.string.nls_snooze); 190 191 } 192 193 @Override 194 protected void setUp() { 195 status = READY; 196 } 197 198 @Override 199 protected void test() { 200 if (status == READY) { 201 MockConditionProvider.getInstance().requestUnbind(); 202 status = RETEST; 203 } else { 204 if (MockConditionProvider.getInstance() == null || 205 !MockConditionProvider.getInstance().isConnected()) { 206 status = PASS; 207 } else { 208 if (--mRetries > 0) { 209 status = RETEST; 210 } else { 211 logFail(); 212 status = FAIL; 213 } 214 } 215 next(); 216 } 217 } 218 } 219 220 private class RequestBindTest extends InteractiveTestCase { 221 int mRetries = 5; 222 223 @Override 224 protected View inflate(ViewGroup parent) { 225 return createAutoItem(parent, R.string.nls_unsnooze); 226 227 } 228 229 @Override 230 protected void test() { 231 if (status == READY) { 232 MockConditionProvider.requestRebind(MockConditionProvider.COMPONENT_NAME); 233 status = RETEST; 234 } else { 235 if (MockConditionProvider.getInstance().isConnected() 236 && MockConditionProvider.getInstance().isBound()) { 237 status = PASS; 238 next(); 239 } else { 240 if (--mRetries > 0) { 241 status = RETEST; 242 next(); 243 } else { 244 logFail(); 245 status = FAIL; 246 } 247 } 248 } 249 } 250 } 251 252 253 private class CreateAutomaticZenRuleTest extends InteractiveTestCase { 254 private String id = null; 255 256 @Override 257 protected View inflate(ViewGroup parent) { 258 return createAutoItem(parent, R.string.cp_create_rule); 259 } 260 261 @Override 262 protected void test() { 263 AutomaticZenRule ruleToCreate = 264 createRule("Rule", "value", NotificationManager.INTERRUPTION_FILTER_ALARMS); 265 id = mNm.addAutomaticZenRule(ruleToCreate); 266 267 if (!TextUtils.isEmpty(id)) { 268 status = PASS; 269 } else { 270 logFail(); 271 status = FAIL; 272 } 273 next(); 274 } 275 276 @Override 277 protected void tearDown() { 278 if (id != null) { 279 mNm.removeAutomaticZenRule(id); 280 } 281 MockConditionProvider.getInstance().resetData(); 282 } 283 } 284 285 private class UpdateAutomaticZenRuleTest extends InteractiveTestCase { 286 private String id = null; 287 288 @Override 289 protected View inflate(ViewGroup parent) { 290 return createAutoItem(parent, R.string.cp_update_rule); 291 } 292 293 @Override 294 protected void setUp() { 295 id = mNm.addAutomaticZenRule(createRule("BeforeUpdate", "beforeValue", 296 NotificationManager.INTERRUPTION_FILTER_ALARMS)); 297 status = READY; 298 delay(); 299 } 300 301 @Override 302 protected void test() { 303 AutomaticZenRule updated = mNm.getAutomaticZenRule(id); 304 updated.setName("AfterUpdate"); 305 updated.setConditionId(MockConditionProvider.toConditionId("afterValue")); 306 updated.setInterruptionFilter(NotificationManager.INTERRUPTION_FILTER_NONE); 307 308 try { 309 boolean success = mNm.updateAutomaticZenRule(id, updated); 310 if (success && updated.equals(mNm.getAutomaticZenRule(id))) { 311 status = PASS; 312 } else { 313 logFail(); 314 status = FAIL; 315 } 316 } catch (Exception e) { 317 logFail("update failed", e); 318 status = FAIL; 319 } 320 next(); 321 } 322 323 @Override 324 protected void tearDown() { 325 if (id != null) { 326 mNm.removeAutomaticZenRule(id); 327 } 328 MockConditionProvider.getInstance().resetData(); 329 } 330 } 331 332 private class SubscribeAutomaticZenRuleTest extends InteractiveTestCase { 333 private String id = null; 334 private AutomaticZenRule ruleToCreate; 335 private int mRetries = 3; 336 337 @Override 338 protected View inflate(ViewGroup parent) { 339 return createAutoItem(parent, R.string.cp_subscribe_rule); 340 } 341 342 @Override 343 protected void setUp() { 344 ruleToCreate = createRule("RuleSubscribe", "Subscribevalue", 345 NotificationManager.INTERRUPTION_FILTER_ALARMS); 346 id = mNm.addAutomaticZenRule(ruleToCreate); 347 status = READY; 348 delay(); 349 } 350 351 @Override 352 protected void test() { 353 boolean foundMatch = false; 354 List<Uri> subscriptions = MockConditionProvider.getInstance().getSubscriptions(); 355 for (Uri actual : subscriptions) { 356 if (ruleToCreate.getConditionId().equals(actual)) { 357 status = PASS; 358 foundMatch = true; 359 break; 360 } 361 } 362 if (foundMatch) { 363 status = PASS; 364 next(); 365 } else if (--mRetries > 0) { 366 setFailed(); 367 } else { 368 status = RETEST; 369 next(); 370 } 371 } 372 373 @Override 374 protected void tearDown() { 375 if (id != null) { 376 mNm.removeAutomaticZenRule(id); 377 } 378 MockConditionProvider.getInstance().resetData(); 379 } 380 } 381 382 private class GetAutomaticZenRuleTest extends InteractiveTestCase { 383 private String id = null; 384 private AutomaticZenRule ruleToCreate; 385 386 @Override 387 protected View inflate(ViewGroup parent) { 388 return createAutoItem(parent, R.string.cp_get_rule); 389 } 390 391 @Override 392 protected void setUp() { 393 ruleToCreate = createRule("RuleGet", "valueGet", 394 NotificationManager.INTERRUPTION_FILTER_ALARMS); 395 id = mNm.addAutomaticZenRule(ruleToCreate); 396 status = READY; 397 delay(); 398 } 399 400 @Override 401 protected void test() { 402 AutomaticZenRule queriedRule = mNm.getAutomaticZenRule(id); 403 if (queriedRule != null 404 && ruleToCreate.getName().equals(queriedRule.getName()) 405 && ruleToCreate.getOwner().equals(queriedRule.getOwner()) 406 && ruleToCreate.getConditionId().equals(queriedRule.getConditionId()) 407 && ruleToCreate.isEnabled() == queriedRule.isEnabled()) { 408 status = PASS; 409 } else { 410 logFail(); 411 status = FAIL; 412 } 413 next(); 414 } 415 416 @Override 417 protected void tearDown() { 418 if (id != null) { 419 mNm.removeAutomaticZenRule(id); 420 } 421 MockConditionProvider.getInstance().resetData(); 422 } 423 } 424 425 private class GetAutomaticZenRulesTest extends InteractiveTestCase { 426 private List<String> ids = new ArrayList<>(); 427 private AutomaticZenRule rule1; 428 private AutomaticZenRule rule2; 429 430 @Override 431 protected View inflate(ViewGroup parent) { 432 return createAutoItem(parent, R.string.cp_get_rules); 433 } 434 435 @Override 436 protected void setUp() { 437 rule1 = createRule("Rule1", "value1", NotificationManager.INTERRUPTION_FILTER_ALARMS); 438 rule2 = createRule("Rule2", "value2", NotificationManager.INTERRUPTION_FILTER_NONE); 439 ids.add(mNm.addAutomaticZenRule(rule1)); 440 ids.add(mNm.addAutomaticZenRule(rule2)); 441 status = READY; 442 delay(); 443 } 444 445 @Override 446 protected void test() { 447 Map<String, AutomaticZenRule> rules = mNm.getAutomaticZenRules(); 448 449 if (rules == null || rules.size() != 2) { 450 logFail(); 451 status = FAIL; 452 next(); 453 return; 454 } 455 456 for (AutomaticZenRule createdRule : rules.values()) { 457 if (!compareRules(createdRule, rule1) && !compareRules(createdRule, rule2)) { 458 logFail(); 459 status = FAIL; 460 break; 461 } 462 } 463 status = PASS; 464 next(); 465 } 466 467 @Override 468 protected void tearDown() { 469 for (String id : ids) { 470 mNm.removeAutomaticZenRule(id); 471 } 472 MockConditionProvider.getInstance().resetData(); 473 } 474 } 475 476 private class DeleteAutomaticZenRuleTest extends InteractiveTestCase { 477 private String id = null; 478 479 @Override 480 protected View inflate(ViewGroup parent) { 481 return createAutoItem(parent, R.string.cp_delete_rule); 482 } 483 484 @Override 485 protected void test() { 486 AutomaticZenRule ruleToCreate = createRule("RuleDelete", "Deletevalue", 487 NotificationManager.INTERRUPTION_FILTER_ALARMS); 488 id = mNm.addAutomaticZenRule(ruleToCreate); 489 490 if (id != null) { 491 if (mNm.removeAutomaticZenRule(id)) { 492 if (mNm.getAutomaticZenRule(id) == null) { 493 status = PASS; 494 } else { 495 logFail(); 496 status = FAIL; 497 } 498 } else { 499 logFail(); 500 status = FAIL; 501 } 502 } else { 503 logFail("Couldn't test rule deletion; creation failed."); 504 status = FAIL; 505 } 506 next(); 507 } 508 509 @Override 510 protected void tearDown() { 511 MockConditionProvider.getInstance().resetData(); 512 delay(); 513 } 514 } 515 516 private class UnsubscribeAutomaticZenRuleTest extends InteractiveTestCase { 517 private String id = null; 518 private AutomaticZenRule ruleToCreate; 519 private int mSubscribeRetries = 3; 520 private int mUnsubscribeRetries = 3; 521 private boolean mSubscribing = true; 522 523 @Override 524 protected View inflate(ViewGroup parent) { 525 return createAutoItem(parent, R.string.cp_unsubscribe_rule); 526 } 527 528 @Override 529 protected void setUp() { 530 ruleToCreate = createRule("RuleUnsubscribe", "valueUnsubscribe", 531 NotificationManager.INTERRUPTION_FILTER_PRIORITY); 532 id = mNm.addAutomaticZenRule(ruleToCreate); 533 status = READY; 534 delay(); 535 } 536 537 @Override 538 protected void test() { 539 if (mSubscribing) { 540 // trying to subscribe 541 boolean foundMatch = false; 542 List<Uri> subscriptions = MockConditionProvider.getInstance().getSubscriptions(); 543 for (Uri actual : subscriptions) { 544 if (ruleToCreate.getConditionId().equals(actual)) { 545 status = PASS; 546 foundMatch = true; 547 break; 548 } 549 } 550 if (foundMatch) { 551 // Now that it's subscribed, remove the rule and verify that it 552 // unsubscribes. 553 Log.d(MockConditionProvider.TAG, "Found subscription, removing"); 554 mNm.removeAutomaticZenRule(id); 555 556 mSubscribing = false; 557 status = RETEST; 558 next(); 559 } else if (--mSubscribeRetries > 0) { 560 setFailed(); 561 } else { 562 status = RETEST; 563 next(); 564 } 565 } else { 566 // trying to unsubscribe 567 List<Uri> continuingSubscriptions 568 = MockConditionProvider.getInstance().getSubscriptions(); 569 boolean stillFoundMatch = false; 570 for (Uri actual : continuingSubscriptions) { 571 if (ruleToCreate.getConditionId().equals(actual)) { 572 stillFoundMatch = true; 573 break; 574 } 575 } 576 if (!stillFoundMatch) { 577 status = PASS; 578 next(); 579 } else if (stillFoundMatch && --mUnsubscribeRetries > 0) { 580 Log.d(MockConditionProvider.TAG, "Still found subscription, retrying"); 581 status = RETEST; 582 next(); 583 } else { 584 setFailed(); 585 } 586 } 587 } 588 589 @Override 590 protected void tearDown() { 591 mNm.removeAutomaticZenRule(id); 592 MockConditionProvider.getInstance().resetData(); 593 } 594 } 595 596 private class IsDisabledTest extends InteractiveTestCase { 597 @Override 598 protected View inflate(ViewGroup parent) { 599 return createSettingsItem(parent, R.string.cp_disable_service); 600 } 601 602 @Override 603 boolean autoStart() { 604 return true; 605 } 606 607 @Override 608 protected void test() { 609 if (!mNm.isNotificationPolicyAccessGranted()) { 610 status = PASS; 611 } else { 612 status = WAIT_FOR_USER; 613 } 614 next(); 615 } 616 617 @Override 618 protected Intent getIntent() { 619 return new Intent(Settings.ACTION_NOTIFICATION_POLICY_ACCESS_SETTINGS); 620 } 621 } 622 623 private class ServiceStoppedTest extends InteractiveTestCase { 624 int mRetries = 5; 625 626 @Override 627 protected View inflate(ViewGroup parent) { 628 return createAutoItem(parent, R.string.cp_service_stopped); 629 } 630 631 @Override 632 protected void test() { 633 if (MockConditionProvider.getInstance() == null || 634 !MockConditionProvider.getInstance().isConnected()) { 635 status = PASS; 636 } else { 637 if (--mRetries > 0) { 638 status = RETEST; 639 } else { 640 logFail(); 641 status = FAIL; 642 } 643 } 644 next(); 645 } 646 } 647 648 private AutomaticZenRule createRule(String name, String queryValue, int status) { 649 return new AutomaticZenRule(name, 650 ComponentName.unflattenFromString(CP_PATH), 651 MockConditionProvider.toConditionId(queryValue), 652 status, 653 true); 654 } 655 656 private boolean compareRules(AutomaticZenRule rule1, AutomaticZenRule rule2) { 657 return rule1.isEnabled() == rule2.isEnabled() 658 && Objects.equals(rule1.getName(), rule2.getName()) 659 && rule1.getInterruptionFilter() == rule2.getInterruptionFilter() 660 && Objects.equals(rule1.getConditionId(), rule2.getConditionId()) 661 && Objects.equals(rule1.getOwner(), rule2.getOwner()); 662 } 663 664 protected View createSettingsItem(ViewGroup parent, int messageId) { 665 return createUserItem(parent, R.string.cp_start_settings, messageId); 666 } 667 } 668