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