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