TelecomSystemTest.java revision b63b57e2c35c4769e756f47131c7ebbc0af42c59
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 com.android.internal.telecom.IInCallAdapter;
20import com.android.server.telecom.CallsManager;
21import com.android.server.telecom.HeadsetMediaButton;
22import com.android.server.telecom.HeadsetMediaButtonFactory;
23import com.android.server.telecom.InCallWakeLockController;
24import com.android.server.telecom.InCallWakeLockControllerFactory;
25import com.android.server.telecom.MissedCallNotifier;
26import com.android.server.telecom.ProximitySensorManager;
27import com.android.server.telecom.ProximitySensorManagerFactory;
28import com.android.server.telecom.TelecomSystem;
29
30import org.mockito.ArgumentCaptor;
31import org.mockito.Mock;
32
33import android.annotation.TargetApi;
34import android.content.BroadcastReceiver;
35import android.content.ComponentName;
36import android.content.Context;
37import android.content.Intent;
38import android.net.Uri;
39import android.os.Bundle;
40import android.os.Handler;
41import android.os.UserHandle;
42import android.telecom.CallState;
43import android.telecom.ConnectionRequest;
44import android.telecom.DisconnectCause;
45import android.telecom.ParcelableCall;
46import android.telecom.PhoneAccount;
47import android.telecom.PhoneAccountHandle;
48import android.telecom.TelecomManager;
49import android.telephony.TelephonyManager;
50
51import static org.mockito.Matchers.anyBoolean;
52import static org.mockito.Matchers.anyInt;
53import static org.mockito.Mockito.any;
54import static org.mockito.Mockito.anyString;
55import static org.mockito.Mockito.eq;
56import static org.mockito.Mockito.mock;
57import static org.mockito.Mockito.timeout;
58import static org.mockito.Mockito.verify;
59import static org.mockito.Mockito.when;
60
61public class TelecomSystemTest extends TelecomTestCase {
62
63    static final int TEST_TIMEOUT = 1000;  // milliseconds
64
65    @Mock MissedCallNotifier mMissedCallNotifier;
66    @Mock HeadsetMediaButton mHeadsetMediaButton;
67    @Mock ProximitySensorManager mProximitySensorManager;
68    @Mock InCallWakeLockController mInCallWakeLockController;
69
70    final ComponentName mInCallServiceComponentNameX =
71            new ComponentName(
72                    "incall-service-package-X",
73                    "incall-service-class-X");
74    final ComponentName mInCallServiceComponentNameY =
75            new ComponentName(
76                    "incall-service-package-Y",
77                    "incall-service-class-Y");
78
79    InCallServiceFixture mInCallServiceFixtureX;
80    InCallServiceFixture mInCallServiceFixtureY;
81
82    final ComponentName mConnectionServiceComponentNameA =
83            new ComponentName(
84                    "connection-service-package-A",
85                    "connection-service-class-A");
86    final ComponentName mConnectionServiceComponentNameB =
87            new ComponentName(
88                    "connection-service-package-B",
89                    "connection-service-class-B");
90
91    final PhoneAccount mPhoneAccountA0 =
92            PhoneAccount.builder(
93                    new PhoneAccountHandle(
94                            mConnectionServiceComponentNameA,
95                            "id A 0"),
96                    "Phone account service A ID 0")
97                    .addSupportedUriScheme("tel")
98                    .setCapabilities(
99                            PhoneAccount.CAPABILITY_CALL_PROVIDER |
100                            PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION)
101                    .build();
102    final PhoneAccount mPhoneAccountA1 =
103            PhoneAccount.builder(
104                    new PhoneAccountHandle(
105                            mConnectionServiceComponentNameA,
106                            "id A 1"),
107                    "Phone account service A ID 1")
108                    .addSupportedUriScheme("tel")
109                    .setCapabilities(
110                            PhoneAccount.CAPABILITY_CALL_PROVIDER |
111                            PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION)
112                    .build();
113    final PhoneAccount mPhoneAccountB0 =
114            PhoneAccount.builder(
115                    new PhoneAccountHandle(
116                            mConnectionServiceComponentNameA,
117                            "id B 0"),
118                    "Phone account service B ID 0")
119                    .addSupportedUriScheme("tel")
120                    .setCapabilities(
121                            PhoneAccount.CAPABILITY_CALL_PROVIDER |
122                            PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION)
123                    .build();
124
125    ConnectionServiceFixture mConnectionServiceFixtureA;
126    ConnectionServiceFixture mConnectionServiceFixtureB;
127
128    TelecomSystem mTelecomSystem;
129
130    @Override
131    public void setUp() throws Exception {
132        super.setUp();
133
134        // First set up information about the In-Call services in the mock Context, since
135        // Telecom will search for these as soon as it is instantiated
136        setupInCallServices();
137
138        // Next, create the TelecomSystem, our system under test
139        setupTelecomSystem();
140
141        // Finally, register the ConnectionServices with the PhoneAccountRegistrar of the
142        // now-running TelecomSystem
143        setupConnectionServices();
144    }
145
146    @Override
147    public void tearDown() throws Exception {
148        mTelecomSystem = null;
149        super.tearDown();
150    }
151
152    private void setupTelecomSystem() throws Exception {
153        HeadsetMediaButtonFactory headsetMediaButtonFactory =
154                mock(HeadsetMediaButtonFactory.class);
155        ProximitySensorManagerFactory proximitySensorManagerFactory =
156                mock(ProximitySensorManagerFactory.class);
157        InCallWakeLockControllerFactory inCallWakeLockControllerFactory =
158                mock(InCallWakeLockControllerFactory.class);
159
160        when(headsetMediaButtonFactory.create(
161                any(Context.class),
162                any(CallsManager.class)))
163                .thenReturn(mHeadsetMediaButton);
164        when(proximitySensorManagerFactory.create(
165                any(Context.class),
166                any(CallsManager.class)))
167                .thenReturn(mProximitySensorManager);
168        when(inCallWakeLockControllerFactory.create(
169                any(Context.class),
170                any(CallsManager.class)))
171                .thenReturn(mInCallWakeLockController);
172
173        mTelecomSystem = new TelecomSystem(
174                mComponentContextFixture.getTestDouble(),
175                mMissedCallNotifier,
176                headsetMediaButtonFactory,
177                proximitySensorManagerFactory,
178                inCallWakeLockControllerFactory);
179
180        verify(headsetMediaButtonFactory).create(
181                eq(mComponentContextFixture.getTestDouble().getApplicationContext()),
182                any(CallsManager.class));
183        verify(proximitySensorManagerFactory).create(
184                eq(mComponentContextFixture.getTestDouble().getApplicationContext()),
185                any(CallsManager.class));
186        verify(inCallWakeLockControllerFactory).create(
187                eq(mComponentContextFixture.getTestDouble().getApplicationContext()),
188                any(CallsManager.class));
189    }
190
191    private void setupConnectionServices() throws Exception {
192        mConnectionServiceFixtureA = new ConnectionServiceFixture();
193        mConnectionServiceFixtureB = new ConnectionServiceFixture();
194
195        mComponentContextFixture.addConnectionService(
196                mConnectionServiceComponentNameA,
197                mConnectionServiceFixtureA.getTestDouble());
198        mComponentContextFixture.addConnectionService(
199                mConnectionServiceComponentNameB,
200                mConnectionServiceFixtureB.getTestDouble());
201
202        mTelecomSystem.getPhoneAccountRegistrar().registerPhoneAccount(mPhoneAccountA0);
203        mTelecomSystem.getPhoneAccountRegistrar().registerPhoneAccount(mPhoneAccountA1);
204        mTelecomSystem.getPhoneAccountRegistrar().registerPhoneAccount(mPhoneAccountB0);
205    }
206
207    private void setupInCallServices() throws Exception {
208        mComponentContextFixture.putResource(
209                com.android.server.telecom.R.string.ui_default_package,
210                mInCallServiceComponentNameX.getPackageName());
211        mComponentContextFixture.putResource(
212                com.android.server.telecom.R.string.incall_default_class,
213                mInCallServiceComponentNameX.getClassName());
214
215        mInCallServiceFixtureX = new InCallServiceFixture();
216        mInCallServiceFixtureY = new InCallServiceFixture();
217
218        mComponentContextFixture.addInCallService(
219                mInCallServiceComponentNameX,
220                mInCallServiceFixtureX.getTestDouble());
221        mComponentContextFixture.addInCallService(
222                mInCallServiceComponentNameY,
223                mInCallServiceFixtureY.getTestDouble());
224    }
225
226    private String startOutgoingPhoneCall(
227            String number,
228            PhoneAccountHandle phoneAccountHandle,
229            ConnectionServiceFixture connectionServiceFixture) throws Exception {
230        Intent actionCallIntent = new Intent();
231        actionCallIntent.setData(Uri.parse("tel:" + number));
232        actionCallIntent.putExtra(Intent.EXTRA_PHONE_NUMBER, number);
233        actionCallIntent.setAction(Intent.ACTION_CALL);
234        if (phoneAccountHandle != null) {
235            actionCallIntent.putExtra(
236                    TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE,
237                    phoneAccountHandle);
238        }
239
240        mTelecomSystem.getCallIntentProcessor().processIntent(actionCallIntent);
241
242        ArgumentCaptor<Intent> newOutgoingCallIntent =
243                ArgumentCaptor.forClass(Intent.class);
244        ArgumentCaptor<BroadcastReceiver> newOutgoingCallReceiver =
245                ArgumentCaptor.forClass(BroadcastReceiver.class);
246
247        verify(mComponentContextFixture.getTestDouble().getApplicationContext())
248                .sendOrderedBroadcastAsUser(
249                        newOutgoingCallIntent.capture(),
250                        any(UserHandle.class),
251                        anyString(),
252                        newOutgoingCallReceiver.capture(),
253                        any(Handler.class),
254                        anyInt(),
255                        anyString(),
256                        any(Bundle.class));
257
258        assertNotNull(mInCallServiceFixtureX.mInCallAdapter);
259        assertNotNull(mInCallServiceFixtureY.mInCallAdapter);
260
261        // Pass on the new outgoing call Intent
262        // Set a dummy PendingResult so the BroadcastReceiver agrees to accept onReceive()
263        newOutgoingCallReceiver.getValue().setPendingResult(
264                new BroadcastReceiver.PendingResult(0, "", null, 0, true, false, null, 0));
265        newOutgoingCallReceiver.getValue().setResultData(
266                newOutgoingCallIntent.getValue().getStringExtra(Intent.EXTRA_PHONE_NUMBER));
267        newOutgoingCallReceiver.getValue().onReceive(
268                mComponentContextFixture.getTestDouble(),
269                newOutgoingCallIntent.getValue());
270
271        verify(connectionServiceFixture.getTestDouble()).createConnection(
272                eq(phoneAccountHandle),
273                anyString(),
274                any(ConnectionRequest.class),
275                anyBoolean(),
276                anyBoolean());
277
278        String id = connectionServiceFixture.mLatestConnectionId;
279
280        connectionServiceFixture.sendHandleCreateConnectionComplete(id);
281
282        return id;
283    }
284
285    private String startIncomingPhoneCall(
286            String number,
287            PhoneAccountHandle phoneAccountHandle,
288            ConnectionServiceFixture connectionServiceFixture) throws Exception {
289        Bundle extras = new Bundle();
290        extras.putParcelable(
291                TelephonyManager.EXTRA_INCOMING_NUMBER,
292                Uri.fromParts(PhoneAccount.SCHEME_TEL, number, null));
293        mTelecomSystem.getTelecomServiceImpl().getBinder()
294                .addNewIncomingCall(phoneAccountHandle, extras);
295
296        verify(connectionServiceFixture.getTestDouble()).createConnection(
297                any(PhoneAccountHandle.class),
298                anyString(),
299                any(ConnectionRequest.class),
300                eq(true),
301                eq(false));
302
303        String id = connectionServiceFixture.mLatestConnectionId;
304
305        connectionServiceFixture.sendHandleCreateConnectionComplete(id);
306        connectionServiceFixture.sendSetRinging(id);
307
308        // For the case of incoming calls, Telecom connecting the InCall services and adding the
309        // Call is triggered by the async completion of the CallerInfoAsyncQuery. Once the Call
310        // is added, future interactions as triggered by the ConnectionService, through the various
311        // test fixtures, will be synchronous.
312
313        verify(
314                mInCallServiceFixtureX.getTestDouble(),
315                timeout(TEST_TIMEOUT))
316                .setInCallAdapter(
317                        any(IInCallAdapter.class));
318        verify(
319                mInCallServiceFixtureY.getTestDouble(),
320                timeout(TEST_TIMEOUT))
321                .setInCallAdapter(
322                        any(IInCallAdapter.class));
323
324        assertNotNull(mInCallServiceFixtureX.mInCallAdapter);
325        assertNotNull(mInCallServiceFixtureY.mInCallAdapter);
326
327        verify(
328                mInCallServiceFixtureX.getTestDouble(),
329                timeout(TEST_TIMEOUT))
330                .addCall(
331                        any(ParcelableCall.class));
332        verify(
333                mInCallServiceFixtureY.getTestDouble(),
334                timeout(TEST_TIMEOUT))
335                .addCall(
336                        any(ParcelableCall.class));
337
338        return id;
339    }
340
341    // A simple outgoing call, verifying that the appropriate connection service is contacted,
342    // the proper lifecycle is followed, and both In-Call Services are updated correctly.
343    public void testSingleOutgoingCall() throws Exception {
344        String connectionId = startOutgoingPhoneCall(
345                "650-555-1212",
346                mPhoneAccountA0.getAccountHandle(),
347                mConnectionServiceFixtureA);
348
349        assertEquals(1, mConnectionServiceFixtureA.mConnectionServiceAdapters.size());
350        assertEquals(1, mConnectionServiceFixtureA.mConnectionById.size());
351
352        mConnectionServiceFixtureA.sendSetDialing(connectionId);
353
354        assertEquals(1, mInCallServiceFixtureX.mCallById.size());
355        String callId = mInCallServiceFixtureX.mLatestCallId;
356
357        assertEquals(CallState.DIALING, mInCallServiceFixtureX.getCall(callId).getState());
358        assertEquals(CallState.DIALING, mInCallServiceFixtureY.getCall(callId).getState());
359
360        mConnectionServiceFixtureA.sendSetActive(connectionId);
361        assertEquals(CallState.ACTIVE, mInCallServiceFixtureX.getCall(callId).getState());
362        assertEquals(CallState.ACTIVE, mInCallServiceFixtureY.getCall(callId).getState());
363
364        mInCallServiceFixtureX.mInCallAdapter.disconnectCall(callId);;
365        assertEquals(CallState.ACTIVE, mInCallServiceFixtureX.getCall(callId).getState());
366        assertEquals(CallState.ACTIVE, mInCallServiceFixtureY.getCall(callId).getState());
367
368        mConnectionServiceFixtureA.sendSetDisconnected(connectionId, DisconnectCause.LOCAL);
369        assertEquals(CallState.DISCONNECTED, mInCallServiceFixtureX.getCall(callId).getState());
370        assertEquals(CallState.DISCONNECTED, mInCallServiceFixtureY.getCall(callId).getState());
371    }
372
373    // A simple incoming call, similar in scope to the previous test
374    public void testSingleIncomingCall() throws Exception {
375        String connectionId = startIncomingPhoneCall(
376                "650-555-1212",
377                mPhoneAccountA0.getAccountHandle(),
378                mConnectionServiceFixtureA);
379
380        assertEquals(1, mConnectionServiceFixtureA.mConnectionServiceAdapters.size());
381        assertEquals(1, mConnectionServiceFixtureA.mConnectionById.size());
382
383        assertEquals(1, mInCallServiceFixtureX.mCallById.size());
384        String callId = mInCallServiceFixtureX.mLatestCallId;
385
386        assertEquals(CallState.RINGING, mInCallServiceFixtureX.getCall(callId).getState());
387        assertEquals(CallState.RINGING, mInCallServiceFixtureY.getCall(callId).getState());
388
389        mConnectionServiceFixtureA.sendSetActive(connectionId);
390        assertEquals(CallState.ACTIVE, mInCallServiceFixtureX.getCall(callId).getState());
391        assertEquals(CallState.ACTIVE, mInCallServiceFixtureY.getCall(callId).getState());
392
393        mInCallServiceFixtureX.mInCallAdapter.disconnectCall(callId);;
394        assertEquals(CallState.ACTIVE, mInCallServiceFixtureX.getCall(callId).getState());
395        assertEquals(CallState.ACTIVE, mInCallServiceFixtureY.getCall(callId).getState());
396
397        mConnectionServiceFixtureA.sendSetDisconnected(connectionId, DisconnectCause.LOCAL);
398        assertEquals(CallState.DISCONNECTED, mInCallServiceFixtureX.getCall(callId).getState());
399        assertEquals(CallState.DISCONNECTED, mInCallServiceFixtureY.getCall(callId).getState());
400    }
401}
402