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.server.telecom.tests; 18 19 import static com.android.server.telecom.tests.TelecomSystemTest.TEST_TIMEOUT; 20 21 import android.content.ComponentName; 22 import android.graphics.drawable.Icon; 23 import android.net.Uri; 24 import android.os.Binder; 25 import android.telecom.DisconnectCause; 26 import android.telecom.PhoneAccount; 27 import android.telecom.PhoneAccountHandle; 28 import android.test.suitebuilder.annotation.SmallTest; 29 30 import com.android.server.telecom.Call; 31 import com.android.server.telecom.CallIdMapper; 32 import com.android.server.telecom.ConnectionServiceFocusManager; 33 import com.android.server.telecom.ConnectionServiceRepository; 34 import com.android.server.telecom.ConnectionServiceWrapper; 35 import com.android.server.telecom.CreateConnectionProcessor; 36 import com.android.server.telecom.CreateConnectionResponse; 37 import com.android.server.telecom.PhoneAccountRegistrar; 38 39 import org.junit.After; 40 import org.junit.Before; 41 import org.junit.Test; 42 import org.junit.runner.RunWith; 43 import org.junit.runners.JUnit4; 44 import org.mockito.Mock; 45 import org.mockito.MockitoAnnotations; 46 import org.mockito.invocation.InvocationOnMock; 47 import org.mockito.stubbing.Answer; 48 49 import java.util.ArrayList; 50 import java.util.Arrays; 51 52 import static org.mockito.ArgumentMatchers.nullable; 53 import static org.mockito.Matchers.any; 54 import static org.mockito.Matchers.eq; 55 import static org.mockito.Mockito.doAnswer; 56 import static org.mockito.Mockito.mock; 57 import static org.mockito.Mockito.never; 58 import static org.mockito.Mockito.reset; 59 import static org.mockito.Mockito.timeout; 60 import static org.mockito.Mockito.verify; 61 import static org.mockito.Mockito.when; 62 63 /** 64 * Unit testing for CreateConnectionProcessor as well as CreateConnectionTimeout classes. 65 */ 66 @RunWith(JUnit4.class) 67 public class CreateConnectionProcessorTest extends TelecomTestCase { 68 69 private static final String TEST_PACKAGE = "com.android.server.telecom.tests"; 70 private static final String TEST_CLASS = 71 "com.android.server.telecom.tests.MockConnectionService"; 72 73 @Mock 74 ConnectionServiceRepository mMockConnectionServiceRepository; 75 @Mock 76 PhoneAccountRegistrar mMockAccountRegistrar; 77 @Mock 78 CreateConnectionResponse mMockCreateConnectionResponse; 79 @Mock 80 Call mMockCall; 81 @Mock 82 ConnectionServiceFocusManager mConnectionServiceFocusManager; 83 84 CreateConnectionProcessor mTestCreateConnectionProcessor; 85 86 @Override 87 @Before 88 public void setUp() throws Exception { 89 super.setUp(); 90 MockitoAnnotations.initMocks(this); 91 mContext = mComponentContextFixture.getTestDouble().getApplicationContext(); 92 93 when(mMockCall.getConnectionServiceFocusManager()).thenReturn( 94 mConnectionServiceFocusManager); 95 doAnswer(new Answer<Void>() { 96 @Override 97 public Void answer(InvocationOnMock invocation) { 98 Object[] args = invocation.getArguments(); 99 ConnectionServiceFocusManager.CallFocus focus = 100 (ConnectionServiceFocusManager.CallFocus) args[0]; 101 ConnectionServiceFocusManager.RequestFocusCallback callback = 102 (ConnectionServiceFocusManager.RequestFocusCallback) args[1]; 103 callback.onRequestFocusDone(focus); 104 return null; 105 } 106 } 107 ).when(mConnectionServiceFocusManager).requestFocus(any(), any()); 108 109 mTestCreateConnectionProcessor = new CreateConnectionProcessor(mMockCall, 110 mMockConnectionServiceRepository, mMockCreateConnectionResponse, 111 mMockAccountRegistrar, mContext); 112 } 113 114 @Override 115 @After 116 public void tearDown() throws Exception { 117 mTestCreateConnectionProcessor = null; 118 super.tearDown(); 119 } 120 121 @SmallTest 122 @Test 123 public void testSimPhoneAccountSuccess() throws Exception { 124 PhoneAccountHandle pAHandle = getNewTargetPhoneAccountHandle("tel_acct"); 125 when(mMockCall.isEmergencyCall()).thenReturn(false); 126 // No Connection Manager in this case 127 when(mMockAccountRegistrar.getSimCallManagerFromCall(any(Call.class))).thenReturn(null); 128 ConnectionServiceWrapper service = makeConnectionServiceWrapper(); 129 130 mTestCreateConnectionProcessor.process(); 131 132 verify(mMockCall).setConnectionManagerPhoneAccount(eq(pAHandle)); 133 verify(mMockCall).setTargetPhoneAccount(eq(pAHandle)); 134 verify(mMockCall).setConnectionService(eq(service)); 135 verify(service).createConnection(eq(mMockCall), any(CreateConnectionResponse.class)); 136 // Notify successful connection to call 137 CallIdMapper mockCallIdMapper = mock(CallIdMapper.class); 138 mTestCreateConnectionProcessor.handleCreateConnectionSuccess(mockCallIdMapper, null); 139 verify(mMockCreateConnectionResponse).handleCreateConnectionSuccess(mockCallIdMapper, null); 140 } 141 142 @SmallTest 143 @Test 144 public void testbadPhoneAccount() throws Exception { 145 PhoneAccountHandle pAHandle = null; 146 when(mMockCall.isEmergencyCall()).thenReturn(false); 147 when(mMockCall.getTargetPhoneAccount()).thenReturn(pAHandle); 148 givePhoneAccountBindPermission(pAHandle); 149 // No Connection Manager in this case 150 when(mMockAccountRegistrar.getSimCallManagerFromCall(any(Call.class))).thenReturn(null); 151 ConnectionServiceWrapper service = makeConnectionServiceWrapper(); 152 153 mTestCreateConnectionProcessor.process(); 154 155 verify(service, never()).createConnection(eq(mMockCall), 156 any(CreateConnectionResponse.class)); 157 verify(mMockCreateConnectionResponse).handleCreateConnectionFailure( 158 eq(new DisconnectCause(DisconnectCause.ERROR))); 159 } 160 161 @SmallTest 162 @Test 163 public void testConnectionManagerSuccess() throws Exception { 164 PhoneAccountHandle pAHandle = getNewTargetPhoneAccountHandle("tel_acct"); 165 when(mMockCall.isEmergencyCall()).thenReturn(false); 166 // Include a Connection Manager 167 PhoneAccountHandle callManagerPAHandle = getNewConnectionMangerHandle("cm_acct"); 168 ConnectionServiceWrapper service = makeConnectionServiceWrapper(); 169 // Make sure the target phone account has the correct permissions 170 PhoneAccount mFakeTargetPhoneAccount = makeQuickAccount("cm_acct", 171 PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION); 172 when(mMockAccountRegistrar.getPhoneAccountUnchecked(pAHandle)).thenReturn( 173 mFakeTargetPhoneAccount); 174 175 mTestCreateConnectionProcessor.process(); 176 177 verify(mMockCall).setConnectionManagerPhoneAccount(eq(callManagerPAHandle)); 178 verify(mMockCall).setTargetPhoneAccount(eq(pAHandle)); 179 verify(mMockCall).setConnectionService(eq(service)); 180 verify(service).createConnection(eq(mMockCall), 181 any(CreateConnectionResponse.class)); 182 // Notify successful connection to call 183 CallIdMapper mockCallIdMapper = mock(CallIdMapper.class); 184 mTestCreateConnectionProcessor.handleCreateConnectionSuccess(mockCallIdMapper, null); 185 verify(mMockCreateConnectionResponse).handleCreateConnectionSuccess(mockCallIdMapper, null); 186 } 187 188 @SmallTest 189 @Test 190 public void testConnectionManagerFailedFallToSim() throws Exception { 191 PhoneAccountHandle pAHandle = getNewTargetPhoneAccountHandle("tel_acct"); 192 when(mMockCall.isEmergencyCall()).thenReturn(false); 193 // Include a Connection Manager 194 PhoneAccountHandle callManagerPAHandle = getNewConnectionMangerHandle("cm_acct"); 195 ConnectionServiceWrapper service = makeConnectionServiceWrapper(); 196 when(mMockCall.getConnectionManagerPhoneAccount()).thenReturn(callManagerPAHandle); 197 PhoneAccount mFakeTargetPhoneAccount = makeQuickAccount("cm_acct", 198 PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION); 199 when(mMockAccountRegistrar.getPhoneAccountUnchecked(pAHandle)).thenReturn( 200 mFakeTargetPhoneAccount); 201 when(mMockCall.getConnectionService()).thenReturn(service); 202 // Put CreateConnectionProcessor in correct state to fail with ConnectionManager 203 mTestCreateConnectionProcessor.process(); 204 reset(mMockCall); 205 reset(service); 206 207 when(mMockCall.getConnectionServiceFocusManager()).thenReturn( 208 mConnectionServiceFocusManager); 209 // Notify that the ConnectionManager has denied the call. 210 when(mMockCall.getConnectionManagerPhoneAccount()).thenReturn(callManagerPAHandle); 211 when(mMockCall.getConnectionService()).thenReturn(service); 212 mTestCreateConnectionProcessor.handleCreateConnectionFailure( 213 new DisconnectCause(DisconnectCause.CONNECTION_MANAGER_NOT_SUPPORTED)); 214 215 // Verify that the Sim Phone Account is used correctly 216 verify(mMockCall).setConnectionManagerPhoneAccount(eq(pAHandle)); 217 verify(mMockCall).setTargetPhoneAccount(eq(pAHandle)); 218 verify(mMockCall).setConnectionService(eq(service)); 219 verify(service).createConnection(eq(mMockCall), any(CreateConnectionResponse.class)); 220 // Notify successful connection to call 221 CallIdMapper mockCallIdMapper = mock(CallIdMapper.class); 222 mTestCreateConnectionProcessor.handleCreateConnectionSuccess(mockCallIdMapper, null); 223 verify(mMockCreateConnectionResponse).handleCreateConnectionSuccess(mockCallIdMapper, null); 224 } 225 226 @SmallTest 227 @Test 228 public void testConnectionManagerFailedDoNotFallToSim() throws Exception { 229 PhoneAccountHandle pAHandle = getNewTargetPhoneAccountHandle("tel_acct"); 230 when(mMockCall.isEmergencyCall()).thenReturn(false); 231 // Include a Connection Manager 232 PhoneAccountHandle callManagerPAHandle = getNewConnectionMangerHandle("cm_acct"); 233 ConnectionServiceWrapper service = makeConnectionServiceWrapper(); 234 when(mMockCall.getConnectionManagerPhoneAccount()).thenReturn(callManagerPAHandle); 235 PhoneAccount mFakeTargetPhoneAccount = makeQuickAccount("cm_acct", 236 PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION); 237 when(mMockAccountRegistrar.getPhoneAccountUnchecked(pAHandle)).thenReturn( 238 mFakeTargetPhoneAccount); 239 when(mMockCall.getConnectionService()).thenReturn(service); 240 // Put CreateConnectionProcessor in correct state to fail with ConnectionManager 241 mTestCreateConnectionProcessor.process(); 242 reset(mMockCall); 243 reset(service); 244 245 when(mMockCall.getConnectionServiceFocusManager()).thenReturn( 246 mConnectionServiceFocusManager); 247 // Notify that the ConnectionManager has rejected the call. 248 when(mMockCall.getConnectionManagerPhoneAccount()).thenReturn(callManagerPAHandle); 249 when(mMockCall.getConnectionService()).thenReturn(service); 250 when(service.isServiceValid("createConnection")).thenReturn(true); 251 mTestCreateConnectionProcessor.handleCreateConnectionFailure( 252 new DisconnectCause(DisconnectCause.OTHER)); 253 254 // Verify call connection rejected 255 verify(mMockCreateConnectionResponse).handleCreateConnectionFailure( 256 new DisconnectCause(DisconnectCause.OTHER)); 257 } 258 259 @SmallTest 260 @Test 261 public void testEmergencyCallToSim() throws Exception { 262 when(mMockCall.isEmergencyCall()).thenReturn(true); 263 // Put in a regular phone account to be sure it doesn't call that 264 PhoneAccountHandle pAHandle = getNewTargetPhoneAccountHandle("tel_acct"); 265 // Include a Connection Manager to be sure it doesn't call that 266 PhoneAccount callManagerPA = getNewConnectionManagerPhoneAccount("cm_acct", 0); 267 ConnectionServiceWrapper service = makeConnectionServiceWrapper(); 268 PhoneAccount emergencyPhoneAccount = makeEmergencyPhoneAccount("tel_emer"); 269 PhoneAccountHandle emergencyPhoneAccountHandle = emergencyPhoneAccount.getAccountHandle(); 270 271 mTestCreateConnectionProcessor.process(); 272 273 verify(mMockCall).setConnectionManagerPhoneAccount(eq(emergencyPhoneAccountHandle)); 274 verify(mMockCall).setTargetPhoneAccount(eq(emergencyPhoneAccountHandle)); 275 verify(mMockCall).setConnectionService(eq(service)); 276 verify(service).createConnection(eq(mMockCall), any(CreateConnectionResponse.class)); 277 // Notify successful connection to call 278 CallIdMapper mockCallIdMapper = mock(CallIdMapper.class); 279 mTestCreateConnectionProcessor.handleCreateConnectionSuccess(mockCallIdMapper, null); 280 verify(mMockCreateConnectionResponse).handleCreateConnectionSuccess(mockCallIdMapper, null); 281 } 282 283 @SmallTest 284 @Test 285 public void testEmergencyCallSimFailToConnectionManager() throws Exception { 286 when(mMockCall.isEmergencyCall()).thenReturn(true); 287 when(mMockCall.getHandle()).thenReturn(Uri.parse("")); 288 // Put in a regular phone account to be sure it doesn't call that 289 PhoneAccountHandle pAHandle = getNewTargetPhoneAccountHandle("tel_acct"); 290 when(mMockAccountRegistrar.getOutgoingPhoneAccountForSchemeOfCurrentUser( 291 nullable(String.class))).thenReturn(pAHandle); 292 // Include a normal Connection Manager to be sure it doesn't call that 293 PhoneAccount callManagerPA = getNewConnectionManagerPhoneAccount("cm_acct", 0); 294 // Include a connection Manager for the user with the capability to make calls 295 PhoneAccount emerCallManagerPA = getNewEmergencyConnectionManagerPhoneAccount("cm_acct", 296 PhoneAccount.CAPABILITY_PLACE_EMERGENCY_CALLS); 297 ConnectionServiceWrapper service = makeConnectionServiceWrapper(); 298 PhoneAccount emergencyPhoneAccount = makeEmergencyPhoneAccount("tel_emer"); 299 mTestCreateConnectionProcessor.process(); 300 reset(mMockCall); 301 reset(service); 302 303 when(mMockCall.getConnectionServiceFocusManager()).thenReturn( 304 mConnectionServiceFocusManager); 305 when(mMockCall.isEmergencyCall()).thenReturn(true); 306 307 // When Notify SIM connection fails, fall back to connection manager 308 mTestCreateConnectionProcessor.handleCreateConnectionFailure(new DisconnectCause( 309 DisconnectCause.REJECTED)); 310 311 verify(mMockCall).setConnectionManagerPhoneAccount( 312 eq(emerCallManagerPA.getAccountHandle())); 313 verify(mMockCall).setTargetPhoneAccount(eq(pAHandle)); 314 verify(mMockCall).setConnectionService(eq(service)); 315 verify(service).createConnection(eq(mMockCall), any(CreateConnectionResponse.class)); 316 } 317 318 private PhoneAccount makeEmergencyPhoneAccount(String id) { 319 final PhoneAccount emergencyPhoneAccount = makeQuickAccount(id, 320 PhoneAccount.CAPABILITY_PLACE_EMERGENCY_CALLS | 321 PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION); 322 PhoneAccountHandle emergencyPhoneAccountHandle = emergencyPhoneAccount.getAccountHandle(); 323 givePhoneAccountBindPermission(emergencyPhoneAccountHandle); 324 ArrayList<PhoneAccount> phoneAccounts = new ArrayList<PhoneAccount>() {{ 325 add(emergencyPhoneAccount); 326 }}; 327 when(mMockAccountRegistrar.getAllPhoneAccountsOfCurrentUser()).thenReturn(phoneAccounts); 328 return emergencyPhoneAccount; 329 } 330 331 private void givePhoneAccountBindPermission(PhoneAccountHandle handle) { 332 when(mMockAccountRegistrar.phoneAccountRequiresBindPermission(eq(handle))).thenReturn(true); 333 } 334 335 private PhoneAccountHandle getNewConnectionMangerHandle(String id) { 336 PhoneAccountHandle callManagerPAHandle = makeQuickAccountHandle(id); 337 when(mMockAccountRegistrar.getSimCallManagerFromCall(any(Call.class))).thenReturn( 338 callManagerPAHandle); 339 givePhoneAccountBindPermission(callManagerPAHandle); 340 return callManagerPAHandle; 341 } 342 343 private PhoneAccountHandle getNewTargetPhoneAccountHandle(String id) { 344 PhoneAccountHandle pAHandle = makeQuickAccountHandle(id); 345 when(mMockCall.getTargetPhoneAccount()).thenReturn(pAHandle); 346 givePhoneAccountBindPermission(pAHandle); 347 return pAHandle; 348 } 349 350 private PhoneAccount getNewConnectionManagerPhoneAccount(String id, int capability) { 351 PhoneAccount callManagerPA = makeQuickAccount(id, capability); 352 when(mMockAccountRegistrar.getSimCallManagerFromCall(any(Call.class))).thenReturn( 353 callManagerPA.getAccountHandle()); 354 givePhoneAccountBindPermission(callManagerPA.getAccountHandle()); 355 when(mMockAccountRegistrar.getPhoneAccountUnchecked( 356 callManagerPA.getAccountHandle())).thenReturn(callManagerPA); 357 return callManagerPA; 358 } 359 360 private PhoneAccount getNewEmergencyConnectionManagerPhoneAccount(String id, int capability) { 361 PhoneAccount callManagerPA = makeQuickAccount(id, capability); 362 when(mMockAccountRegistrar.getSimCallManagerOfCurrentUser()).thenReturn( 363 callManagerPA.getAccountHandle()); 364 givePhoneAccountBindPermission(callManagerPA.getAccountHandle()); 365 when(mMockAccountRegistrar.getPhoneAccountUnchecked( 366 callManagerPA.getAccountHandle())).thenReturn(callManagerPA); 367 return callManagerPA; 368 } 369 370 private static ComponentName makeQuickConnectionServiceComponentName() { 371 return new ComponentName(TEST_PACKAGE, TEST_CLASS); 372 } 373 374 private ConnectionServiceWrapper makeConnectionServiceWrapper() { 375 ConnectionServiceWrapper wrapper = mock(ConnectionServiceWrapper.class); 376 when(mMockConnectionServiceRepository.getService( 377 eq(makeQuickConnectionServiceComponentName()), 378 eq(Binder.getCallingUserHandle()))).thenReturn(wrapper); 379 return wrapper; 380 } 381 382 private static PhoneAccountHandle makeQuickAccountHandle(String id) { 383 return new PhoneAccountHandle(makeQuickConnectionServiceComponentName(), id, 384 Binder.getCallingUserHandle()); 385 } 386 387 private PhoneAccount.Builder makeQuickAccountBuilder(String id, int idx) { 388 return new PhoneAccount.Builder(makeQuickAccountHandle(id), "label" + idx); 389 } 390 391 private PhoneAccount makeQuickAccount(String id, int idx) { 392 return makeQuickAccountBuilder(id, idx) 393 .setAddress(Uri.parse("http://foo.com/" + idx)) 394 .setSubscriptionAddress(Uri.parse("tel:555-000" + idx)) 395 .setCapabilities(idx) 396 .setIcon(Icon.createWithResource( 397 "com.android.server.telecom.tests", R.drawable.stat_sys_phone_call)) 398 .setShortDescription("desc" + idx) 399 .setIsEnabled(true) 400 .build(); 401 } 402 }