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