• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2019 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 
17 package com.android.server.telecom.tests;
18 
19 import static org.junit.Assert.assertEquals;
20 import static org.junit.Assert.assertFalse;
21 import static org.junit.Assert.assertNotNull;
22 import static org.junit.Assert.assertNull;
23 import static org.junit.Assert.assertTrue;
24 import static org.mockito.ArgumentMatchers.any;
25 import static org.mockito.ArgumentMatchers.anyBoolean;
26 import static org.mockito.ArgumentMatchers.argThat;
27 import static org.mockito.ArgumentMatchers.eq;
28 import static org.mockito.Mockito.doReturn;
29 import static org.mockito.Mockito.mock;
30 import static org.mockito.Mockito.never;
31 import static org.mockito.Mockito.times;
32 import static org.mockito.Mockito.verify;
33 import static org.mockito.Mockito.when;
34 
35 import android.content.ComponentName;
36 import android.content.Intent;
37 import android.content.pm.PackageManager;
38 import android.content.res.Resources;
39 import android.graphics.Bitmap;
40 import android.graphics.drawable.ColorDrawable;
41 import android.net.Uri;
42 import android.os.Bundle;
43 import android.os.PersistableBundle;
44 import android.os.UserHandle;
45 import android.telecom.CallAttributes;
46 import android.telecom.CallEndpoint;
47 import android.telecom.CallerInfo;
48 import android.telecom.Connection;
49 import android.telecom.DisconnectCause;
50 import android.telecom.ParcelableConference;
51 import android.telecom.ParcelableConnection;
52 import android.telecom.PhoneAccount;
53 import android.telecom.PhoneAccountHandle;
54 import android.telecom.StatusHints;
55 import android.telecom.TelecomManager;
56 import android.telecom.VideoProfile;
57 import android.telephony.CallQuality;
58 
59 import androidx.test.ext.junit.runners.AndroidJUnit4;
60 import androidx.test.filters.SmallTest;
61 
62 import com.android.server.telecom.CachedAvailableEndpointsChange;
63 import com.android.server.telecom.CachedCallEventQueue;
64 import com.android.server.telecom.CachedCurrentEndpointChange;
65 import com.android.server.telecom.CachedMuteStateChange;
66 import com.android.server.telecom.Call;
67 import com.android.server.telecom.CallIdMapper;
68 import com.android.server.telecom.CallState;
69 import com.android.server.telecom.CallerInfoLookupHelper;
70 import com.android.server.telecom.CallsManager;
71 import com.android.server.telecom.ClockProxy;
72 import com.android.server.telecom.ConnectionServiceWrapper;
73 import com.android.server.telecom.EmergencyCallHelper;
74 import com.android.server.telecom.PhoneAccountRegistrar;
75 import com.android.server.telecom.PhoneNumberUtilsAdapter;
76 import com.android.server.telecom.TelecomSystem;
77 import com.android.server.telecom.TransactionalServiceWrapper;
78 import com.android.server.telecom.ui.ToastFactory;
79 
80 import org.junit.After;
81 import org.junit.Before;
82 import org.junit.Test;
83 import org.junit.runner.RunWith;
84 import org.mockito.ArgumentCaptor;
85 import org.mockito.Mock;
86 import org.mockito.Mockito;
87 
88 import java.util.Collections;
89 import java.util.Set;
90 
91 @RunWith(AndroidJUnit4.class)
92 public class CallTest extends TelecomTestCase {
93     private static final Uri TEST_ADDRESS = Uri.parse("tel:555-1212");
94     private static final ComponentName COMPONENT_NAME_1 = ComponentName
95             .unflattenFromString("com.foo/.Blah");
96     private static final ComponentName COMPONENT_NAME_2 = ComponentName
97             .unflattenFromString("com.bar/.Blah");
98     private static final PhoneAccountHandle SIM_1_HANDLE = new PhoneAccountHandle(
99             COMPONENT_NAME_1, "Sim1");
100     private static final PhoneAccount SIM_1_ACCOUNT = new PhoneAccount.Builder(SIM_1_HANDLE, "Sim1")
101             .setCapabilities(PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION
102                     | PhoneAccount.CAPABILITY_CALL_PROVIDER)
103             .setIsEnabled(true)
104             .build();
105     private static final long TIMEOUT_MILLIS = 1000;
106 
107     @Mock private CallsManager mMockCallsManager;
108     @Mock private CallerInfoLookupHelper mMockCallerInfoLookupHelper;
109     @Mock private PhoneAccountRegistrar mMockPhoneAccountRegistrar;
110     @Mock private ClockProxy mMockClockProxy;
111     @Mock private ToastFactory mMockToastProxy;
112     @Mock private PhoneNumberUtilsAdapter mMockPhoneNumberUtilsAdapter;
113     @Mock private ConnectionServiceWrapper mMockConnectionService;
114     @Mock private TransactionalServiceWrapper mMockTransactionalService;
115 
116     private final TelecomSystem.SyncRoot mLock = new TelecomSystem.SyncRoot() { };
117 
118     @Before
setUp()119     public void setUp() throws Exception {
120         super.setUp();
121         doReturn(mMockCallerInfoLookupHelper).when(mMockCallsManager).getCallerInfoLookupHelper();
122         doReturn(mMockPhoneAccountRegistrar).when(mMockCallsManager).getPhoneAccountRegistrar();
123         doReturn(0L).when(mMockClockProxy).elapsedRealtime();
124         doReturn(SIM_1_ACCOUNT).when(mMockPhoneAccountRegistrar).getPhoneAccountUnchecked(
125                 eq(SIM_1_HANDLE));
126         doReturn(new ComponentName(mContext, CallTest.class))
127                 .when(mMockConnectionService).getComponentName();
128         doReturn(UserHandle.CURRENT).when(mMockCallsManager).getCurrentUserHandle();
129         Resources mockResources = mContext.getResources();
130         when(mockResources.getBoolean(R.bool.skip_loading_canned_text_response))
131                 .thenReturn(false);
132         when(mockResources.getString(R.string.skip_incoming_caller_info_account_package))
133                 .thenReturn("");
134         EmergencyCallHelper helper = mock(EmergencyCallHelper.class);
135         doReturn(helper).when(mMockCallsManager).getEmergencyCallHelper();
136     }
137 
138     @After
tearDown()139     public void tearDown() throws Exception {
140         super.tearDown();
141     }
142 
143     @Test
144     @SmallTest
testSetHasGoneActive()145     public void testSetHasGoneActive() {
146         Call call = createCall("1", Call.CALL_DIRECTION_INCOMING);
147         assertFalse(call.hasGoneActiveBefore());
148         call.setState(CallState.ACTIVE, "");
149         assertTrue(call.hasGoneActiveBefore());
150         call.setState(CallState.AUDIO_PROCESSING, "");
151         assertTrue(call.hasGoneActiveBefore());
152     }
153 
154     /**
155      * Verify that transactional calls remap the [CallAttributes#CallCapability]s to
156      * Connection capabilities.
157      */
158     @Test
159     @SmallTest
testTransactionalCallCapabilityRemapping()160     public void testTransactionalCallCapabilityRemapping() {
161         // ensure when the flag is disabled, the old behavior is unchanged
162         Bundle disabledFlagExtras = new Bundle();
163         Call call = createCall("1", Call.CALL_DIRECTION_INCOMING);
164         disabledFlagExtras.putInt(CallAttributes.CALL_CAPABILITIES_KEY,
165                 Connection.CAPABILITY_MERGE_CONFERENCE);
166         when(mFeatureFlags.remapTransactionalCapabilities()).thenReturn(false);
167         call.setTransactionalCapabilities(disabledFlagExtras);
168         assertTrue(call.can(Connection.CAPABILITY_MERGE_CONFERENCE));
169         // enable the bug fix flag and ensure the transactional capabilities are remapped
170         Bundle enabledFlagExtras = new Bundle();
171         Call call2 = createCall("2", Call.CALL_DIRECTION_INCOMING);
172         enabledFlagExtras.putInt(CallAttributes.CALL_CAPABILITIES_KEY,
173                 CallAttributes.SUPPORTS_SET_INACTIVE);
174         when(mFeatureFlags.remapTransactionalCapabilities()).thenReturn(true);
175         call2.setTransactionalCapabilities(enabledFlagExtras);
176         assertTrue(call2.can(Connection.CAPABILITY_HOLD));
177         assertTrue(call2.can(Connection.CAPABILITY_SUPPORT_HOLD));
178     }
179 
180     /**
181      * Verify Call#setVideoState will only upgrade to video if the PhoneAccount supports video
182      * state capabilities
183      */
184     @Test
185     @SmallTest
testSetVideoStateForTransactionalCalls()186     public void testSetVideoStateForTransactionalCalls() {
187         Call call = createCall("1", Call.CALL_DIRECTION_INCOMING);
188         TransactionalServiceWrapper tsw = Mockito.mock(TransactionalServiceWrapper.class);
189         call.setIsTransactionalCall(true);
190         call.setTransactionServiceWrapper(tsw);
191         assertTrue(call.isTransactionalCall());
192         assertNotNull(call.getTransactionServiceWrapper());
193         when(mFeatureFlags.transactionalVideoState()).thenReturn(true);
194 
195         // VoIP apps using transactional APIs must register a PhoneAccount that supports
196         // video calling capabilities or the video state will be defaulted to audio
197         assertFalse(call.isVideoCallingSupportedByPhoneAccount());
198         call.setVideoState(VideoProfile.STATE_BIDIRECTIONAL);
199         assertEquals(VideoProfile.STATE_AUDIO_ONLY, call.getVideoState());
200 
201         call.setVideoCallingSupportedByPhoneAccount(true);
202         assertTrue(call.isVideoCallingSupportedByPhoneAccount());
203 
204         // After the PhoneAccount signals it supports video calling, video state changes can occur
205         call.setVideoState(VideoProfile.STATE_BIDIRECTIONAL);
206         assertEquals(VideoProfile.STATE_BIDIRECTIONAL, call.getVideoState());
207         verify(tsw, times(1)).onVideoStateChanged(call, CallAttributes.VIDEO_CALL);
208     }
209 
210     /**
211      * Verify all video state changes are echoed out to the TransactionalServiceWrapper
212      */
213     @Test
214     @SmallTest
testToggleTransactionalVideoState()215     public void testToggleTransactionalVideoState() {
216         Call call = createCall("1", Call.CALL_DIRECTION_INCOMING);
217         TransactionalServiceWrapper tsw = Mockito.mock(TransactionalServiceWrapper.class);
218         call.setIsTransactionalCall(true);
219         call.setTransactionServiceWrapper(tsw);
220         call.setVideoCallingSupportedByPhoneAccount(true);
221         assertTrue(call.isTransactionalCall());
222         assertNotNull(call.getTransactionServiceWrapper());
223         assertTrue(call.isVideoCallingSupportedByPhoneAccount());
224         when(mFeatureFlags.transactionalVideoState()).thenReturn(true);
225 
226         call.setVideoState(VideoProfile.STATE_BIDIRECTIONAL);
227         assertEquals(VideoProfile.STATE_BIDIRECTIONAL, call.getVideoState());
228         verify(tsw, times(1)).onVideoStateChanged(call, CallAttributes.VIDEO_CALL);
229 
230         call.setVideoState(VideoProfile.STATE_BIDIRECTIONAL);
231         assertEquals(VideoProfile.STATE_BIDIRECTIONAL, call.getVideoState());
232         verify(tsw, times(2)).onVideoStateChanged(call, CallAttributes.VIDEO_CALL);
233 
234         call.setVideoState(VideoProfile.STATE_AUDIO_ONLY);
235         assertEquals(VideoProfile.STATE_AUDIO_ONLY, call.getVideoState());
236         verify(tsw, times(1)).onVideoStateChanged(call, CallAttributes.AUDIO_CALL);
237 
238         call.setVideoState(VideoProfile.STATE_BIDIRECTIONAL);
239         assertEquals(VideoProfile.STATE_BIDIRECTIONAL, call.getVideoState());
240         verify(tsw, times(3)).onVideoStateChanged(call, CallAttributes.VIDEO_CALL);
241     }
242 
243     @Test
testMultipleCachedCallEvents()244     public void testMultipleCachedCallEvents() {
245         when(mFeatureFlags.cacheCallAudioCallbacks()).thenReturn(true);
246         when(mFeatureFlags.cacheCallEvents()).thenReturn(true);
247         TransactionalServiceWrapper tsw = Mockito.mock(TransactionalServiceWrapper.class);
248         Call call = createCall("1", Call.CALL_DIRECTION_INCOMING);
249 
250         assertNull(call.getTransactionServiceWrapper());
251 
252         String testEvent1 = "test1";
253         Bundle testBundle1 = new Bundle();
254         testBundle1.putInt("testKey", 1);
255         call.sendCallEvent(testEvent1, testBundle1);
256         assertEquals(1,
257                 call.getCachedServiceCallbacksCopy().get(CachedCallEventQueue.ID).size());
258 
259         String testEvent2 = "test2";
260         Bundle testBundle2 = new Bundle();
261         testBundle2.putInt("testKey", 2);
262         call.sendCallEvent(testEvent2, testBundle2);
263         assertEquals(2,
264                 call.getCachedServiceCallbacksCopy().get(CachedCallEventQueue.ID).size());
265 
266         String testEvent3 = "test3";
267         Bundle testBundle3 = new Bundle();
268         testBundle2.putInt("testKey", 3);
269         call.sendCallEvent(testEvent3, testBundle3);
270         assertEquals(3,
271                 call.getCachedServiceCallbacksCopy().get(CachedCallEventQueue.ID).size());
272 
273         verify(tsw, times(0)).sendCallEvent(any(), any(), any());
274         call.setTransactionServiceWrapper(tsw);
275         verify(tsw, times(1)).sendCallEvent(any(), eq(testEvent1), eq(testBundle1));
276         verify(tsw, times(1)).sendCallEvent(any(), eq(testEvent2), eq(testBundle2));
277         verify(tsw, times(1)).sendCallEvent(any(), eq(testEvent3), eq(testBundle3));
278         assertEquals(0, call.getCachedServiceCallbacksCopy().size());
279     }
280 
281     @Test
testMultipleCachedMuteStateChanges()282     public void testMultipleCachedMuteStateChanges() {
283         when(mFeatureFlags.cacheCallAudioCallbacks()).thenReturn(true);
284         TransactionalServiceWrapper tsw = Mockito.mock(TransactionalServiceWrapper.class);
285         Call call = createCall("1", Call.CALL_DIRECTION_INCOMING);
286 
287         assertNull(call.getTransactionServiceWrapper());
288 
289         call.cacheServiceCallback(new CachedMuteStateChange(true));
290         assertEquals(1,
291                 call.getCachedServiceCallbacksCopy().get(CachedMuteStateChange.ID).size());
292 
293         call.cacheServiceCallback(new CachedMuteStateChange(false));
294         assertEquals(1,
295                 call.getCachedServiceCallbacksCopy().get(CachedMuteStateChange.ID).size());
296 
297         CachedMuteStateChange currentCacheMuteState = (CachedMuteStateChange) call
298                 .getCachedServiceCallbacksCopy()
299                 .get(CachedMuteStateChange.ID)
300                 .getLast();
301 
302         assertFalse(currentCacheMuteState.isMuted());
303 
304         call.setTransactionServiceWrapper(tsw);
305         verify(tsw, times(1)).onMuteStateChanged(any(), eq(false));
306         assertEquals(0, call.getCachedServiceCallbacksCopy().size());
307     }
308 
309     @Test
testCacheAfterServiceSet()310     public void testCacheAfterServiceSet() {
311         when(mFeatureFlags.cacheCallAudioCallbacks()).thenReturn(true);
312         when(mFeatureFlags.cacheCallEvents()).thenReturn(true);
313         TransactionalServiceWrapper tsw = Mockito.mock(TransactionalServiceWrapper.class);
314         Call call = createCall("1", Call.CALL_DIRECTION_INCOMING);
315 
316         assertNull(call.getTransactionServiceWrapper());
317         call.setTransactionServiceWrapper(tsw);
318         call.cacheServiceCallback(new CachedMuteStateChange(true));
319         // Ensure that we do not lose events if for some reason a CachedCallback is cached after
320         // the service is set
321         verify(tsw, times(1)).onMuteStateChanged(any(), eq(true));
322         assertEquals(0, call.getCachedServiceCallbacksCopy().size());
323     }
324 
325     @Test
testMultipleCachedCurrentEndpointChanges()326     public void testMultipleCachedCurrentEndpointChanges() {
327         when(mFeatureFlags.cacheCallAudioCallbacks()).thenReturn(true);
328         TransactionalServiceWrapper tsw = Mockito.mock(TransactionalServiceWrapper.class);
329         CallEndpoint earpiece = Mockito.mock(CallEndpoint.class);
330         CallEndpoint speaker = Mockito.mock(CallEndpoint.class);
331         when(earpiece.getEndpointType()).thenReturn(CallEndpoint.TYPE_EARPIECE);
332         when(speaker.getEndpointType()).thenReturn(CallEndpoint.TYPE_SPEAKER);
333 
334         Call call = createCall("1", Call.CALL_DIRECTION_INCOMING);
335 
336         assertNull(call.getTransactionServiceWrapper());
337 
338         call.cacheServiceCallback(new CachedCurrentEndpointChange(earpiece));
339         assertEquals(1,
340                 call.getCachedServiceCallbacksCopy().get(CachedCurrentEndpointChange.ID).size());
341 
342         call.cacheServiceCallback(new CachedCurrentEndpointChange(speaker));
343         assertEquals(1,
344                 call.getCachedServiceCallbacksCopy().get(CachedCurrentEndpointChange.ID).size());
345 
346         CachedCurrentEndpointChange currentEndpointChange = (CachedCurrentEndpointChange) call
347                 .getCachedServiceCallbacksCopy()
348                 .get(CachedCurrentEndpointChange.ID)
349                 .getLast();
350 
351         assertEquals(CallEndpoint.TYPE_SPEAKER,
352                 currentEndpointChange.getCurrentCallEndpoint().getEndpointType());
353 
354         call.setTransactionServiceWrapper(tsw);
355         verify(tsw, times(1)).onCallEndpointChanged(any(), any());
356         assertEquals(0, call.getCachedServiceCallbacksCopy().size());
357     }
358 
359     @Test
testMultipleCachedAvailableEndpointChanges()360     public void testMultipleCachedAvailableEndpointChanges() {
361         when(mFeatureFlags.cacheCallAudioCallbacks()).thenReturn(true);
362         TransactionalServiceWrapper tsw = Mockito.mock(TransactionalServiceWrapper.class);
363         CallEndpoint earpiece = Mockito.mock(CallEndpoint.class);
364         CallEndpoint bluetooth = Mockito.mock(CallEndpoint.class);
365         Set<CallEndpoint> initialSet = Set.of(earpiece);
366         Set<CallEndpoint> finalSet = Set.of(earpiece, bluetooth);
367         when(earpiece.getEndpointType()).thenReturn(CallEndpoint.TYPE_EARPIECE);
368         when(bluetooth.getEndpointType()).thenReturn(CallEndpoint.TYPE_BLUETOOTH);
369 
370         Call call = createCall("1", Call.CALL_DIRECTION_INCOMING);
371 
372         assertNull(call.getTransactionServiceWrapper());
373 
374         call.cacheServiceCallback(new CachedAvailableEndpointsChange(initialSet));
375         assertEquals(1,
376                 call.getCachedServiceCallbacksCopy().get(CachedAvailableEndpointsChange.ID).size());
377 
378         call.cacheServiceCallback(new CachedAvailableEndpointsChange(finalSet));
379         assertEquals(1,
380                 call.getCachedServiceCallbacksCopy().get(CachedAvailableEndpointsChange.ID).size());
381 
382         CachedAvailableEndpointsChange availableEndpoints = (CachedAvailableEndpointsChange) call
383                 .getCachedServiceCallbacksCopy()
384                 .get(CachedAvailableEndpointsChange.ID)
385                 .getLast();
386 
387         assertEquals(2, availableEndpoints.getAvailableEndpoints().size());
388 
389         call.setTransactionServiceWrapper(tsw);
390         verify(tsw, times(1)).onAvailableCallEndpointsChanged(any(), any());
391         assertEquals(0, call.getCachedServiceCallbacksCopy().size());
392     }
393 
394     /**
395      * verify that if multiple types of cached callbacks are added to the call, the call executes
396      * all the callbacks once the service is set.
397      */
398     @Test
testAllCachedCallbacks()399     public void testAllCachedCallbacks() {
400         when(mFeatureFlags.cacheCallAudioCallbacks()).thenReturn(true);
401         when(mFeatureFlags.cacheCallEvents()).thenReturn(true);
402         TransactionalServiceWrapper tsw = Mockito.mock(TransactionalServiceWrapper.class);
403         CallEndpoint earpiece = Mockito.mock(CallEndpoint.class);
404         CallEndpoint bluetooth = Mockito.mock(CallEndpoint.class);
405         Set<CallEndpoint> availableEndpointsSet = Set.of(earpiece, bluetooth);
406         when(earpiece.getEndpointType()).thenReturn(CallEndpoint.TYPE_EARPIECE);
407         when(bluetooth.getEndpointType()).thenReturn(CallEndpoint.TYPE_BLUETOOTH);
408         Call call = createCall("1", Call.CALL_DIRECTION_INCOMING);
409 
410         // The call should have a null service so that callbacks are cached
411         assertNull(call.getTransactionServiceWrapper());
412 
413         // add cached callbacks
414         call.cacheServiceCallback(new CachedMuteStateChange(false));
415         assertEquals(1, call.getCachedServiceCallbacksCopy().size());
416         call.cacheServiceCallback(new CachedCurrentEndpointChange(earpiece));
417         assertEquals(2, call.getCachedServiceCallbacksCopy().size());
418         call.cacheServiceCallback(new CachedAvailableEndpointsChange(availableEndpointsSet));
419         assertEquals(3, call.getCachedServiceCallbacksCopy().size());
420         String testEvent = "testEvent";
421         Bundle testBundle = new Bundle();
422         call.sendCallEvent("testEvent", testBundle);
423 
424         // verify the cached callbacks are stored properly within the cache map and the values
425         // can be evaluated
426         CachedMuteStateChange currentCacheMuteState = (CachedMuteStateChange) call
427                 .getCachedServiceCallbacksCopy()
428                 .get(CachedMuteStateChange.ID)
429                 .getLast();
430         CachedCurrentEndpointChange currentEndpointChange = (CachedCurrentEndpointChange) call
431                 .getCachedServiceCallbacksCopy()
432                 .get(CachedCurrentEndpointChange.ID)
433                 .getLast();
434         CachedAvailableEndpointsChange availableEndpoints = (CachedAvailableEndpointsChange) call
435                 .getCachedServiceCallbacksCopy()
436                 .get(CachedAvailableEndpointsChange.ID)
437                 .getLast();
438         assertFalse(currentCacheMuteState.isMuted());
439         assertEquals(CallEndpoint.TYPE_EARPIECE,
440                 currentEndpointChange.getCurrentCallEndpoint().getEndpointType());
441         assertEquals(2, availableEndpoints.getAvailableEndpoints().size());
442 
443         // set the service to a non-null value
444         call.setTransactionServiceWrapper(tsw);
445 
446         // ensure the cached callbacks were executed
447         verify(tsw, times(1)).onMuteStateChanged(any(), anyBoolean());
448         verify(tsw, times(1)).onCallEndpointChanged(any(), any());
449         verify(tsw, times(1)).onAvailableCallEndpointsChanged(any(), any());
450         verify(tsw, times(1)).sendCallEvent(any(), eq(testEvent), eq(testBundle));
451 
452         // the cache map should be cleared
453         assertEquals(0, call.getCachedServiceCallbacksCopy().size());
454     }
455 
456     /**
457      * Basic tests to check which call states are considered transitory.
458      */
459     @Test
460     @SmallTest
testIsCallStateTransitory()461     public void testIsCallStateTransitory() {
462         assertTrue(CallState.isTransitoryState(CallState.NEW));
463         assertTrue(CallState.isTransitoryState(CallState.CONNECTING));
464         assertTrue(CallState.isTransitoryState(CallState.DISCONNECTING));
465         assertTrue(CallState.isTransitoryState(CallState.ANSWERED));
466 
467         assertFalse(CallState.isTransitoryState(CallState.SELECT_PHONE_ACCOUNT));
468         assertFalse(CallState.isTransitoryState(CallState.DIALING));
469         assertFalse(CallState.isTransitoryState(CallState.RINGING));
470         assertFalse(CallState.isTransitoryState(CallState.ACTIVE));
471         assertFalse(CallState.isTransitoryState(CallState.ON_HOLD));
472         assertFalse(CallState.isTransitoryState(CallState.DISCONNECTED));
473         assertFalse(CallState.isTransitoryState(CallState.ABORTED));
474         assertFalse(CallState.isTransitoryState(CallState.PULLING));
475         assertFalse(CallState.isTransitoryState(CallState.AUDIO_PROCESSING));
476         assertFalse(CallState.isTransitoryState(CallState.SIMULATED_RINGING));
477     }
478 
479     /**
480      * Basic tests to check which call states are considered intermediate.
481      */
482     @Test
483     @SmallTest
testIsCallStateIntermediate()484     public void testIsCallStateIntermediate() {
485         assertTrue(CallState.isIntermediateState(CallState.DIALING));
486         assertTrue(CallState.isIntermediateState(CallState.RINGING));
487 
488         assertFalse(CallState.isIntermediateState(CallState.NEW));
489         assertFalse(CallState.isIntermediateState(CallState.CONNECTING));
490         assertFalse(CallState.isIntermediateState(CallState.DISCONNECTING));
491         assertFalse(CallState.isIntermediateState(CallState.ANSWERED));
492         assertFalse(CallState.isIntermediateState(CallState.SELECT_PHONE_ACCOUNT));
493         assertFalse(CallState.isIntermediateState(CallState.ACTIVE));
494         assertFalse(CallState.isIntermediateState(CallState.ON_HOLD));
495         assertFalse(CallState.isIntermediateState(CallState.DISCONNECTED));
496         assertFalse(CallState.isIntermediateState(CallState.ABORTED));
497         assertFalse(CallState.isIntermediateState(CallState.PULLING));
498         assertFalse(CallState.isIntermediateState(CallState.AUDIO_PROCESSING));
499         assertFalse(CallState.isIntermediateState(CallState.SIMULATED_RINGING));
500     }
501 
502     @SmallTest
503     @Test
testIsCreateConnectionComplete()504     public void testIsCreateConnectionComplete() {
505         // A new call with basic info.
506         Call call = new Call(
507                 "1", /* callId */
508                 mContext,
509                 mMockCallsManager,
510                 mLock,
511                 null /* ConnectionServiceRepository */,
512                 mMockPhoneNumberUtilsAdapter,
513                 TEST_ADDRESS,
514                 null /* GatewayInfo */,
515                 null /* connectionManagerPhoneAccountHandle */,
516                 SIM_1_HANDLE,
517                 Call.CALL_DIRECTION_INCOMING,
518                 false /* shouldAttachToExistingConnection*/,
519                 false /* isConference */,
520                 mMockClockProxy,
521                 mMockToastProxy,
522                 mFeatureFlags);
523 
524         // To start with connection creation isn't complete.
525         assertFalse(call.isCreateConnectionComplete());
526 
527         // Need the bare minimum to get connection creation to complete.
528         ParcelableConnection connection = new ParcelableConnection(null, 0, 0, 0, 0, null, 0, null,
529                 0, null, 0, false, false, 0L, 0L, null, null, Collections.emptyList(), null, null,
530                 0, 0);
531         call.handleCreateConnectionSuccess(Mockito.mock(CallIdMapper.class), connection);
532         assertTrue(call.isCreateConnectionComplete());
533     }
534 
535     @Test
536     @SmallTest
testDisconnectCauseWhenAudioProcessing()537     public void testDisconnectCauseWhenAudioProcessing() {
538         Call call = createCall("1", Call.CALL_DIRECTION_INCOMING);
539         call.setState(CallState.AUDIO_PROCESSING, "");
540         call.disconnect();
541         call.setDisconnectCause(new DisconnectCause(DisconnectCause.LOCAL));
542         assertEquals(DisconnectCause.REJECTED, call.getDisconnectCause().getCode());
543     }
544 
545     @Test
546     @SmallTest
testDisconnectCauseWhenAudioProcessingAfterActive()547     public void testDisconnectCauseWhenAudioProcessingAfterActive() {
548         Call call = createCall("1", Call.CALL_DIRECTION_INCOMING);
549         call.setState(CallState.AUDIO_PROCESSING, "");
550         call.setState(CallState.ACTIVE, "");
551         call.setState(CallState.AUDIO_PROCESSING, "");
552         call.disconnect();
553         call.setDisconnectCause(new DisconnectCause(DisconnectCause.LOCAL));
554         assertEquals(DisconnectCause.LOCAL, call.getDisconnectCause().getCode());
555     }
556 
557     @Test
558     @SmallTest
testDisconnectCauseWhenSimulatedRingingAndDisconnect()559     public void testDisconnectCauseWhenSimulatedRingingAndDisconnect() {
560         Call call = createCall("1", Call.CALL_DIRECTION_INCOMING);
561         call.setState(CallState.SIMULATED_RINGING, "");
562         call.disconnect();
563         call.setDisconnectCause(new DisconnectCause(DisconnectCause.LOCAL));
564         assertEquals(DisconnectCause.MISSED, call.getDisconnectCause().getCode());
565     }
566 
567     @Test
568     @SmallTest
testDisconnectCauseWhenSimulatedRingingAndReject()569     public void testDisconnectCauseWhenSimulatedRingingAndReject() {
570         Call call = createCall("1", Call.CALL_DIRECTION_INCOMING);
571         call.setState(CallState.SIMULATED_RINGING, "");
572         call.reject(false, "");
573         call.setDisconnectCause(new DisconnectCause(DisconnectCause.LOCAL));
574         assertEquals(DisconnectCause.REJECTED, call.getDisconnectCause().getCode());
575     }
576 
577     @Test
578     @SmallTest
testCanPullCallRemovedDuringEmergencyCall()579     public void testCanPullCallRemovedDuringEmergencyCall() {
580         Call call = createCall("1", Call.CALL_DIRECTION_INCOMING);
581         boolean[] hasCalledConnectionCapabilitiesChanged = new boolean[1];
582         call.addListener(new Call.ListenerBase() {
583             @Override
584             public void onConnectionCapabilitiesChanged(Call call) {
585                 hasCalledConnectionCapabilitiesChanged[0] = true;
586             }
587         });
588         call.setConnectionService(mMockConnectionService);
589         call.setConnectionProperties(Connection.PROPERTY_IS_EXTERNAL_CALL);
590         call.setConnectionCapabilities(Connection.CAPABILITY_CAN_PULL_CALL);
591         call.setState(CallState.ACTIVE, "");
592         assertTrue(hasCalledConnectionCapabilitiesChanged[0]);
593         // Capability should be present
594         assertTrue((call.getConnectionCapabilities() | Connection.CAPABILITY_CAN_PULL_CALL) > 0);
595         hasCalledConnectionCapabilitiesChanged[0] = false;
596         // Emergency call in progress
597         call.setIsPullExternalCallSupported(false /*isPullCallSupported*/);
598         assertTrue(hasCalledConnectionCapabilitiesChanged[0]);
599         // Capability should not be present
600         assertEquals(0, call.getConnectionCapabilities() & Connection.CAPABILITY_CAN_PULL_CALL);
601         hasCalledConnectionCapabilitiesChanged[0] = false;
602         // Emergency call complete
603         call.setIsPullExternalCallSupported(true /*isPullCallSupported*/);
604         assertTrue(hasCalledConnectionCapabilitiesChanged[0]);
605         // Capability should be present
606         assertEquals(Connection.CAPABILITY_CAN_PULL_CALL,
607                 call.getConnectionCapabilities() & Connection.CAPABILITY_CAN_PULL_CALL);
608     }
609 
610     @Test
611     @SmallTest
testCanNotPullCallDuringEmergencyCall()612     public void testCanNotPullCallDuringEmergencyCall() {
613         Call call = createCall("1", Call.CALL_DIRECTION_INCOMING);
614         call.setConnectionService(mMockConnectionService);
615         call.setConnectionProperties(Connection.PROPERTY_IS_EXTERNAL_CALL);
616         call.setConnectionCapabilities(Connection.CAPABILITY_CAN_PULL_CALL);
617         call.setState(CallState.ACTIVE, "");
618         // Emergency call in progress, this should show a toast and never call pullExternalCall
619         // on the ConnectionService.
620         doReturn(true).when(mMockCallsManager).isInEmergencyCall();
621         call.pullExternalCall();
622         verify(mMockConnectionService, never()).pullExternalCall(any());
623     }
624 
625     @Test
626     @SmallTest
testCallDirection()627     public void testCallDirection() {
628         Call call = createCall("1");
629         boolean[] hasCallDirectionChanged = new boolean[1];
630         call.addListener(new Call.ListenerBase() {
631             @Override
632             public void onCallDirectionChanged(Call call) {
633                 hasCallDirectionChanged[0] = true;
634             }
635         });
636         assertFalse(call.isIncoming());
637         call.setCallDirection(Call.CALL_DIRECTION_INCOMING);
638         assertTrue(hasCallDirectionChanged[0]);
639         assertTrue(call.isIncoming());
640     }
641 
642     @Test
testIsSuppressedByDoNotDisturbExtra()643     public void testIsSuppressedByDoNotDisturbExtra() {
644         Call call = new Call(
645                 "1", /* callId */
646                 mContext,
647                 mMockCallsManager,
648                 mLock,
649                 null /* ConnectionServiceRepository */,
650                 mMockPhoneNumberUtilsAdapter,
651                 TEST_ADDRESS,
652                 null /* GatewayInfo */,
653                 null /* connectionManagerPhoneAccountHandle */,
654                 SIM_1_HANDLE,
655                 Call.CALL_DIRECTION_UNDEFINED,
656                 false /* shouldAttachToExistingConnection*/,
657                 true /* isConference */,
658                 mMockClockProxy,
659                 mMockToastProxy,
660                 mFeatureFlags);
661 
662         assertFalse(call.wasDndCheckComputedForCall());
663         assertFalse(call.isCallSuppressedByDoNotDisturb());
664         call.setCallIsSuppressedByDoNotDisturb(true);
665         assertTrue(call.wasDndCheckComputedForCall());
666         assertTrue(call.isCallSuppressedByDoNotDisturb());
667     }
668 
669     @Test
testGetConnectionServiceWrapper()670     public void testGetConnectionServiceWrapper() {
671         Call call = new Call(
672                 "1", /* callId */
673                 mContext,
674                 mMockCallsManager,
675                 mLock,
676                 null /* ConnectionServiceRepository */,
677                 mMockPhoneNumberUtilsAdapter,
678                 TEST_ADDRESS,
679                 null /* GatewayInfo */,
680                 null /* connectionManagerPhoneAccountHandle */,
681                 SIM_1_HANDLE,
682                 Call.CALL_DIRECTION_UNDEFINED,
683                 false /* shouldAttachToExistingConnection*/,
684                 true /* isConference */,
685                 mMockClockProxy,
686                 mMockToastProxy,
687                 mFeatureFlags);
688 
689         assertNull(call.getConnectionServiceWrapper());
690         assertFalse(call.isTransactionalCall());
691         call.setConnectionService(mMockConnectionService);
692         assertEquals(mMockConnectionService, call.getConnectionServiceWrapper());
693         call.setIsTransactionalCall(true);
694         assertTrue(call.isTransactionalCall());
695         assertNull(call.getConnectionServiceWrapper());
696         call.setTransactionServiceWrapper(mMockTransactionalService);
697         assertEquals(mMockTransactionalService, call.getTransactionServiceWrapper());
698     }
699 
700     @Test
testCallEventCallbacksWereCalled()701     public void testCallEventCallbacksWereCalled() {
702         Call call = new Call(
703                 "1", /* callId */
704                 mContext,
705                 mMockCallsManager,
706                 mLock,
707                 null /* ConnectionServiceRepository */,
708                 mMockPhoneNumberUtilsAdapter,
709                 TEST_ADDRESS,
710                 null /* GatewayInfo */,
711                 null /* connectionManagerPhoneAccountHandle */,
712                 SIM_1_HANDLE,
713                 Call.CALL_DIRECTION_UNDEFINED,
714                 false /* shouldAttachToExistingConnection*/,
715                 true /* isConference */,
716                 mMockClockProxy,
717                 mMockToastProxy,
718                 mFeatureFlags);
719 
720         // setup
721         call.setIsTransactionalCall(true);
722         assertTrue(call.isTransactionalCall());
723         assertNull(call.getConnectionServiceWrapper());
724         call.setTransactionServiceWrapper(mMockTransactionalService);
725         assertEquals(mMockTransactionalService, call.getTransactionServiceWrapper());
726 
727         // assert CallEventCallback#onSetInactive is called
728         call.setState(CallState.ACTIVE, "test");
729         call.hold();
730         verify(mMockTransactionalService, times(1)).onSetInactive(call);
731 
732         // assert CallEventCallback#onSetActive is called
733         call.setState(CallState.ON_HOLD, "test");
734         call.unhold();
735         verify(mMockTransactionalService, times(1)).onSetActive(call);
736 
737         // assert CallEventCallback#onAnswer is called
738         call.setState(CallState.RINGING, "test");
739         call.answer(0);
740         verify(mMockTransactionalService, times(1)).onAnswer(call, 0);
741 
742         // assert CallEventCallback#onDisconnect is called
743         call.setState(CallState.ACTIVE, "test");
744         call.disconnect();
745         verify(mMockTransactionalService, times(1)).onDisconnect(call,
746                 call.getDisconnectCause());
747     }
748 
749     @Test
750     @SmallTest
testSetConnectionPropertiesRttOnOff()751     public void testSetConnectionPropertiesRttOnOff() {
752         Call call = createCall("1");
753         call.setConnectionService(mMockConnectionService);
754 
755         call.setConnectionProperties(Connection.PROPERTY_IS_RTT);
756         verify(mMockCallsManager).playRttUpgradeToneForCall(any());
757         assertNotNull(null, call.getInCallToCsRttPipeForCs());
758         assertNotNull(null, call.getCsToInCallRttPipeForInCall());
759 
760         call.setConnectionProperties(0);
761         assertNull(null, call.getInCallToCsRttPipeForCs());
762         assertNull(null, call.getCsToInCallRttPipeForInCall());
763     }
764 
765     @Test
766     @SmallTest
testGetFromCallerInfo()767     public void testGetFromCallerInfo() {
768         Call call = createCall("1");
769 
770         CallerInfo info = new CallerInfo();
771         info.setName("name");
772         info.setPhoneNumber("number");
773         info.cachedPhoto = new ColorDrawable();
774         info.cachedPhotoIcon = Bitmap.createBitmap(24, 24, Bitmap.Config.ALPHA_8);
775 
776         ArgumentCaptor<CallerInfoLookupHelper.OnQueryCompleteListener> listenerCaptor =
777                 ArgumentCaptor.forClass(CallerInfoLookupHelper.OnQueryCompleteListener.class);
778         verify(mMockCallerInfoLookupHelper).startLookup(any(), listenerCaptor.capture());
779         listenerCaptor.getValue().onCallerInfoQueryComplete(call.getHandle(), info);
780 
781         assertEquals(info, call.getCallerInfo());
782         assertEquals(info.getName(), call.getName());
783         assertEquals(info.getPhoneNumber(), call.getPhoneNumber());
784         assertEquals(info.cachedPhoto, call.getPhoto());
785         assertEquals(info.cachedPhotoIcon, call.getPhotoIcon());
786         assertEquals(call.getHandle(), call.getContactUri());
787     }
788 
789     @Test
790     @SmallTest
testGetFromCallerInfo_skipLookup()791     public void testGetFromCallerInfo_skipLookup() {
792         Resources mockResources = mContext.getResources();
793         when(mockResources.getString(R.string.skip_incoming_caller_info_account_package))
794                 .thenReturn("com.foo");
795 
796         createCall("1");
797 
798         verify(mMockCallerInfoLookupHelper, never()).startLookup(any(), any());
799     }
800 
801     @Test
802     @SmallTest
testOriginalCallIntent()803     public void testOriginalCallIntent() {
804         Call call = createCall("1");
805 
806         Intent i = new Intent();
807         call.setOriginalCallIntent(i);
808 
809         assertEquals(i, call.getOriginalCallIntent());
810     }
811 
812     @Test
813     @SmallTest
testHandleCreateConferenceSuccessNotifiesListeners()814     public void testHandleCreateConferenceSuccessNotifiesListeners() {
815         Call.Listener listener = mock(Call.Listener.class);
816 
817         Call incomingCall = createCall("1", Call.CALL_DIRECTION_INCOMING);
818         incomingCall.setConnectionService(mMockConnectionService);
819         incomingCall.addListener(listener);
820         Call outgoingCall = createCall("2", Call.CALL_DIRECTION_OUTGOING);
821         outgoingCall.setConnectionService(mMockConnectionService);
822         outgoingCall.addListener(listener);
823 
824         StatusHints statusHints = mock(StatusHints.class);
825         Bundle extra = new Bundle();
826         ParcelableConference conference =
827                 new ParcelableConference.Builder(SIM_1_HANDLE, Connection.STATE_NEW)
828                     .setAddress(TEST_ADDRESS, TelecomManager.PRESENTATION_ALLOWED)
829                     .setConnectionCapabilities(123)
830                     .setVideoAttributes(null, VideoProfile.STATE_AUDIO_ONLY)
831                     .setRingbackRequested(true)
832                     .setStatusHints(statusHints)
833                     .setExtras(extra)
834                     .build();
835 
836         incomingCall.handleCreateConferenceSuccess(null, conference);
837         verify(listener).onSuccessfulIncomingCall(incomingCall);
838 
839         outgoingCall.handleCreateConferenceSuccess(null, conference);
840         verify(listener).onSuccessfulOutgoingCall(outgoingCall, CallState.NEW);
841     }
842 
843     @Test
844     @SmallTest
testHandleCreateConferenceSuccess()845     public void testHandleCreateConferenceSuccess() {
846         Call call = createCall("1", Call.CALL_DIRECTION_INCOMING);
847         call.setConnectionService(mMockConnectionService);
848 
849         StatusHints statusHints = mock(StatusHints.class);
850         Bundle extra = new Bundle();
851         ParcelableConference conference =
852                 new ParcelableConference.Builder(SIM_1_HANDLE, Connection.STATE_NEW)
853                     .setAddress(TEST_ADDRESS, TelecomManager.PRESENTATION_ALLOWED)
854                     .setConnectionCapabilities(123)
855                     .setVideoAttributes(null, VideoProfile.STATE_AUDIO_ONLY)
856                     .setRingbackRequested(true)
857                     .setStatusHints(statusHints)
858                     .setExtras(extra)
859                     .build();
860 
861         call.handleCreateConferenceSuccess(null, conference);
862 
863         assertEquals(SIM_1_HANDLE, call.getTargetPhoneAccount());
864         assertEquals(TEST_ADDRESS, call.getHandle());
865         assertEquals(123, call.getConnectionCapabilities());
866         assertNull(call.getVideoProviderProxy());
867         assertEquals(VideoProfile.STATE_AUDIO_ONLY, call.getVideoState());
868         assertTrue(call.isRingbackRequested());
869         assertEquals(statusHints, call.getStatusHints());
870     }
871 
872     @Test
873     @SmallTest
testHandleCreateConferenceFailure()874     public void testHandleCreateConferenceFailure() {
875         Call.Listener listener = mock(Call.Listener.class);
876 
877         Call incomingCall = createCall("1", Call.CALL_DIRECTION_INCOMING);
878         incomingCall.setConnectionService(mMockConnectionService);
879         incomingCall.addListener(listener);
880         Call outgoingCall = createCall("2", Call.CALL_DIRECTION_OUTGOING);
881         outgoingCall.setConnectionService(mMockConnectionService);
882         outgoingCall.addListener(listener);
883 
884         final DisconnectCause cause = new DisconnectCause(DisconnectCause.REJECTED);
885 
886         incomingCall.handleCreateConferenceFailure(cause);
887         assertEquals(cause, incomingCall.getDisconnectCause());
888         verify(listener).onFailedIncomingCall(incomingCall);
889 
890         outgoingCall.handleCreateConferenceFailure(cause);
891         assertEquals(cause, outgoingCall.getDisconnectCause());
892         verify(listener).onFailedOutgoingCall(outgoingCall, cause);
893     }
894 
895     @Test
896     @SmallTest
testWasConferencePreviouslyMerged()897     public void testWasConferencePreviouslyMerged() {
898         Call call = createCall("1");
899         call.setConnectionService(mMockConnectionService);
900         call.setConnectionCapabilities(Connection.CAPABILITY_MERGE_CONFERENCE);
901 
902         assertFalse(call.wasConferencePreviouslyMerged());
903 
904         call.mergeConference();
905 
906         assertTrue(call.wasConferencePreviouslyMerged());
907     }
908 
909     @Test
910     @SmallTest
testSwapConference()911     public void testSwapConference() {
912         Call.Listener listener = mock(Call.Listener.class);
913 
914         Call call = createCall("1");
915         call.setConnectionService(mMockConnectionService);
916         call.setConnectionCapabilities(Connection.CAPABILITY_SWAP_CONFERENCE);
917         call.addListener(listener);
918 
919         call.swapConference();
920         assertNull(call.getConferenceLevelActiveCall());
921 
922         Call childCall1 = createCall("child1");
923         childCall1.setChildOf(call);
924         call.swapConference();
925         assertEquals(childCall1, call.getConferenceLevelActiveCall());
926 
927         Call childCall2 = createCall("child2");
928         childCall2.setChildOf(call);
929         call.swapConference();
930         assertEquals(childCall1, call.getConferenceLevelActiveCall());
931         call.swapConference();
932         assertEquals(childCall2, call.getConferenceLevelActiveCall());
933 
934         verify(listener, times(4)).onCdmaConferenceSwap(call);
935     }
936 
937     @Test
938     @SmallTest
testHandleCreateConnectionFailure()939     public void testHandleCreateConnectionFailure() {
940         Call.Listener listener = mock(Call.Listener.class);
941 
942         Call incomingCall = createCall("1", Call.CALL_DIRECTION_INCOMING);
943         incomingCall.setConnectionService(mMockConnectionService);
944         incomingCall.addListener(listener);
945         Call outgoingCall = createCall("2", Call.CALL_DIRECTION_OUTGOING);
946         outgoingCall.setConnectionService(mMockConnectionService);
947         outgoingCall.addListener(listener);
948         Call unknownCall = createCall("3", Call.CALL_DIRECTION_UNKNOWN);
949         unknownCall.setConnectionService(mMockConnectionService);
950         unknownCall.addListener(listener);
951 
952         final DisconnectCause cause = new DisconnectCause(DisconnectCause.REJECTED);
953 
954         incomingCall.handleCreateConnectionFailure(cause);
955         assertEquals(cause, incomingCall.getDisconnectCause());
956         verify(listener).onFailedIncomingCall(incomingCall);
957 
958         outgoingCall.handleCreateConnectionFailure(cause);
959         assertEquals(cause, outgoingCall.getDisconnectCause());
960         verify(listener).onFailedOutgoingCall(outgoingCall, cause);
961 
962         unknownCall.handleCreateConnectionFailure(cause);
963         assertEquals(cause, unknownCall.getDisconnectCause());
964         verify(listener).onFailedUnknownCall(unknownCall);
965     }
966 
967     /**
968      * ensure a Call object does not throw an NPE when the CallingPackageIdentity is not set and
969      * the correct values are returned when set
970      */
971     @Test
972     @SmallTest
testCallingPackageIdentity()973     public void testCallingPackageIdentity() {
974         final int packageUid = 123;
975         final int packagePid = 1;
976 
977         Call call = createCall("1");
978 
979         // assert default values for a Calls CallingPackageIdentity are -1 unless set via the setter
980         assertEquals(-1, call.getCallingPackageIdentity().mCallingPackageUid);
981         assertEquals(-1, call.getCallingPackageIdentity().mCallingPackagePid);
982 
983         // set the Call objects CallingPackageIdentity via the setter and a bundle
984         Bundle extras = new Bundle();
985         extras.putInt(CallAttributes.CALLER_UID_KEY, packageUid);
986         extras.putInt(CallAttributes.CALLER_PID_KEY, packagePid);
987         // assert that the setter removed the extras
988         assertEquals(packageUid, extras.getInt(CallAttributes.CALLER_UID_KEY));
989         assertEquals(packagePid, extras.getInt(CallAttributes.CALLER_PID_KEY));
990         call.setCallingPackageIdentity(extras);
991         // assert that the setter removed the extras
992         assertEquals(0, extras.getInt(CallAttributes.CALLER_UID_KEY));
993         assertEquals(0, extras.getInt(CallAttributes.CALLER_PID_KEY));
994         // assert the properties are fetched correctly
995         assertEquals(packageUid, call.getCallingPackageIdentity().mCallingPackageUid);
996         assertEquals(packagePid, call.getCallingPackageIdentity().mCallingPackagePid);
997     }
998 
999         @Test
1000     @SmallTest
testOnConnectionEventNotifiesListener()1001     public void testOnConnectionEventNotifiesListener() {
1002         when(mFeatureFlags.enableCallSequencing()).thenReturn(true);
1003         Call.Listener listener = mock(Call.Listener.class);
1004         Call call = createCall("1");
1005         call.addListener(listener);
1006 
1007         call.onConnectionEvent(Connection.EVENT_ON_HOLD_TONE_START, null);
1008         verify(listener).onHoldToneRequested(call);
1009         assertTrue(call.isRemotelyHeld());
1010 
1011         call.onConnectionEvent(Connection.EVENT_ON_HOLD_TONE_END, null);
1012         verify(listener, times(2)).onHoldToneRequested(call);
1013         assertFalse(call.isRemotelyHeld());
1014 
1015         call.onConnectionEvent(Connection.EVENT_CALL_HOLD_FAILED, null);
1016         verify(listener).onCallHoldFailed(call);
1017 
1018         call.onConnectionEvent(Connection.EVENT_CALL_SWITCH_FAILED, null);
1019         verify(listener).onCallSwitchFailed(call);
1020 
1021         call.onConnectionEvent(Connection.EVENT_CALL_RESUME_FAILED, null);
1022         verify(listener).onCallResumeFailed(call);
1023 
1024         final int d2dType = 1;
1025         final int d2dValue = 2;
1026         final Bundle d2dExtras = new Bundle();
1027         d2dExtras.putInt(Connection.EXTRA_DEVICE_TO_DEVICE_MESSAGE_TYPE, d2dType);
1028         d2dExtras.putInt(Connection.EXTRA_DEVICE_TO_DEVICE_MESSAGE_VALUE, d2dValue);
1029         call.onConnectionEvent(Connection.EVENT_DEVICE_TO_DEVICE_MESSAGE, d2dExtras);
1030         verify(listener).onReceivedDeviceToDeviceMessage(call, d2dType, d2dValue);
1031 
1032         final CallQuality quality = new CallQuality();
1033         final Bundle callQualityExtras = new Bundle();
1034         callQualityExtras.putParcelable(Connection.EXTRA_CALL_QUALITY_REPORT, quality);
1035         call.onConnectionEvent(Connection.EVENT_CALL_QUALITY_REPORT, callQualityExtras);
1036         verify(listener).onReceivedCallQualityReport(call, quality);
1037     }
1038 
1039     @Test
1040     @SmallTest
testDiagnosticMessage()1041     public void testDiagnosticMessage() {
1042         Call.Listener listener = mock(Call.Listener.class);
1043         Call call = createCall("1");
1044         call.addListener(listener);
1045 
1046         final int id = 1;
1047         final String message = "msg";
1048 
1049         call.displayDiagnosticMessage(id, message);
1050         verify(listener).onConnectionEvent(
1051                 eq(call),
1052                 eq(android.telecom.Call.EVENT_DISPLAY_DIAGNOSTIC_MESSAGE),
1053                 argThat(extras -> {
1054                     return extras.getInt(android.telecom.Call.EXTRA_DIAGNOSTIC_MESSAGE_ID) == id &&
1055                             extras.getCharSequence(android.telecom.Call.EXTRA_DIAGNOSTIC_MESSAGE)
1056                                 .toString().equals(message);
1057                 }));
1058 
1059         call.clearDiagnosticMessage(id);
1060         verify(listener).onConnectionEvent(
1061                 eq(call),
1062                 eq(android.telecom.Call.EVENT_CLEAR_DIAGNOSTIC_MESSAGE),
1063                 argThat(extras -> {
1064                     return extras.getInt(android.telecom.Call.EXTRA_DIAGNOSTIC_MESSAGE_ID) == id;
1065                 }));
1066     }
1067 
1068     @Test
1069     @SmallTest
testExcludesInCallServiceFromDoNotLogCallExtra()1070     public void testExcludesInCallServiceFromDoNotLogCallExtra() {
1071         Call call = createCall("any");
1072         Bundle extra = new Bundle();
1073         extra.putBoolean(TelecomManager.EXTRA_DO_NOT_LOG_CALL, true);
1074 
1075         call.putInCallServiceExtras(extra, "packageName");
1076 
1077         assertFalse(call.getExtras().containsKey(TelecomManager.EXTRA_DO_NOT_LOG_CALL));
1078     }
1079 
1080     /**
1081      * Verify that a Call can handle a case where no telephony stack is present to detect emergency
1082      * numbers.
1083      */
1084     @Test
1085     @SmallTest
testNoTelephonyEmergencyBehavior()1086     public void testNoTelephonyEmergencyBehavior() {
1087         when(mComponentContextFixture.getTelephonyManager().isEmergencyNumber(any()))
1088                 .thenReturn(true);
1089         Call testCall = createCall("1", Call.CALL_DIRECTION_OUTGOING, Uri.parse("tel:911"));
1090         assertTrue(testCall.isEmergencyCall());
1091 
1092         when(mComponentContextFixture.getTelephonyManager().isEmergencyNumber(any()))
1093                 .thenThrow(new UnsupportedOperationException("Bee-boop"));
1094         Call testCall2 = createCall("2", Call.CALL_DIRECTION_OUTGOING, Uri.parse("tel:911"));
1095         assertTrue(!testCall2.isEmergencyCall());
1096     }
1097 
1098     @Test
1099     @SmallTest
testExcludesConnectionServiceWithoutModifyStatePermissionFromDoNotLogCallExtra()1100     public void testExcludesConnectionServiceWithoutModifyStatePermissionFromDoNotLogCallExtra() {
1101         PackageManager packageManager = mContext.getPackageManager();
1102         Bundle extra = new Bundle();
1103         extra.putBoolean(TelecomManager.EXTRA_DO_NOT_LOG_CALL, true);
1104         String packageName = SIM_1_HANDLE.getComponentName().getPackageName();
1105         doReturn(PackageManager.PERMISSION_DENIED)
1106                 .when(packageManager)
1107                 .checkPermission(android.Manifest.permission.MODIFY_PHONE_STATE, packageName);
1108         Call call = createCall("any");
1109 
1110         call.putConnectionServiceExtras(extra);
1111 
1112         assertFalse(call.getExtras().containsKey(TelecomManager.EXTRA_DO_NOT_LOG_CALL));
1113     }
1114 
1115     @Test
1116     @SmallTest
testDoesNotExcludeConnectionServiceWithModifyStatePermissionFromDoNotLogCallExtra()1117     public void testDoesNotExcludeConnectionServiceWithModifyStatePermissionFromDoNotLogCallExtra() {
1118         String packageName = SIM_1_HANDLE.getComponentName().getPackageName();
1119         Bundle extra = new Bundle();
1120         extra.putBoolean(TelecomManager.EXTRA_DO_NOT_LOG_CALL, true);
1121         PackageManager packageManager = mContext.getPackageManager();
1122         doReturn(PackageManager.PERMISSION_GRANTED)
1123                 .when(packageManager)
1124                 .checkPermission(android.Manifest.permission.MODIFY_PHONE_STATE, packageName);
1125         Call call = createCall("any");
1126 
1127         call.putConnectionServiceExtras(extra);
1128 
1129         assertTrue(call.getExtras().containsKey(TelecomManager.EXTRA_DO_NOT_LOG_CALL));
1130     }
1131 
1132     @Test
1133     @SmallTest
testSkipLoadingCannedTextResponse()1134     public void testSkipLoadingCannedTextResponse() {
1135         Call call = createCall("any");
1136         Resources mockResources = mContext.getResources();
1137         when(mockResources.getBoolean(R.bool.skip_loading_canned_text_response))
1138                 .thenReturn(true);
1139 
1140 
1141         assertFalse(call.isRespondViaSmsCapable());
1142     }
1143 
createCall(String id)1144     private Call createCall(String id) {
1145         return createCall(id, Call.CALL_DIRECTION_UNDEFINED);
1146     }
1147 
createCall(String id, int callDirection)1148     private Call createCall(String id, int callDirection) {
1149         return createCall(id, callDirection, TEST_ADDRESS);
1150     }
1151 
createCall(String id, int callDirection, Uri address)1152     private Call createCall(String id, int callDirection, Uri address) {
1153         return new Call(
1154                 id,
1155                 mContext,
1156                 mMockCallsManager,
1157                 mLock,
1158                 null,
1159                 mMockPhoneNumberUtilsAdapter,
1160                 address,
1161                 null /* GatewayInfo */,
1162                 null,
1163                 SIM_1_HANDLE,
1164                 callDirection,
1165                 false,
1166                 false,
1167                 mMockClockProxy,
1168                 mMockToastProxy,
1169                 mFeatureFlags);
1170     }
1171 }
1172