1 /* 2 * Copyright (C) 2017 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.internal.telephony.ims; 18 19 import static junit.framework.Assert.assertEquals; 20 import static junit.framework.Assert.assertFalse; 21 import static junit.framework.Assert.assertTrue; 22 23 import static org.mockito.Matchers.any; 24 import static org.mockito.Matchers.anyInt; 25 import static org.mockito.Matchers.eq; 26 import static org.mockito.Mockito.never; 27 import static org.mockito.Mockito.times; 28 import static org.mockito.Mockito.verify; 29 import static org.mockito.Mockito.when; 30 31 import android.content.ComponentName; 32 import android.content.Context; 33 import android.content.Intent; 34 import android.content.ServiceConnection; 35 import android.os.Handler; 36 import android.os.IBinder; 37 import android.os.Looper; 38 import android.os.RemoteException; 39 import android.support.test.filters.FlakyTest; 40 import android.support.test.runner.AndroidJUnit4; 41 import android.telephony.ims.ImsService; 42 import android.telephony.ims.stub.ImsFeatureConfiguration; 43 44 import com.android.ims.internal.IImsServiceFeatureCallback; 45 46 import org.junit.After; 47 import org.junit.Before; 48 import org.junit.Ignore; 49 import org.junit.Test; 50 import org.junit.runner.RunWith; 51 import org.mockito.ArgumentCaptor; 52 import org.mockito.Mock; 53 import org.mockito.Spy; 54 55 import java.util.HashSet; 56 57 /** 58 * Unit tests for ImsServiceController 59 */ 60 @RunWith(AndroidJUnit4.class) 61 @Ignore 62 public class ImsServiceControllerTest extends ImsTestBase { 63 64 private static final ImsServiceController.RebindRetry REBIND_RETRY = 65 new ImsServiceController.RebindRetry() { 66 @Override 67 public long getStartDelay() { 68 return 50; 69 } 70 71 @Override 72 public long getMaximumDelay() { 73 return 1000; 74 } 75 }; 76 77 @Spy TestImsServiceControllerAdapter mMockServiceControllerBinder; 78 @Mock ImsServiceController.ImsServiceControllerCallbacks mMockCallbacks; 79 @Mock IImsServiceFeatureCallback mMockProxyCallbacks; 80 @Mock Context mMockContext; 81 private final ComponentName mTestComponentName = new ComponentName("TestPkg", 82 "ImsServiceControllerTest"); 83 private final Handler mHandler = new Handler(Looper.getMainLooper()); 84 private ImsServiceController mTestImsServiceController; 85 86 @Before 87 @Override 88 public void setUp() throws Exception { 89 super.setUp(); 90 mTestImsServiceController = new ImsServiceController(mMockContext, mTestComponentName, 91 mMockCallbacks, mHandler, REBIND_RETRY); 92 mTestImsServiceController.addImsServiceFeatureCallback(mMockProxyCallbacks); 93 when(mMockContext.bindService(any(), any(), anyInt())).thenReturn(true); 94 } 95 96 97 @After 98 @Override 99 public void tearDown() throws Exception { 100 mTestImsServiceController = null; 101 super.tearDown(); 102 } 103 104 /** 105 * Tests that Context.bindService is called with the correct parameters when we call bind. 106 */ 107 @FlakyTest 108 @Test 109 public void testBindService() { 110 HashSet<ImsFeatureConfiguration.FeatureSlotPair> testFeatures = new HashSet<>(); 111 // Slot 1, MMTel 112 testFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(1, 1)); 113 // Slot 1, RCS 114 testFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(1, 2)); 115 ArgumentCaptor<Intent> intentCaptor = 116 ArgumentCaptor.forClass(Intent.class); 117 118 assertTrue(mTestImsServiceController.bind(testFeatures)); 119 120 int expectedFlags = Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE 121 | Context.BIND_IMPORTANT; 122 verify(mMockContext).bindService(intentCaptor.capture(), any(), eq(expectedFlags)); 123 Intent testIntent = intentCaptor.getValue(); 124 assertEquals(ImsService.SERVICE_INTERFACE, testIntent.getAction()); 125 assertEquals(mTestComponentName, testIntent.getComponent()); 126 } 127 128 /** 129 * Verify that if bind is called multiple times, we only call bindService once. 130 */ 131 @FlakyTest 132 @Test 133 public void testBindFailureWhenBound() { 134 HashSet<ImsFeatureConfiguration.FeatureSlotPair> testFeatures = new HashSet<>(); 135 // Slot 1, MMTel 136 testFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(1, 1)); 137 bindAndConnectService(testFeatures); 138 139 // already bound, should return false 140 assertFalse(mTestImsServiceController.bind(testFeatures)); 141 142 verify(mMockContext, times(1)).bindService(any(), any(), anyInt()); 143 } 144 145 /** 146 * Tests ImsServiceController callbacks are properly called when an ImsService is bound and 147 * connected. 148 */ 149 @FlakyTest 150 @Test 151 public void testBindServiceAndConnected() throws RemoteException { 152 HashSet<ImsFeatureConfiguration.FeatureSlotPair> testFeatures = new HashSet<>(); 153 // Slot 1, MMTel 154 testFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(1, 1)); 155 // Slot 1, RCS 156 testFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(1, 2)); 157 158 bindAndConnectService(testFeatures); 159 160 IBinder binder = mMockServiceControllerBinder.getBinder().asBinder(); 161 verify(binder).linkToDeath(any(), anyInt()); 162 verify(mMockServiceControllerBinder).createMMTelFeature(eq(1)); 163 verify(mMockServiceControllerBinder).createRcsFeature(eq(1)); 164 verify(mMockCallbacks).imsServiceFeatureCreated(eq(1), eq(1), 165 eq(mTestImsServiceController)); 166 verify(mMockCallbacks).imsServiceFeatureCreated(eq(1), eq(2), 167 eq(mTestImsServiceController)); 168 verify(mMockProxyCallbacks).imsFeatureCreated(eq(1), eq(1)); 169 verify(mMockProxyCallbacks).imsFeatureCreated(eq(1), eq(2)); 170 assertEquals(mMockServiceControllerBinder.getBinder(), 171 mTestImsServiceController.getImsServiceControllerBinder()); 172 } 173 174 /** 175 * Tests Emergency MMTEL ImsServiceController callbacks are properly called when an ImsService 176 * is bound and connected. 177 */ 178 @FlakyTest 179 @Test 180 public void testBindEmergencyMmTel() throws RemoteException { 181 HashSet<ImsFeatureConfiguration.FeatureSlotPair> testFeatures = new HashSet<>(); 182 // Slot 1, Emergency MMTel 183 testFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(1, 0)); 184 // Slot 1, MmTel 185 testFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(1, 1)); 186 187 bindAndConnectService(testFeatures); 188 189 IBinder binder = mMockServiceControllerBinder.getBinder().asBinder(); 190 verify(binder).linkToDeath(any(), anyInt()); 191 verify(mMockServiceControllerBinder).createMMTelFeature(eq(1)); 192 // We do not want this callback to happen for emergency MMTEL 193 verify(mMockCallbacks, never()).imsServiceFeatureCreated(eq(1), eq(0), 194 eq(mTestImsServiceController)); 195 verify(mMockCallbacks).imsServiceFeatureCreated(eq(1), eq(1), 196 eq(mTestImsServiceController)); 197 // Make sure this callback happens, which will notify the framework of emergency calling 198 // availability. 199 verify(mMockProxyCallbacks).imsFeatureCreated(eq(1), eq(0)); 200 verify(mMockProxyCallbacks).imsFeatureCreated(eq(1), eq(1)); 201 assertEquals(mMockServiceControllerBinder.getBinder(), 202 mTestImsServiceController.getImsServiceControllerBinder()); 203 } 204 205 /** 206 * Tests that if a callback is added after the ImsServiceController is already bound, we get a 207 * imsFeatureCreated callback. 208 */ 209 @FlakyTest 210 @Test 211 public void testCallbacksHappenWhenAddedAfterBind() throws RemoteException { 212 HashSet<ImsFeatureConfiguration.FeatureSlotPair> testFeatures = new HashSet<>(); 213 // Slot 1, Emergency MMTel 214 testFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(1, 0)); 215 // Slot 1, MmTel 216 testFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(1, 1)); 217 mTestImsServiceController.removeImsServiceFeatureCallbacks(); 218 219 bindAndConnectService(testFeatures); 220 // add the callback after bind 221 mTestImsServiceController.addImsServiceFeatureCallback(mMockProxyCallbacks); 222 223 // Make sure this callback happens for Emergency MMTEL and MMTEL 224 verify(mMockProxyCallbacks).imsFeatureCreated(eq(1), eq(0)); 225 verify(mMockProxyCallbacks).imsFeatureCreated(eq(1), eq(1)); 226 assertEquals(mMockServiceControllerBinder.getBinder(), 227 mTestImsServiceController.getImsServiceControllerBinder()); 228 } 229 230 /** 231 * Tests ImsServiceController callbacks are properly called when an ImsService is bound and 232 * connected. 233 */ 234 @FlakyTest 235 @Test 236 public void testBindServiceAndConnectedDisconnected() throws RemoteException { 237 HashSet<ImsFeatureConfiguration.FeatureSlotPair> testFeatures = new HashSet<>(); 238 // Slot 1, MMTel 239 testFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(1, 1)); 240 // Slot 1, RCS 241 testFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(1, 2)); 242 ServiceConnection conn = bindAndConnectService(testFeatures); 243 244 conn.onServiceDisconnected(mTestComponentName); 245 246 IBinder binder = mMockServiceControllerBinder.getBinder().asBinder(); 247 verify(binder).unlinkToDeath(any(), anyInt()); 248 // binder already disconnected, removeImsFeatures shouldn't be called. 249 verify(mMockServiceControllerBinder, never()).removeImsFeature(anyInt(), anyInt()); 250 verify(mMockCallbacks).imsServiceFeatureRemoved(eq(1), eq(1), 251 eq(mTestImsServiceController)); 252 verify(mMockCallbacks).imsServiceFeatureRemoved(eq(1), eq(2), 253 eq(mTestImsServiceController)); 254 verify(mMockProxyCallbacks).imsFeatureRemoved(eq(1), eq(1)); 255 verify(mMockProxyCallbacks).imsFeatureRemoved(eq(1), eq(2)); 256 } 257 258 /** 259 * Tests ImsServiceController callbacks are properly called when an ImsService is bound and 260 * connected. 261 */ 262 @FlakyTest 263 @Test 264 public void testBindServiceBindUnbind() throws RemoteException { 265 HashSet<ImsFeatureConfiguration.FeatureSlotPair> testFeatures = new HashSet<>(); 266 // Slot 1, MMTel 267 testFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(1, 1)); 268 // Slot 1, RCS 269 testFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(1, 2)); 270 ServiceConnection conn = bindAndConnectService(testFeatures); 271 272 mTestImsServiceController.unbind(); 273 274 verify(mMockContext).unbindService(eq(conn)); 275 IBinder binder = mMockServiceControllerBinder.getBinder().asBinder(); 276 verify(binder).unlinkToDeath(any(), anyInt()); 277 verify(mMockServiceControllerBinder).removeImsFeature(eq(1), eq(1)); 278 verify(mMockServiceControllerBinder).removeImsFeature(eq(1), eq(2)); 279 verify(mMockCallbacks).imsServiceFeatureRemoved(eq(1), eq(1), 280 eq(mTestImsServiceController)); 281 verify(mMockCallbacks).imsServiceFeatureRemoved(eq(1), eq(2), 282 eq(mTestImsServiceController)); 283 verify(mMockProxyCallbacks).imsFeatureRemoved(eq(1), eq(1)); 284 verify(mMockProxyCallbacks).imsFeatureRemoved(eq(1), eq(2)); 285 } 286 287 /** 288 * Ensures that imsServiceFeatureRemoved is called when the binder dies in another process. 289 */ 290 @FlakyTest 291 @Test 292 public void testBindServiceAndBinderDied() throws RemoteException { 293 HashSet<ImsFeatureConfiguration.FeatureSlotPair> testFeatures = new HashSet<>(); 294 // Slot 1, MMTel 295 testFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(1, 1)); 296 // Slot 1, RCS 297 testFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(1, 2)); 298 bindAndConnectService(testFeatures); 299 ArgumentCaptor<IBinder.DeathRecipient> deathCaptor = 300 ArgumentCaptor.forClass(IBinder.DeathRecipient.class); 301 IBinder binder = mMockServiceControllerBinder.getBinder().asBinder(); 302 verify(binder).linkToDeath(deathCaptor.capture(), anyInt()); 303 304 deathCaptor.getValue().binderDied(); 305 306 verify(mMockCallbacks).imsServiceFeatureRemoved(eq(1), eq(1), 307 eq(mTestImsServiceController)); 308 verify(mMockCallbacks).imsServiceFeatureRemoved(eq(1), eq(2), 309 eq(mTestImsServiceController)); 310 verify(mMockProxyCallbacks).imsFeatureRemoved(eq(1), eq(1)); 311 verify(mMockProxyCallbacks).imsFeatureRemoved(eq(1), eq(2)); 312 } 313 314 /** 315 * Ensures ImsService and ImsResolver are notified when a feature is added. 316 */ 317 @FlakyTest 318 @Test 319 public void testBindServiceAndAddFeature() throws RemoteException { 320 HashSet<ImsFeatureConfiguration.FeatureSlotPair> testFeatures = new HashSet<>(); 321 // Slot 1, MMTel 322 testFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(1, 1)); 323 bindAndConnectService(testFeatures); 324 verify(mMockServiceControllerBinder).createMMTelFeature(eq(1)); 325 verify(mMockCallbacks).imsServiceFeatureCreated(eq(1), eq(1), 326 eq(mTestImsServiceController)); 327 verify(mMockProxyCallbacks).imsFeatureCreated(eq(1), eq(1)); 328 // Create a new list with an additional item 329 HashSet<ImsFeatureConfiguration.FeatureSlotPair> testFeaturesWithAddition = new HashSet<>( 330 testFeatures); 331 testFeaturesWithAddition.add(new ImsFeatureConfiguration.FeatureSlotPair(2, 1)); 332 333 mTestImsServiceController.changeImsServiceFeatures(testFeaturesWithAddition); 334 335 verify(mMockServiceControllerBinder).createMMTelFeature(eq(2)); 336 verify(mMockCallbacks).imsServiceFeatureCreated(eq(2), eq(1), 337 eq(mTestImsServiceController)); 338 verify(mMockProxyCallbacks).imsFeatureCreated(eq(2), eq(1)); 339 } 340 341 /** 342 * Ensures ImsService and ImsResolver are notified when a feature is added. 343 */ 344 @FlakyTest 345 @Test 346 public void testBindServiceAndRemoveFeature() throws RemoteException { 347 HashSet<ImsFeatureConfiguration.FeatureSlotPair> testFeatures = new HashSet<>(); 348 // Slot 1, MMTel 349 testFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(1, 1)); 350 // Slot 2, MMTel 351 testFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(2, 1)); 352 bindAndConnectService(testFeatures); 353 verify(mMockServiceControllerBinder).createMMTelFeature(eq(1)); 354 verify(mMockCallbacks).imsServiceFeatureCreated(eq(1), eq(1), 355 eq(mTestImsServiceController)); 356 verify(mMockProxyCallbacks).imsFeatureCreated(eq(1), eq(1)); 357 verify(mMockServiceControllerBinder).createMMTelFeature(eq(2)); 358 verify(mMockCallbacks).imsServiceFeatureCreated(eq(2), eq(1), 359 eq(mTestImsServiceController)); 360 verify(mMockProxyCallbacks).imsFeatureCreated(eq(2), eq(1)); 361 // Create a new list with one less item 362 HashSet<ImsFeatureConfiguration.FeatureSlotPair> testFeaturesWithSubtraction = 363 new HashSet<>(testFeatures); 364 testFeaturesWithSubtraction.remove(new ImsFeatureConfiguration.FeatureSlotPair(2, 1)); 365 366 mTestImsServiceController.changeImsServiceFeatures(testFeaturesWithSubtraction); 367 368 verify(mMockServiceControllerBinder).removeImsFeature(eq(2), eq(1)); 369 verify(mMockCallbacks).imsServiceFeatureRemoved(eq(2), eq(1), 370 eq(mTestImsServiceController)); 371 verify(mMockProxyCallbacks).imsFeatureRemoved(eq(2), eq(1)); 372 } 373 374 /** 375 * Ensures ImsService and ImsResolver are notified when all features are removed. 376 */ 377 @FlakyTest 378 @Test 379 public void testBindServiceAndRemoveAllFeatures() throws RemoteException { 380 HashSet<ImsFeatureConfiguration.FeatureSlotPair> testFeatures = new HashSet<>(); 381 // slot 1, MMTel 382 testFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(1, 1)); 383 // slot 2, MMTel 384 testFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(2, 1)); 385 bindAndConnectService(testFeatures); 386 verify(mMockServiceControllerBinder).createMMTelFeature(eq(1)); 387 verify(mMockCallbacks).imsServiceFeatureCreated(eq(1), eq(1), 388 eq(mTestImsServiceController)); 389 verify(mMockProxyCallbacks).imsFeatureCreated(eq(1), eq(1)); 390 verify(mMockServiceControllerBinder).createMMTelFeature(eq(2)); 391 verify(mMockCallbacks).imsServiceFeatureCreated(eq(2), eq(1), 392 eq(mTestImsServiceController)); 393 verify(mMockProxyCallbacks).imsFeatureCreated(eq(2), eq(1)); 394 395 // Create a new empty list 396 mTestImsServiceController.changeImsServiceFeatures(new HashSet<>()); 397 398 verify(mMockServiceControllerBinder).removeImsFeature(eq(1), eq(1)); 399 verify(mMockCallbacks).imsServiceFeatureRemoved(eq(1), eq(1), 400 eq(mTestImsServiceController)); 401 verify(mMockProxyCallbacks).imsFeatureRemoved(eq(1), eq(1)); 402 verify(mMockServiceControllerBinder).removeImsFeature(eq(2), eq(1)); 403 verify(mMockCallbacks).imsServiceFeatureRemoved(eq(2), eq(1), 404 eq(mTestImsServiceController)); 405 verify(mMockProxyCallbacks).imsFeatureRemoved(eq(2), eq(1)); 406 } 407 408 /** 409 * Verifies that nothing is notified of a feature change if the service is not bound. 410 */ 411 @FlakyTest 412 @Test 413 public void testBindUnbindServiceAndAddFeature() throws RemoteException { 414 HashSet<ImsFeatureConfiguration.FeatureSlotPair> testFeatures = new HashSet<>(); 415 // Slot 1, MMTel 416 testFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(1, 1)); 417 bindAndConnectService(testFeatures); 418 mTestImsServiceController.unbind(); 419 // Create a new list with an additional item 420 HashSet<ImsFeatureConfiguration.FeatureSlotPair> testFeaturesWithAddition = new HashSet<>( 421 testFeatures); 422 // Try to create an RCS feature 423 testFeaturesWithAddition.add(new ImsFeatureConfiguration.FeatureSlotPair(1, 2)); 424 425 mTestImsServiceController.changeImsServiceFeatures(testFeaturesWithAddition); 426 427 verify(mMockServiceControllerBinder, never()).createRcsFeature(eq(1)); 428 verify(mMockCallbacks, never()).imsServiceFeatureCreated(eq(1), eq(2), 429 eq(mTestImsServiceController)); 430 verify(mMockProxyCallbacks, never()).imsFeatureCreated(eq(1), eq(2)); 431 } 432 433 /** 434 * Verifies that the ImsServiceController automatically tries to bind again after an untimely 435 * binder death. 436 */ 437 @FlakyTest 438 @Test 439 public void testAutoBindAfterBinderDied() throws RemoteException { 440 HashSet<ImsFeatureConfiguration.FeatureSlotPair> testFeatures = new HashSet<>(); 441 // Slot 1, MMTel 442 testFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(1, 1)); 443 // Slot 1, RCS 444 testFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(1, 2)); 445 bindAndConnectService(testFeatures); 446 447 getDeathRecipient().binderDied(); 448 449 long delay = mTestImsServiceController.getRebindDelay(); 450 waitForHandlerActionDelayed(mHandler, delay, 2 * delay); 451 // The service should autobind after rebind event occurs 452 verify(mMockContext, times(2)).bindService(any(), any(), anyInt()); 453 } 454 455 /** 456 * Ensure that bindService has only been called once before automatic rebind occurs. 457 */ 458 @FlakyTest 459 @Test 460 public void testNoAutoBindBeforeTimeout() throws RemoteException { 461 HashSet<ImsFeatureConfiguration.FeatureSlotPair> testFeatures = new HashSet<>(); 462 // Slot 1, MMTel 463 testFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(1, 1)); 464 // Slot 1, RCS 465 testFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(1, 2)); 466 bindAndConnectService(testFeatures); 467 468 getDeathRecipient().binderDied(); 469 470 // Be sure that there are no binds before the RETRY_TIMEOUT expires 471 verify(mMockContext, times(1)).bindService(any(), any(), anyInt()); 472 } 473 474 /** 475 * Ensure that calling unbind stops automatic rebind of the ImsService from occuring. 476 */ 477 @FlakyTest 478 @Test 479 public void testUnbindCauseAutoBindCancelAfterBinderDied() throws RemoteException { 480 HashSet<ImsFeatureConfiguration.FeatureSlotPair> testFeatures = new HashSet<>(); 481 // Slot 1, MMTel 482 testFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(1, 1)); 483 // Slot 1, RCS 484 testFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(1, 2)); 485 bindAndConnectService(testFeatures); 486 487 getDeathRecipient().binderDied(); 488 mTestImsServiceController.unbind(); 489 490 long delay = mTestImsServiceController.getRebindDelay(); 491 waitForHandlerActionDelayed(mHandler, delay, 2 * delay); 492 493 // Unbind should stop the autobind from occurring. 494 verify(mMockContext, times(1)).bindService(any(), any(), anyInt()); 495 } 496 497 /** 498 * Ensure that calling bind causes the automatic rebinding to be cancelled or not cause another 499 * call to bindService. 500 */ 501 @FlakyTest 502 @Test 503 public void testBindCauseAutoBindCancelAfterBinderDied() throws RemoteException { 504 HashSet<ImsFeatureConfiguration.FeatureSlotPair> testFeatures = new HashSet<>(); 505 // Slot 1, MMTel 506 testFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(1, 1)); 507 // Slot 1, RCS 508 testFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(1, 2)); 509 bindAndConnectService(testFeatures); 510 getDeathRecipient().binderDied(); 511 mTestImsServiceController.bind(testFeatures); 512 513 long delay = mTestImsServiceController.getRebindDelay(); 514 waitForHandlerActionDelayed(mHandler, delay, 2 * delay); 515 // Should only see two binds, not three from the auto rebind that occurs. 516 verify(mMockContext, times(2)).bindService(any(), any(), anyInt()); 517 } 518 519 private ServiceConnection bindAndConnectService( 520 HashSet<ImsFeatureConfiguration.FeatureSlotPair> testFeatures) { 521 ArgumentCaptor<ServiceConnection> serviceCaptor = 522 ArgumentCaptor.forClass(ServiceConnection.class); 523 assertTrue(mTestImsServiceController.bind(testFeatures)); 524 verify(mMockContext).bindService(any(), serviceCaptor.capture(), anyInt()); 525 serviceCaptor.getValue().onServiceConnected(mTestComponentName, 526 mMockServiceControllerBinder.getBinder().asBinder()); 527 return serviceCaptor.getValue(); 528 } 529 530 private IBinder.DeathRecipient getDeathRecipient() throws RemoteException { 531 ArgumentCaptor<IBinder.DeathRecipient> deathCaptor = 532 ArgumentCaptor.forClass(IBinder.DeathRecipient.class); 533 IBinder binder = mMockServiceControllerBinder.getBinder().asBinder(); 534 verify(binder).linkToDeath(deathCaptor.capture(), anyInt()); 535 return deathCaptor.getValue(); 536 } 537 } 538