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