1 /* 2 * Copyright (C) 2008 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 android.app.cts; 18 19 import android.app.Notification; 20 import android.app.NotificationManager; 21 import android.app.stubs.ActivityTestsBase; 22 import android.app.stubs.LocalDeniedService; 23 import android.app.stubs.LocalForegroundService; 24 import android.app.stubs.LocalGrantedService; 25 import android.app.stubs.LocalService; 26 import android.content.ComponentName; 27 import android.content.Context; 28 import android.content.Intent; 29 import android.content.ServiceConnection; 30 import android.cts.util.IBinderParcelable; 31 import android.os.Binder; 32 import android.os.Bundle; 33 import android.os.IBinder; 34 import android.os.Parcel; 35 import android.os.RemoteException; 36 import android.service.notification.StatusBarNotification; 37 import android.test.suitebuilder.annotation.MediumTest; 38 import android.util.Log; 39 import android.app.stubs.R; 40 41 public class ServiceTest extends ActivityTestsBase { 42 private static final String TAG = "ServiceTest"; 43 private static final int STATE_START_1 = 0; 44 private static final int STATE_START_2 = 1; 45 private static final int STATE_START_3 = 2; 46 private static final int STATE_UNBIND = 3; 47 private static final int STATE_DESTROY = 4; 48 private static final int STATE_REBIND = 5; 49 private static final int STATE_UNBIND_ONLY = 6; 50 private static final int DELAY = 5000; 51 private static final 52 String EXIST_CONN_TO_RECEIVE_SERVICE = "existing connection to receive service"; 53 private static final String EXIST_CONN_TO_LOSE_SERVICE = "existing connection to lose service"; 54 private int mExpectedServiceState; 55 private Context mContext; 56 private Intent mLocalService; 57 private Intent mLocalDeniedService; 58 private Intent mLocalForegroundService; 59 private Intent mLocalGrantedService; 60 private Intent mLocalService_ApplicationHasPermission; 61 private Intent mLocalService_ApplicationDoesNotHavePermission; 62 63 private IBinder mStateReceiver; 64 65 private static class EmptyConnection implements ServiceConnection { 66 @Override onServiceConnected(ComponentName name, IBinder service)67 public void onServiceConnected(ComponentName name, IBinder service) { 68 } 69 70 @Override onServiceDisconnected(ComponentName name)71 public void onServiceDisconnected(ComponentName name) { 72 } 73 } 74 75 private class TestConnection implements ServiceConnection { 76 private final boolean mExpectDisconnect; 77 private final boolean mSetReporter; 78 private boolean mMonitor; 79 private int mCount; 80 TestConnection(boolean expectDisconnect, boolean setReporter)81 public TestConnection(boolean expectDisconnect, boolean setReporter) { 82 mExpectDisconnect = expectDisconnect; 83 mSetReporter = setReporter; 84 mMonitor = !setReporter; 85 } 86 setMonitor(boolean v)87 void setMonitor(boolean v) { 88 mMonitor = v; 89 } 90 91 @Override onServiceConnected(ComponentName name, IBinder service)92 public void onServiceConnected(ComponentName name, IBinder service) { 93 if (mSetReporter) { 94 Parcel data = Parcel.obtain(); 95 data.writeInterfaceToken(LocalService.SERVICE_LOCAL); 96 data.writeStrongBinder(mStateReceiver); 97 try { 98 service.transact(LocalService.SET_REPORTER_CODE, data, null, 0); 99 } catch (RemoteException e) { 100 finishBad("DeadObjectException when sending reporting object"); 101 } 102 data.recycle(); 103 } 104 105 if (mMonitor) { 106 mCount++; 107 if (mExpectedServiceState == STATE_START_1) { 108 if (mCount == 1) { 109 finishGood(); 110 } else { 111 finishBad("onServiceConnected() again on an object when it " 112 + "should have been the first time"); 113 } 114 } else if (mExpectedServiceState == STATE_START_2) { 115 if (mCount == 2) { 116 finishGood(); 117 } else { 118 finishBad("onServiceConnected() the first time on an object " 119 + "when it should have been the second time"); 120 } 121 } else { 122 finishBad("onServiceConnected() called unexpectedly"); 123 } 124 } 125 } 126 127 @Override onServiceDisconnected(ComponentName name)128 public void onServiceDisconnected(ComponentName name) { 129 if (mMonitor) { 130 if (mExpectedServiceState == STATE_DESTROY) { 131 if (mExpectDisconnect) { 132 finishGood(); 133 } else { 134 finishBad("onServiceDisconnected() when it shouldn't have been"); 135 } 136 } else { 137 finishBad("onServiceDisconnected() called unexpectedly"); 138 } 139 } 140 } 141 } 142 startExpectResult(Intent service)143 private void startExpectResult(Intent service) { 144 startExpectResult(service, new Bundle()); 145 } 146 startExpectResult(Intent service, Bundle bundle)147 private void startExpectResult(Intent service, Bundle bundle) { 148 bundle.putParcelable(LocalService.REPORT_OBJ_NAME, new IBinderParcelable(mStateReceiver)); 149 150 boolean success = false; 151 try { 152 mExpectedServiceState = STATE_START_1; 153 mContext.startService(new Intent(service).putExtras(bundle)); 154 waitForResultOrThrow(DELAY, "service to start first time"); 155 mExpectedServiceState = STATE_START_2; 156 mContext.startService(new Intent(service).putExtras(bundle)); 157 waitForResultOrThrow(DELAY, "service to start second time"); 158 success = true; 159 } finally { 160 if (!success) { 161 mContext.stopService(service); 162 } 163 } 164 mExpectedServiceState = STATE_DESTROY; 165 mContext.stopService(service); 166 waitForResultOrThrow(DELAY, "service to be destroyed"); 167 } 168 getNotificationManager()169 private NotificationManager getNotificationManager() { 170 NotificationManager notificationManager = 171 (NotificationManager) getContext().getSystemService(Context.NOTIFICATION_SERVICE); 172 return notificationManager; 173 } 174 sendNotififcation(int id, String title)175 private void sendNotififcation(int id, String title) { 176 Notification notification = new Notification.Builder(getContext()) 177 .setContentTitle(title) 178 .setSmallIcon(R.drawable.black) 179 .build(); 180 getNotificationManager().notify(id, notification); 181 } 182 cancelNotification(int id)183 private void cancelNotification(int id) { 184 getNotificationManager().cancel(id); 185 } 186 assertNotification(int id, String expectedTitle)187 private void assertNotification(int id, String expectedTitle) { 188 String packageName = getContext().getPackageName(); 189 String errorMessage = null; 190 for (int i = 1; i<=2; i++) { 191 errorMessage = null; 192 StatusBarNotification[] sbns = getNotificationManager().getActiveNotifications(); 193 for (StatusBarNotification sbn : sbns) { 194 if (sbn.getId() == id && sbn.getPackageName().equals(packageName)) { 195 String actualTitle = 196 sbn.getNotification().extras.getString(Notification.EXTRA_TITLE); 197 if (expectedTitle.equals(actualTitle)) { 198 return; 199 } 200 // It's possible the notification hasn't been updated yet, so save the error 201 // message to only fail after retrying. 202 errorMessage = String.format("Wrong title for notification #%d: " 203 + "expected '%s', actual '%s'", id, expectedTitle, actualTitle); 204 Log.w(TAG, errorMessage); 205 } 206 } 207 // Notification might not be rendered yet, wait and try again... 208 try { 209 Thread.sleep(DELAY); 210 } catch (InterruptedException e) { 211 Thread.currentThread().interrupt(); 212 } 213 } 214 if (errorMessage != null) { 215 fail(errorMessage); 216 } 217 fail("No notification with id " + id + " for package " + packageName); 218 } 219 assertNoNotification(int id)220 private void assertNoNotification(int id) { 221 String packageName = getContext().getPackageName(); 222 StatusBarNotification found = null; 223 for (int i = 1; i<=2; i++) { 224 found = null; 225 StatusBarNotification[] sbns = getNotificationManager().getActiveNotifications(); 226 for (StatusBarNotification sbn : sbns) { 227 if (sbn.getId() == id && sbn.getPackageName().equals(packageName)) { 228 found = sbn; 229 break; 230 } 231 } 232 if (found != null) { 233 // Notification might not be canceled yet, wait and try again... 234 try { 235 Thread.sleep(DELAY); 236 } catch (InterruptedException e) { 237 Thread.currentThread().interrupt(); 238 } 239 } 240 } 241 assertNull("Found notification with id " + id + " for package " + packageName + ": " 242 + found, found); 243 } 244 245 /** 246 * test the service lifecycle, a service can be used in two ways: 247 * 1 It can be started and allowed to run until someone stops it or it stops itself. 248 * In this mode, it's started by calling Context.startService() 249 * and stopped by calling Context.stopService(). 250 * It can stop itself by calling Service.stopSelf() or Service.stopSelfResult(). 251 * Only one stopService() call is needed to stop the service, 252 * no matter how many times startService() was called. 253 * 2 It can be operated programmatically using an interface that it defines and exports. 254 * Clients establish a connection to the Service object 255 * and use that connection to call into the service. 256 * The connection is established by calling Context.bindService(), 257 * and is closed by calling Context.unbindService(). 258 * Multiple clients can bind to the same service. 259 * If the service has not already been launched, bindService() can optionally launch it. 260 */ bindExpectResult(Intent service)261 private void bindExpectResult(Intent service) { 262 TestConnection conn = new TestConnection(true, false); 263 TestConnection conn2 = new TestConnection(false, false); 264 boolean success = false; 265 try { 266 // Expect to see the TestConnection connected. 267 mExpectedServiceState = STATE_START_1; 268 mContext.bindService(service, conn, 0); 269 mContext.startService(service); 270 waitForResultOrThrow(DELAY, EXIST_CONN_TO_RECEIVE_SERVICE); 271 272 // Expect to see the second TestConnection connected. 273 mContext.bindService(service, conn2, 0); 274 waitForResultOrThrow(DELAY, "new connection to receive service"); 275 276 mContext.unbindService(conn2); 277 success = true; 278 } finally { 279 if (!success) { 280 mContext.unbindService(conn); 281 mContext.unbindService(conn2); 282 mContext.stopService(service); 283 } 284 } 285 286 // Expect to see the TestConnection disconnected. 287 mExpectedServiceState = STATE_DESTROY; 288 mContext.stopService(service); 289 waitForResultOrThrow(DELAY, EXIST_CONN_TO_LOSE_SERVICE); 290 291 mContext.unbindService(conn); 292 293 conn = new TestConnection(true, true); 294 success = false; 295 try { 296 // Expect to see the TestConnection connected. 297 conn.setMonitor(true); 298 mExpectedServiceState = STATE_START_1; 299 mContext.bindService(service, conn, 0); 300 mContext.startService(service); 301 waitForResultOrThrow(DELAY, EXIST_CONN_TO_RECEIVE_SERVICE); 302 303 success = true; 304 } finally { 305 if (!success) { 306 mContext.unbindService(conn); 307 mContext.stopService(service); 308 } 309 } 310 311 // Expect to see the service unbind and then destroyed. 312 conn.setMonitor(false); 313 mExpectedServiceState = STATE_UNBIND; 314 mContext.stopService(service); 315 waitForResultOrThrow(DELAY, EXIST_CONN_TO_LOSE_SERVICE); 316 317 mContext.unbindService(conn); 318 319 conn = new TestConnection(true, true); 320 success = false; 321 try { 322 // Expect to see the TestConnection connected. 323 conn.setMonitor(true); 324 mExpectedServiceState = STATE_START_1; 325 mContext.bindService(service, conn, 0); 326 mContext.startService(service); 327 waitForResultOrThrow(DELAY, EXIST_CONN_TO_RECEIVE_SERVICE); 328 329 success = true; 330 } finally { 331 if (!success) { 332 mContext.unbindService(conn); 333 mContext.stopService(service); 334 } 335 } 336 337 // Expect to see the service unbind but not destroyed. 338 conn.setMonitor(false); 339 mExpectedServiceState = STATE_UNBIND_ONLY; 340 mContext.unbindService(conn); 341 waitForResultOrThrow(DELAY, "existing connection to unbind service"); 342 343 // Expect to see the service rebound. 344 mExpectedServiceState = STATE_REBIND; 345 mContext.bindService(service, conn, 0); 346 waitForResultOrThrow(DELAY, "existing connection to rebind service"); 347 348 // Expect to see the service unbind and then destroyed. 349 mExpectedServiceState = STATE_UNBIND; 350 mContext.stopService(service); 351 waitForResultOrThrow(DELAY, EXIST_CONN_TO_LOSE_SERVICE); 352 353 mContext.unbindService(conn); 354 } 355 356 /** 357 * test automatically create the service as long as the binding exists 358 * and disconnect from an application service 359 */ bindAutoExpectResult(Intent service)360 private void bindAutoExpectResult(Intent service) { 361 TestConnection conn = new TestConnection(false, true); 362 boolean success = false; 363 try { 364 conn.setMonitor(true); 365 mExpectedServiceState = STATE_START_1; 366 mContext.bindService( 367 service, conn, Context.BIND_AUTO_CREATE); 368 waitForResultOrThrow(DELAY, "connection to start and receive service"); 369 success = true; 370 } finally { 371 if (!success) { 372 mContext.unbindService(conn); 373 } 374 } 375 mExpectedServiceState = STATE_UNBIND; 376 mContext.unbindService(conn); 377 waitForResultOrThrow(DELAY, "disconnecting from service"); 378 } 379 380 @Override setUp()381 protected void setUp() throws Exception { 382 super.setUp(); 383 mContext = getContext(); 384 mLocalService = new Intent(mContext, LocalService.class); 385 mLocalForegroundService = new Intent(mContext, LocalForegroundService.class); 386 mLocalDeniedService = new Intent(mContext, LocalDeniedService.class); 387 mLocalGrantedService = new Intent(mContext, LocalGrantedService.class); 388 mLocalService_ApplicationHasPermission = new Intent( 389 LocalService.SERVICE_LOCAL_GRANTED, null /*uri*/, mContext, LocalService.class); 390 mLocalService_ApplicationDoesNotHavePermission = new Intent( 391 LocalService.SERVICE_LOCAL_DENIED, null /*uri*/, mContext, LocalService.class); 392 mStateReceiver = new MockBinder(); 393 } 394 395 private class MockBinder extends Binder { 396 @Override onTransact(int code, Parcel data, Parcel reply, int flags)397 protected boolean onTransact(int code, Parcel data, Parcel reply, 398 int flags) throws RemoteException { 399 if (code == LocalService.STARTED_CODE) { 400 data.enforceInterface(LocalService.SERVICE_LOCAL); 401 int count = data.readInt(); 402 if (mExpectedServiceState == STATE_START_1) { 403 if (count == 1) { 404 finishGood(); 405 } else { 406 finishBad("onStart() again on an object when it " 407 + "should have been the first time"); 408 } 409 } else if (mExpectedServiceState == STATE_START_2) { 410 if (count == 2) { 411 finishGood(); 412 } else { 413 finishBad("onStart() the first time on an object when it " 414 + "should have been the second time"); 415 } 416 } else if (mExpectedServiceState == STATE_START_3) { 417 if (count == 3) { 418 finishGood(); 419 } else { 420 finishBad("onStart() the first time on an object when it " 421 + "should have been the third time"); 422 } 423 } else { 424 finishBad("onStart() was called when not expected (state=" 425 + mExpectedServiceState + ")"); 426 } 427 return true; 428 } else if (code == LocalService.DESTROYED_CODE) { 429 data.enforceInterface(LocalService.SERVICE_LOCAL); 430 if (mExpectedServiceState == STATE_DESTROY) { 431 finishGood(); 432 } else { 433 finishBad("onDestroy() was called when not expected (state=" 434 + mExpectedServiceState + ")"); 435 } 436 return true; 437 } else if (code == LocalService.UNBIND_CODE) { 438 data.enforceInterface(LocalService.SERVICE_LOCAL); 439 if (mExpectedServiceState == STATE_UNBIND) { 440 mExpectedServiceState = STATE_DESTROY; 441 } else if (mExpectedServiceState == STATE_UNBIND_ONLY) { 442 finishGood(); 443 } else { 444 finishBad("onUnbind() was called when not expected (state=" 445 + mExpectedServiceState + ")"); 446 } 447 return true; 448 } else if (code == LocalService.REBIND_CODE) { 449 data.enforceInterface(LocalService.SERVICE_LOCAL); 450 if (mExpectedServiceState == STATE_REBIND) { 451 finishGood(); 452 } else { 453 finishBad("onRebind() was called when not expected (state=" 454 + mExpectedServiceState + ")"); 455 } 456 return true; 457 } else { 458 return super.onTransact(code, data, reply, flags); 459 } 460 } 461 } 462 463 @Override tearDown()464 protected void tearDown() throws Exception { 465 super.tearDown(); 466 mContext.stopService(mLocalService); 467 mContext.stopService(mLocalForegroundService); 468 mContext.stopService(mLocalGrantedService); 469 mContext.stopService(mLocalService_ApplicationHasPermission); 470 } 471 testLocalStartClass()472 public void testLocalStartClass() throws Exception { 473 startExpectResult(mLocalService); 474 } 475 testLocalStartAction()476 public void testLocalStartAction() throws Exception { 477 startExpectResult(new Intent( 478 LocalService.SERVICE_LOCAL, null /*uri*/, mContext, LocalService.class)); 479 } 480 testLocalBindClass()481 public void testLocalBindClass() throws Exception { 482 bindExpectResult(mLocalService); 483 } 484 startForegroundService(int command)485 private void startForegroundService(int command) { 486 mContext.startService(new Intent(mLocalForegroundService).putExtras(LocalForegroundService 487 .newCommand(mStateReceiver, command))); 488 } 489 490 @MediumTest testForegroundService_dontRemoveNotificationOnStop()491 public void testForegroundService_dontRemoveNotificationOnStop() throws Exception { 492 boolean success = false; 493 try { 494 // Start service as foreground - it should show notification #1 495 mExpectedServiceState = STATE_START_1; 496 startForegroundService(LocalForegroundService.COMMAND_START_FOREGROUND); 497 waitForResultOrThrow(DELAY, "service to start first time"); 498 assertNotification(1, LocalForegroundService.getNotificationTitle(1)); 499 500 // Stop foreground without removing notification - it should still show notification #1 501 mExpectedServiceState = STATE_START_2; 502 startForegroundService( 503 LocalForegroundService.COMMAND_STOP_FOREGROUND_DONT_REMOVE_NOTIFICATION); 504 waitForResultOrThrow(DELAY, "service to stop foreground"); 505 assertNotification(1, LocalForegroundService.getNotificationTitle(1)); 506 507 // Sends another notification reusing the same notification id. 508 String newTitle = "YODA I AM"; 509 sendNotififcation(1, newTitle); 510 assertNotification(1, newTitle); 511 512 // Start service as foreground again - it should kill notification #1 and show #2 513 mExpectedServiceState = STATE_START_3; 514 startForegroundService(LocalForegroundService.COMMAND_START_FOREGROUND); 515 waitForResultOrThrow(DELAY, "service to start foreground 2nd time"); 516 assertNoNotification(1); 517 assertNotification(2, LocalForegroundService.getNotificationTitle(2)); 518 519 success = true; 520 } finally { 521 if (!success) { 522 mContext.stopService(mLocalForegroundService); 523 } 524 } 525 mExpectedServiceState = STATE_DESTROY; 526 mContext.stopService(mLocalForegroundService); 527 waitForResultOrThrow(DELAY, "service to be destroyed"); 528 assertNoNotification(1); 529 assertNoNotification(2); 530 } 531 532 @MediumTest testForegroundService_removeNotificationOnStop()533 public void testForegroundService_removeNotificationOnStop() throws Exception { 534 testForegroundServiceRemoveNotificationOnStop(false); 535 } 536 537 @MediumTest testForegroundService_removeNotificationOnStopUsingFlags()538 public void testForegroundService_removeNotificationOnStopUsingFlags() throws Exception { 539 testForegroundServiceRemoveNotificationOnStop(true); 540 } 541 testForegroundServiceRemoveNotificationOnStop(boolean usingFlags)542 private void testForegroundServiceRemoveNotificationOnStop(boolean usingFlags) 543 throws Exception { 544 boolean success = false; 545 try { 546 // Start service as foreground - it should show notification #1 547 mExpectedServiceState = STATE_START_1; 548 startForegroundService(LocalForegroundService.COMMAND_START_FOREGROUND); 549 waitForResultOrThrow(DELAY, "service to start first time"); 550 assertNotification(1, LocalForegroundService.getNotificationTitle(1)); 551 552 // Stop foreground removing notification 553 mExpectedServiceState = STATE_START_2; 554 if (usingFlags) { 555 startForegroundService(LocalForegroundService 556 .COMMAND_STOP_FOREGROUND_REMOVE_NOTIFICATION_USING_FLAGS); 557 } else { 558 startForegroundService(LocalForegroundService 559 .COMMAND_STOP_FOREGROUND_REMOVE_NOTIFICATION); 560 } 561 waitForResultOrThrow(DELAY, "service to stop foreground"); 562 assertNoNotification(1); 563 564 // Start service as foreground again - it should show notification #2 565 mExpectedServiceState = STATE_START_3; 566 startForegroundService(LocalForegroundService.COMMAND_START_FOREGROUND); 567 waitForResultOrThrow(DELAY, "service to start as foreground 2nd time"); 568 assertNotification(2, LocalForegroundService.getNotificationTitle(2)); 569 570 success = true; 571 } finally { 572 if (!success) { 573 mContext.stopService(mLocalForegroundService); 574 } 575 } 576 mExpectedServiceState = STATE_DESTROY; 577 mContext.stopService(mLocalForegroundService); 578 waitForResultOrThrow(DELAY, "service to be destroyed"); 579 assertNoNotification(1); 580 assertNoNotification(2); 581 } 582 583 @MediumTest testForegroundService_detachNotificationOnStop()584 public void testForegroundService_detachNotificationOnStop() throws Exception { 585 String newTitle = null; 586 boolean success = false; 587 try { 588 589 // Start service as foreground - it should show notification #1 590 mExpectedServiceState = STATE_START_1; 591 startForegroundService(LocalForegroundService.COMMAND_START_FOREGROUND); 592 waitForResultOrThrow(DELAY, "service to start first time"); 593 assertNotification(1, LocalForegroundService.getNotificationTitle(1)); 594 595 // Detaching notification 596 mExpectedServiceState = STATE_START_2; 597 startForegroundService( 598 LocalForegroundService.COMMAND_STOP_FOREGROUND_DETACH_NOTIFICATION); 599 waitForResultOrThrow(DELAY, "service to stop foreground"); 600 assertNotification(1, LocalForegroundService.getNotificationTitle(1)); 601 602 // Sends another notification reusing the same notification id. 603 newTitle = "YODA I AM"; 604 sendNotififcation(1, newTitle); 605 assertNotification(1, newTitle); 606 607 // Start service as foreground again - it should show notification #2.. 608 mExpectedServiceState = STATE_START_3; 609 startForegroundService(LocalForegroundService.COMMAND_START_FOREGROUND); 610 waitForResultOrThrow(DELAY, "service to start as foreground 2nd time"); 611 assertNotification(2, LocalForegroundService.getNotificationTitle(2)); 612 //...but keeping notification #1 613 assertNotification(1, newTitle); 614 615 success = true; 616 } finally { 617 if (!success) { 618 mContext.stopService(mLocalForegroundService); 619 } 620 } 621 mExpectedServiceState = STATE_DESTROY; 622 mContext.stopService(mLocalForegroundService); 623 waitForResultOrThrow(DELAY, "service to be destroyed"); 624 if (newTitle == null) { 625 assertNoNotification(1); 626 } else { 627 assertNotification(1, newTitle); 628 cancelNotification(1); 629 assertNoNotification(1); 630 } 631 assertNoNotification(2); 632 } 633 634 @MediumTest testLocalBindAction()635 public void testLocalBindAction() throws Exception { 636 bindExpectResult(new Intent( 637 LocalService.SERVICE_LOCAL, null /*uri*/, mContext, LocalService.class)); 638 } 639 640 @MediumTest testLocalBindAutoClass()641 public void testLocalBindAutoClass() throws Exception { 642 bindAutoExpectResult(mLocalService); 643 } 644 645 @MediumTest testLocalBindAutoAction()646 public void testLocalBindAutoAction() throws Exception { 647 bindAutoExpectResult(new Intent( 648 LocalService.SERVICE_LOCAL, null /*uri*/, mContext, LocalService.class)); 649 } 650 651 @MediumTest testLocalStartClassPermissions()652 public void testLocalStartClassPermissions() throws Exception { 653 startExpectResult(mLocalGrantedService); 654 startExpectResult(mLocalDeniedService); 655 } 656 657 @MediumTest testLocalStartActionPermissions()658 public void testLocalStartActionPermissions() throws Exception { 659 startExpectResult(mLocalService_ApplicationHasPermission); 660 startExpectResult(mLocalService_ApplicationDoesNotHavePermission); 661 } 662 663 @MediumTest testLocalBindClassPermissions()664 public void testLocalBindClassPermissions() throws Exception { 665 bindExpectResult(mLocalGrantedService); 666 bindExpectResult(mLocalDeniedService); 667 } 668 669 @MediumTest testLocalBindActionPermissions()670 public void testLocalBindActionPermissions() throws Exception { 671 bindExpectResult(mLocalService_ApplicationHasPermission); 672 bindExpectResult(mLocalService_ApplicationDoesNotHavePermission); 673 } 674 675 @MediumTest testLocalBindAutoClassPermissionGranted()676 public void testLocalBindAutoClassPermissionGranted() throws Exception { 677 bindAutoExpectResult(mLocalGrantedService); 678 } 679 680 @MediumTest testLocalBindAutoActionPermissionGranted()681 public void testLocalBindAutoActionPermissionGranted() throws Exception { 682 bindAutoExpectResult(mLocalService_ApplicationHasPermission); 683 } 684 685 @MediumTest testLocalUnbindTwice()686 public void testLocalUnbindTwice() throws Exception { 687 EmptyConnection conn = new EmptyConnection(); 688 mContext.bindService( 689 mLocalService_ApplicationHasPermission, conn, 0); 690 mContext.unbindService(conn); 691 try { 692 mContext.unbindService(conn); 693 fail("No exception thrown on the second unbind"); 694 } catch (IllegalArgumentException e) { 695 // expected 696 } 697 } 698 699 @MediumTest testImplicitIntentFailsOnApiLevel21()700 public void testImplicitIntentFailsOnApiLevel21() throws Exception { 701 Intent intent = new Intent(LocalService.SERVICE_LOCAL); 702 EmptyConnection conn = new EmptyConnection(); 703 try { 704 mContext.bindService(intent, conn, 0); 705 mContext.unbindService(conn); 706 fail("Implicit intents should be disallowed for apps targeting API 21+"); 707 } catch (IllegalArgumentException e) { 708 // expected 709 } 710 } 711 } 712