NewOutgoingCallIntentBroadcasterTest.java revision c9cf54407720d32fdb1b69e0254657a6061b9f56
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.Manifest;
20import android.app.Activity;
21import android.app.AppOpsManager;
22import android.content.BroadcastReceiver;
23import android.content.ComponentName;
24import android.content.Context;
25import android.content.Intent;
26import android.net.Uri;
27import android.os.Bundle;
28import android.os.Handler;
29import android.os.UserHandle;
30import android.telecom.GatewayInfo;
31import android.telecom.TelecomManager;
32import android.telecom.VideoProfile;
33import android.telephony.DisconnectCause;
34import android.test.suitebuilder.annotation.SmallTest;
35
36import com.android.server.telecom.Call;
37import com.android.server.telecom.CallsManager;
38import com.android.server.telecom.NewOutgoingCallIntentBroadcaster;
39import com.android.server.telecom.PhoneNumberUtilsAdapter;
40import com.android.server.telecom.PhoneNumberUtilsAdapterImpl;
41import com.android.server.telecom.TelecomSystem;
42
43import org.mockito.ArgumentCaptor;
44import org.mockito.Mock;
45
46import static org.mockito.Matchers.any;
47import static org.mockito.Matchers.anyBoolean;
48import static org.mockito.Matchers.anyInt;
49import static org.mockito.Matchers.anyString;
50import static org.mockito.Matchers.eq;
51import static org.mockito.Matchers.isNotNull;
52import static org.mockito.Matchers.isNull;
53import static org.mockito.Mockito.doReturn;
54import static org.mockito.Mockito.never;
55import static org.mockito.Mockito.spy;
56import static org.mockito.Mockito.verify;
57import static org.mockito.Mockito.when;
58
59public class NewOutgoingCallIntentBroadcasterTest extends TelecomTestCase {
60    private static class ReceiverIntentPair {
61        public BroadcastReceiver receiver;
62        public Intent intent;
63
64        public ReceiverIntentPair(BroadcastReceiver receiver, Intent intent) {
65            this.receiver = receiver;
66            this.intent = intent;
67        }
68    }
69
70    @Mock private CallsManager mCallsManager;
71    @Mock private Call mCall;
72
73    private PhoneNumberUtilsAdapter mPhoneNumberUtilsAdapterSpy;
74
75    @Override
76    public void setUp() throws Exception {
77        super.setUp();
78        mContext = mComponentContextFixture.getTestDouble().getApplicationContext();
79        mPhoneNumberUtilsAdapterSpy = spy(new PhoneNumberUtilsAdapterImpl());
80        when(mCall.getInitiatingUser()).thenReturn(UserHandle.CURRENT);
81        when(mCallsManager.getLock()).thenReturn(new TelecomSystem.SyncRoot() { });
82    }
83
84    @SmallTest
85    public void testNullHandle() {
86        Intent intent = new Intent(Intent.ACTION_CALL, null);
87        int result = processIntent(intent, true);
88        assertEquals(DisconnectCause.INVALID_NUMBER, result);
89        verifyNoBroadcastSent();
90        verifyNoCallPlaced();
91    }
92
93    @SmallTest
94    public void testVoicemailCall() {
95        String voicemailNumber = "voicemail:18005551234";
96        Intent intent = new Intent(Intent.ACTION_CALL, Uri.parse(voicemailNumber));
97        intent.putExtra(TelecomManager.EXTRA_START_CALL_WITH_SPEAKERPHONE, true);
98
99        int result = processIntent(intent, true);
100
101        assertEquals(DisconnectCause.NOT_DISCONNECTED, result);
102        verify(mCallsManager).placeOutgoingCall(eq(mCall), eq(Uri.parse(voicemailNumber)),
103                any(GatewayInfo.class), eq(true), eq(VideoProfile.STATE_AUDIO_ONLY));
104    }
105
106    @SmallTest
107    public void testVoicemailCallWithBadAction() {
108        badCallActionHelper(Uri.parse("voicemail:18005551234"), DisconnectCause.OUTGOING_CANCELED);
109    }
110
111    @SmallTest
112    public void testTelCallWithBadCallAction() {
113        badCallActionHelper(Uri.parse("tel:6505551234"), DisconnectCause.INVALID_NUMBER);
114    }
115
116    @SmallTest
117    public void testSipCallWithBadCallAction() {
118        badCallActionHelper(Uri.parse("sip:testuser@testsite.com"), DisconnectCause.INVALID_NUMBER);
119    }
120
121    private void badCallActionHelper(Uri handle, int expectedCode) {
122        Intent intent = new Intent(Intent.ACTION_ALARM_CHANGED, handle);
123
124        int result = processIntent(intent, true);
125
126        assertEquals(expectedCode, result);
127        verifyNoBroadcastSent();
128        verifyNoCallPlaced();
129    }
130
131    @SmallTest
132    public void testAlreadyDisconnectedCall() {
133        Uri handle = Uri.parse("tel:6505551234");
134        doReturn(true).when(mCall).isDisconnected();
135        Intent callIntent = buildIntent(handle, Intent.ACTION_CALL, null);
136        ReceiverIntentPair result = regularCallTestHelper(callIntent, null);
137
138        result.receiver.setResultData(
139                result.intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER));
140
141        result.receiver.onReceive(mContext, result.intent);
142        verifyNoCallPlaced();
143    }
144
145    @SmallTest
146    public void testNoNumberSupplied() {
147        Uri handle = Uri.parse("tel:");
148        Intent intent = new Intent(Intent.ACTION_CALL, handle);
149
150        int result = processIntent(intent, true);
151
152        assertEquals(DisconnectCause.NO_PHONE_NUMBER_SUPPLIED, result);
153        verifyNoBroadcastSent();
154        verifyNoCallPlaced();
155    }
156
157    @SmallTest
158    public void testEmergencyCallWithNonDefaultDialer() {
159        Uri handle = Uri.parse("tel:6505551911");
160        doReturn(true).when(mPhoneNumberUtilsAdapterSpy).isPotentialLocalEmergencyNumber(
161                any(Context.class), eq(handle.getSchemeSpecificPart()));
162        Intent intent = new Intent(Intent.ACTION_CALL, handle);
163
164        String ui_package_string = "sample_string_1";
165        String dialer_default_class_string = "sample_string_2";
166        mComponentContextFixture.putResource(R.string.ui_default_package, ui_package_string);
167        mComponentContextFixture.putResource(R.string.dialer_default_class,
168                dialer_default_class_string);
169
170        int result = processIntent(intent, false);
171
172        assertEquals(DisconnectCause.OUTGOING_CANCELED, result);
173        verifyNoBroadcastSent();
174        verifyNoCallPlaced();
175
176        ArgumentCaptor<Intent> dialerIntentCaptor = ArgumentCaptor.forClass(Intent.class);
177        verify(mContext).startActivityAsUser(dialerIntentCaptor.capture(), any(UserHandle.class));
178        Intent dialerIntent = dialerIntentCaptor.getValue();
179        assertEquals(new ComponentName(ui_package_string, dialer_default_class_string),
180                dialerIntent.getComponent());
181        assertEquals(Intent.ACTION_DIAL, dialerIntent.getAction());
182        assertEquals(handle, dialerIntent.getData());
183        assertEquals(Intent.FLAG_ACTIVITY_NEW_TASK, dialerIntent.getFlags());
184    }
185
186    @SmallTest
187    public void testActionCallEmergencyCall() {
188        Uri handle = Uri.parse("tel:6505551911");
189        Intent intent = buildIntent(handle, Intent.ACTION_CALL, null);
190        emergencyCallTestHelper(intent, null);
191    }
192
193    @SmallTest
194    public void testActionEmergencyWithEmergencyNumber() {
195        Uri handle = Uri.parse("tel:6505551911");
196        Intent intent = buildIntent(handle, Intent.ACTION_CALL_EMERGENCY, null);
197        emergencyCallTestHelper(intent, null);
198    }
199
200    @SmallTest
201    public void testActionPrivCallWithEmergencyNumber() {
202        Uri handle = Uri.parse("tel:6505551911");
203        Intent intent = buildIntent(handle, Intent.ACTION_CALL_PRIVILEGED, null);
204        emergencyCallTestHelper(intent, null);
205    }
206
207    @SmallTest
208    public void testEmergencyCallWithGatewayExtras() {
209        Uri handle = Uri.parse("tel:6505551911");
210        Bundle gatewayExtras = new Bundle();
211        gatewayExtras.putString(NewOutgoingCallIntentBroadcaster.EXTRA_GATEWAY_PROVIDER_PACKAGE,
212                "sample1");
213        gatewayExtras.putString(NewOutgoingCallIntentBroadcaster.EXTRA_GATEWAY_URI, "sample2");
214
215        Intent intent = buildIntent(handle, Intent.ACTION_CALL, gatewayExtras);
216        emergencyCallTestHelper(intent, gatewayExtras);
217    }
218
219    @SmallTest
220    public void testActionEmergencyWithNonEmergencyNumber() {
221        Uri handle = Uri.parse("tel:6505551911");
222        doReturn(false).when(mPhoneNumberUtilsAdapterSpy).isPotentialLocalEmergencyNumber(
223                any(Context.class), eq(handle.getSchemeSpecificPart()));
224        Intent intent = new Intent(Intent.ACTION_CALL_EMERGENCY, handle);
225        int result = processIntent(intent, true);
226
227        assertEquals(DisconnectCause.OUTGOING_CANCELED, result);
228        verifyNoCallPlaced();
229        verifyNoBroadcastSent();
230    }
231
232    private void emergencyCallTestHelper(Intent intent, Bundle expectedAdditionalExtras) {
233        Uri handle = intent.getData();
234        int videoState = VideoProfile.STATE_BIDIRECTIONAL;
235        boolean isSpeakerphoneOn = true;
236        doReturn(true).when(mPhoneNumberUtilsAdapterSpy).isPotentialLocalEmergencyNumber(
237                any(Context.class), eq(handle.getSchemeSpecificPart()));
238        intent.putExtra(TelecomManager.EXTRA_START_CALL_WITH_SPEAKERPHONE, isSpeakerphoneOn);
239        intent.putExtra(TelecomManager.EXTRA_START_CALL_WITH_VIDEO_STATE, videoState);
240        int result = processIntent(intent, true);
241
242        assertEquals(DisconnectCause.NOT_DISCONNECTED, result);
243        verify(mCallsManager).placeOutgoingCall(eq(mCall), eq(handle), isNull(GatewayInfo.class),
244                eq(isSpeakerphoneOn), eq(videoState));
245
246        Bundle expectedExtras = createNumberExtras(handle.getSchemeSpecificPart());
247        if (expectedAdditionalExtras != null) {
248            expectedExtras.putAll(expectedAdditionalExtras);
249        }
250        BroadcastReceiver receiver = verifyBroadcastSent(handle.getSchemeSpecificPart(),
251                expectedExtras).receiver;
252        assertNull(receiver);
253    }
254
255    @SmallTest
256    public void testUnmodifiedRegularCall() {
257        Uri handle = Uri.parse("tel:6505551234");
258        Intent callIntent = buildIntent(handle, Intent.ACTION_CALL, null);
259        ReceiverIntentPair result = regularCallTestHelper(callIntent, null);
260
261        result.receiver.setResultData(
262                result.intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER));
263
264        result.receiver.onReceive(mContext, result.intent);
265
266        verify(mCallsManager).placeOutgoingCall(eq(mCall), eq(handle), isNull(GatewayInfo.class),
267                eq(true), eq(VideoProfile.STATE_BIDIRECTIONAL));
268    }
269
270    @SmallTest
271    public void testUnmodifiedSipCall() {
272        Uri handle = Uri.parse("sip:test@test.com");
273        Intent callIntent = buildIntent(handle, Intent.ACTION_CALL, null);
274        ReceiverIntentPair result = regularCallTestHelper(callIntent, null);
275
276        result.receiver.setResultData(
277                result.intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER));
278
279        result.receiver.onReceive(mContext, result.intent);
280
281        Uri encHandle = Uri.fromParts(handle.getScheme(),
282                handle.getSchemeSpecificPart(), null);
283        verify(mCallsManager).placeOutgoingCall(eq(mCall), eq(encHandle), isNull(GatewayInfo.class),
284                eq(true), eq(VideoProfile.STATE_BIDIRECTIONAL));
285    }
286
287    @SmallTest
288    public void testCallWithGatewayInfo() {
289        Uri handle = Uri.parse("tel:6505551234");
290        Intent callIntent = buildIntent(handle, Intent.ACTION_CALL, null);
291
292        callIntent.putExtra(NewOutgoingCallIntentBroadcaster
293                        .EXTRA_GATEWAY_PROVIDER_PACKAGE, "sample1");
294        callIntent.putExtra(NewOutgoingCallIntentBroadcaster.EXTRA_GATEWAY_URI, "sample2");
295        ReceiverIntentPair result = regularCallTestHelper(callIntent, callIntent.getExtras());
296
297        result.receiver.setResultData(
298                result.intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER));
299
300        result.receiver.onReceive(mContext, result.intent);
301
302        verify(mCallsManager).placeOutgoingCall(eq(mCall), eq(handle),
303                isNotNull(GatewayInfo.class), eq(true), eq(VideoProfile.STATE_BIDIRECTIONAL));
304    }
305
306    @SmallTest
307    public void testCallNumberModifiedToNull() {
308        Uri handle = Uri.parse("tel:6505551234");
309        Intent callIntent = buildIntent(handle, Intent.ACTION_CALL, null);
310        ReceiverIntentPair result = regularCallTestHelper(callIntent, null);
311
312        result.receiver.setResultData(null);
313
314        result.receiver.onReceive(mContext, result.intent);
315        verifyNoCallPlaced();
316        verify(mCall).disconnect(true);
317    }
318
319    @SmallTest
320    public void testCallModifiedToEmergency() {
321        Uri handle = Uri.parse("tel:6505551234");
322        Intent callIntent = buildIntent(handle, Intent.ACTION_CALL, null);
323        ReceiverIntentPair result = regularCallTestHelper(callIntent, null);
324
325        String newEmergencyNumber = "1234567890";
326        result.receiver.setResultData(newEmergencyNumber);
327
328        doReturn(true).when(mPhoneNumberUtilsAdapterSpy).isPotentialLocalEmergencyNumber(
329                any(Context.class), eq(newEmergencyNumber));
330        result.receiver.onReceive(mContext, result.intent);
331        verify(mCall).disconnect(true);
332    }
333
334    private ReceiverIntentPair regularCallTestHelper(Intent intent,
335            Bundle expectedAdditionalExtras) {
336        Uri handle = intent.getData();
337        int videoState = VideoProfile.STATE_BIDIRECTIONAL;
338        boolean isSpeakerphoneOn = true;
339        intent.putExtra(TelecomManager.EXTRA_START_CALL_WITH_SPEAKERPHONE, isSpeakerphoneOn);
340        intent.putExtra(TelecomManager.EXTRA_START_CALL_WITH_VIDEO_STATE, videoState);
341
342        int result = processIntent(intent, true);
343
344        assertEquals(DisconnectCause.NOT_DISCONNECTED, result);
345        Bundle expectedExtras = createNumberExtras(handle.getSchemeSpecificPart());
346        if (expectedAdditionalExtras != null) {
347            expectedExtras.putAll(expectedAdditionalExtras);
348        }
349        return verifyBroadcastSent(handle.getSchemeSpecificPart(), expectedExtras);
350    }
351
352    private Intent buildIntent(Uri handle, String action, Bundle extras) {
353        Intent i = new Intent(action, handle);
354        if (extras != null) {
355            i.putExtras(extras);
356        }
357        return i;
358    }
359
360    private int processIntent(Intent intent,
361            boolean isDefaultPhoneApp) {
362        NewOutgoingCallIntentBroadcaster b = new NewOutgoingCallIntentBroadcaster(
363                mContext, mCallsManager, mCall, intent, mPhoneNumberUtilsAdapterSpy,
364                isDefaultPhoneApp);
365        return b.processIntent();
366    }
367
368    private ReceiverIntentPair verifyBroadcastSent(String number, Bundle expectedExtras) {
369        ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
370        ArgumentCaptor<BroadcastReceiver> receiverCaptor =
371                ArgumentCaptor.forClass(BroadcastReceiver.class);
372
373        verify(mContext).sendOrderedBroadcastAsUser(
374                intentCaptor.capture(),
375                eq(UserHandle.CURRENT),
376                eq(Manifest.permission.PROCESS_OUTGOING_CALLS),
377                eq(AppOpsManager.OP_PROCESS_OUTGOING_CALLS),
378                receiverCaptor.capture(),
379                isNull(Handler.class),
380                eq(Activity.RESULT_OK),
381                eq(number),
382                isNull(Bundle.class));
383
384        Intent capturedIntent = intentCaptor.getValue();
385        assertEquals(Intent.ACTION_NEW_OUTGOING_CALL, capturedIntent.getAction());
386        assertEquals(Intent.FLAG_RECEIVER_FOREGROUND, capturedIntent.getFlags());
387        assertTrue(areBundlesEqual(expectedExtras, capturedIntent.getExtras()));
388
389        BroadcastReceiver receiver = receiverCaptor.getValue();
390        if (receiver != null) {
391            receiver.setPendingResult(
392                    new BroadcastReceiver.PendingResult(0, "", null, 0, true, false, null, 0, 0));
393        }
394
395        return new ReceiverIntentPair(receiver, capturedIntent);
396    }
397
398    private Bundle createNumberExtras(String number) {
399        Bundle b = new Bundle();
400        b.putString(Intent.EXTRA_PHONE_NUMBER, number);
401        return b;
402    }
403
404    private void verifyNoCallPlaced() {
405        verify(mCallsManager, never()).placeOutgoingCall(any(Call.class), any(Uri.class),
406                any(GatewayInfo.class), anyBoolean(), anyInt());
407    }
408
409    private void verifyNoBroadcastSent() {
410        verify(mContext, never()).sendOrderedBroadcastAsUser(
411                any(Intent.class),
412                any(UserHandle.class),
413                anyString(),
414                anyInt(),
415                any(BroadcastReceiver.class),
416                any(Handler.class),
417                anyInt(),
418                anyString(),
419                any(Bundle.class));
420    }
421
422    private static boolean areBundlesEqual(Bundle b1, Bundle b2) {
423        for (String key1 : b1.keySet()) {
424            if (!b1.get(key1).equals(b2.get(key1))) {
425                return false;
426            }
427        }
428
429        for (String key2 : b2.keySet()) {
430            if (!b2.get(key2).equals(b1.get(key2))) {
431                return false;
432            }
433        }
434        return true;
435    }
436}
437