1/*
2 * Copyright (C) 2016 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 */
16package com.android.internal.telephony;
17
18import android.os.HandlerThread;
19import android.os.SystemProperties;
20import android.telephony.DisconnectCause;
21import android.telephony.PhoneNumberUtils;
22import android.telephony.ServiceState;
23import android.test.suitebuilder.annotation.SmallTest;
24
25import com.android.internal.telephony.test.SimulatedCommandsVerifier;
26import android.os.Message;
27import org.junit.After;
28import org.junit.Assert;
29import org.junit.Before;
30import org.junit.Test;
31import org.mockito.Mock;
32import org.mockito.ArgumentCaptor;
33import android.os.Handler;
34
35import static org.junit.Assert.assertFalse;
36import static org.junit.Assert.assertNotNull;
37import static org.junit.Assert.assertTrue;
38import static org.mockito.Mockito.doReturn;
39import static org.junit.Assert.assertEquals;
40import static org.mockito.Mockito.*;
41import static com.android.internal.telephony.TelephonyTestUtils.waitForMs;
42
43
44public class GsmCdmaCallTrackerTest extends TelephonyTest {
45    private static final int VOICE_CALL_STARTED_EVENT = 0;
46    private static final int VOICE_CALL_ENDED_EVENT = 1;
47    private String mDialString = PhoneNumberUtils.stripSeparators("+17005554141");
48    /* Handler class initiated at the HandlerThread */
49    private GsmCdmaCallTracker mCTUT;
50    @Mock
51    GsmCdmaCall mCall;
52    @Mock
53    private Handler mHandler;
54
55    private class GsmCdmaCTHandlerThread extends HandlerThread {
56
57        private GsmCdmaCTHandlerThread(String name) {
58            super(name);
59        }
60        @Override
61        public void onLooperPrepared() {
62            mCTUT = new GsmCdmaCallTracker(mPhone);
63            setReady(true);
64        }
65    }
66
67    @Before
68    public void setUp() throws Exception {
69        super.setUp(this.getClass().getSimpleName());
70        mSimulatedCommands.setRadioPower(true, null);
71        mPhone.mCi = this.mSimulatedCommands;
72        mContextFixture.putStringArrayResource(com.android.internal.R.array.dial_string_replace,
73                new String[]{});
74
75        new GsmCdmaCTHandlerThread(TAG).start();
76
77        waitUntilReady();
78        logd("GsmCdmaCallTracker initiated, waiting for Power on");
79        /* Make sure radio state is power on before dial.
80         * When radio state changed from off to on, CallTracker
81         * will poll result from RIL. Avoid dialing triggered at the same*/
82        waitForMs(100);
83    }
84
85    @After
86    public void tearDown() throws Exception {
87        mCTUT = null;
88        super.tearDown();
89    }
90
91    @Test
92    @SmallTest
93    public void testMOCallDial() {
94        doReturn(ServiceState.STATE_IN_SERVICE).when(mServiceState).getState();
95        assertEquals(PhoneConstants.State.IDLE, mCTUT.getState());
96        assertEquals(GsmCdmaCall.State.IDLE, mCTUT.mForegroundCall.getState());
97        assertEquals(GsmCdmaCall.State.IDLE, mCTUT.mBackgroundCall.getState());
98        assertEquals(0, mCTUT.mForegroundCall.getConnections().size());
99        try {
100            mCTUT.dial(mDialString);
101        } catch(Exception ex) {
102            ex.printStackTrace();
103            Assert.fail("unexpected exception thrown"+ex.getMessage()+ex.getStackTrace());
104        }
105
106        assertEquals(PhoneConstants.State.OFFHOOK, mCTUT.getState());
107        assertEquals(GsmCdmaCall.State.DIALING, mCTUT.mForegroundCall.getState());
108        assertEquals(1, mCTUT.mForegroundCall.getConnections().size());
109        /* verify the command is sent out to RIL */
110        verify(mSimulatedCommandsVerifier).dial(eq(PhoneNumberUtils.
111                        extractNetworkPortionAlt(mDialString)), anyInt(),
112                eq((UUSInfo) null),
113                isA(Message.class));
114    }
115
116    @Test
117    @SmallTest
118    public void testMOCallPickUp() {
119        testMOCallDial();
120        logd("Waiting for POLL CALL response from RIL");
121        TelephonyTestUtils.waitForMs(50);
122        logd("Pick Up MO call, expecting call state change event ");
123        mSimulatedCommands.progressConnectingToActive();
124        waitForMs(100);
125        assertEquals(GsmCdmaCall.State.ACTIVE, mCTUT.mForegroundCall.getState());
126        assertEquals(GsmCdmaCall.State.IDLE, mCTUT.mBackgroundCall.getState());
127    }
128
129    @Test
130    @SmallTest
131    public void testMOCallHangup() {
132        testMOCallDial();
133        logd("Waiting for POLL CALL response from RIL ");
134        TelephonyTestUtils.waitForMs(50);
135        assertEquals(GsmCdmaCall.State.DIALING, mCTUT.mForegroundCall.getState());
136        assertEquals(PhoneConstants.State.OFFHOOK, mCTUT.getState());
137        assertEquals(1, mCTUT.mForegroundCall.getConnections().size());
138        logd("Hang up MO call after MO call established ");
139        try {
140            mCTUT.hangup(mCTUT.mForegroundCall);
141        } catch(Exception ex) {
142            ex.printStackTrace();
143            Assert.fail("unexpected exception thrown" + ex.getMessage());
144        }
145        waitForMs(200);
146        assertEquals(GsmCdmaCall.State.IDLE, mCTUT.mForegroundCall.getState());
147        assertEquals(0, mCTUT.mForegroundCall.getConnections().size());
148        assertEquals(PhoneConstants.State.IDLE, mCTUT.getState());
149    }
150
151    @Test
152    @SmallTest
153    public void testMOCallDialPickUpHangup() {
154        testMOCallPickUp();
155        assertEquals(GsmCdmaCall.State.ACTIVE, mCTUT.mForegroundCall.getState());
156        assertEquals(PhoneConstants.State.OFFHOOK, mCTUT.getState());
157        assertEquals(1, mCTUT.mForegroundCall.getConnections().size());
158         /* get the reference of the connection before reject */
159        Connection mConnection = mCTUT.mForegroundCall.getConnections().get(0);
160        assertEquals(DisconnectCause.NOT_DISCONNECTED, mConnection.getDisconnectCause());
161        logd("hang up MO call after pickup");
162        try {
163            mCTUT.hangup(mCTUT.mForegroundCall);
164        } catch(Exception ex) {
165            ex.printStackTrace();
166            Assert.fail("unexpected exception thrown" + ex.getMessage());
167        }
168        /* request send to RIL still in disconnecting state */
169        waitForMs(200);
170        assertEquals(GsmCdmaCall.State.IDLE, mCTUT.mForegroundCall.getState());
171        assertEquals(0, mCTUT.mForegroundCall.getConnections().size());
172        assertEquals(PhoneConstants.State.IDLE, mCTUT.getState());
173        assertEquals(DisconnectCause.LOCAL, mConnection.getDisconnectCause());
174
175    }
176
177    @Test
178    @SmallTest
179    public void testMOCallPendingHangUp() {
180        testMOCallDial();
181        logd("MO call hangup before established[ getting result from RIL ]");
182        /* poll call result from RIL, find that there is a pendingMO call,
183         * Didn't do anything for hangup, clear during handle poll result */
184        try {
185            mCTUT.hangup(mCTUT.mForegroundCall);
186        } catch(Exception ex) {
187            ex.printStackTrace();
188            Assert.fail("unexpected exception thrown" + ex.getMessage());
189        }
190        waitForMs(200);
191        assertEquals(GsmCdmaCall.State.IDLE, mCTUT.mForegroundCall.getState());
192        assertEquals(0, mCTUT.mForegroundCall.getConnections().size());
193        assertEquals(PhoneConstants.State.IDLE, mCTUT.getState());
194    }
195
196    @Test
197    @SmallTest
198    public void testMOCallSwitch() {
199        testMOCallPickUp();
200        logd("MO call picked up, initiating a new MO call");
201        assertEquals(GsmCdmaCall.State.ACTIVE, mCTUT.mForegroundCall.getState());
202        assertEquals(GsmCdmaCall.State.IDLE, mCTUT.mBackgroundCall.getState());
203        assertEquals(1, mCTUT.mForegroundCall.getConnections().size());
204        assertEquals(0, mCTUT.mBackgroundCall.getConnections().size());
205
206        String mDialString = PhoneNumberUtils.stripSeparators("+17005554142");
207        try {
208            mCTUT.dial(mDialString);
209        } catch(Exception ex) {
210            ex.printStackTrace();
211            Assert.fail("unexpected exception thrown" + ex.getMessage());
212        }
213        waitForMs(200);
214        assertEquals(GsmCdmaCall.State.DIALING, mCTUT.mForegroundCall.getState());
215        assertEquals(GsmCdmaCall.State.HOLDING, mCTUT.mBackgroundCall.getState());
216        assertEquals(1, mCTUT.mForegroundCall.getConnections().size());
217        assertEquals(1, mCTUT.mBackgroundCall.getConnections().size());
218
219    }
220
221    @Test
222    @SmallTest
223    public void testMTCallRinging() {
224        /* Mock there is a MT call mRinging call and try to accept this MT call */
225        /* if we got a active state followed by another MT call-> move to background call */
226        assertEquals(PhoneConstants.State.IDLE, mCTUT.getState());
227        assertEquals(0, mCTUT.mRingingCall.getConnections().size());
228        assertEquals(GsmCdmaCall.State.IDLE, mCTUT.mForegroundCall.getState());
229        String mDialString = PhoneNumberUtils.stripSeparators("+17005554141");
230        logd("MT call Ringing");
231        mSimulatedCommands.triggerRing(mDialString);
232        waitForMs(50);
233        assertEquals(PhoneConstants.State.RINGING, mCTUT.getState());
234        assertEquals(1, mCTUT.mRingingCall.getConnections().size());
235    }
236
237    @Test
238    @SmallTest
239    public void testMTCallAccept() {
240        testMTCallRinging();
241        assertEquals(mCTUT.mForegroundCall.getConnections().size(),0);
242        logd("accept the MT call");
243        try{
244            mCTUT.acceptCall();
245        } catch(Exception ex) {
246            ex.printStackTrace();
247            Assert.fail("unexpected exception thrown" + ex.getMessage());
248        }
249        verify(mSimulatedCommandsVerifier).acceptCall(isA(Message.class));
250        /* send to the RIL */
251        TelephonyTestUtils.waitForMs(50);
252        assertEquals(PhoneConstants.State.OFFHOOK, mCTUT.getState());
253        assertEquals(GsmCdmaCall.State.ACTIVE, mCTUT.mForegroundCall.getState());
254        assertEquals(1, mCTUT.mForegroundCall.getConnections().size());
255        assertEquals(0, mCTUT.mRingingCall.getConnections().size());
256    }
257
258    @Test
259    @SmallTest
260    public void testMTCallReject() {
261        testMTCallRinging();
262        logd("MT call ringing and rejected ");
263        /* get the reference of the connection before reject */
264        Connection mConnection = mCTUT.mRingingCall.getConnections().get(0);
265        assertNotNull(mConnection);
266        assertEquals(DisconnectCause.NOT_DISCONNECTED, mConnection.getDisconnectCause());
267        try {
268            mCTUT.rejectCall();
269        } catch(Exception ex) {
270            ex.printStackTrace();
271            Assert.fail("unexpected exception thrown" + ex.getMessage());
272        }
273        waitForMs(50);
274        assertEquals(PhoneConstants.State.IDLE, mCTUT.getState());
275        assertEquals(GsmCdmaCall.State.IDLE, mCTUT.mForegroundCall.getState());
276        assertEquals(0, mCTUT.mForegroundCall.getConnections().size());
277        /* ? why rejectCall didnt -> hang up locally to set the cause to LOCAL? */
278        assertEquals(DisconnectCause.INCOMING_MISSED, mConnection.getDisconnectCause());
279
280    }
281
282    @Test
283    @SmallTest
284    public void testMOCallSwitchHangupForeGround() {
285        testMOCallSwitch();
286        logd("Hang up the foreground MO call while dialing ");
287        try {
288            mCTUT.hangup(mCTUT.mForegroundCall);
289        } catch(Exception ex) {
290            ex.printStackTrace();
291            Assert.fail("unexpected exception thrown" + ex.getMessage());
292        }
293        waitForMs(200);
294        logd(" Foreground Call is IDLE and BackGround Call is still HOLDING ");
295        /* if we want to hang up foreground call which is alerting state, hangup all */
296        assertEquals(GsmCdmaCall.State.IDLE, mCTUT.mForegroundCall.getState());
297        assertEquals(GsmCdmaCall.State.HOLDING, mCTUT.mBackgroundCall.getState());
298    }
299
300    @Test
301    @SmallTest
302    public void testMOCallPickUpHangUpResumeBackGround() {
303        testMOCallSwitch();
304        logd("Pick up the new MO Call");
305        try{
306            mSimulatedCommands.progressConnectingToActive();
307        } catch(Exception ex) {
308            ex.printStackTrace();
309            Assert.fail("unexpected exception thrown" + ex.getMessage());
310        }
311
312        waitForMs(200);
313        assertEquals(GsmCdmaCall.State.ACTIVE, mCTUT.mForegroundCall.getState());
314        assertEquals(GsmCdmaCall.State.HOLDING, mCTUT.mBackgroundCall.getState());
315
316        logd("Hang up the new MO Call");
317        try {
318            mCTUT.hangup(mCTUT.mForegroundCall);
319        } catch(Exception ex) {
320            ex.printStackTrace();
321            Assert.fail("unexpected exception thrown" + ex.getMessage());
322        }
323
324        waitForMs(200);
325        logd(" BackGround Call switch to ForeGround Call ");
326        assertEquals(GsmCdmaCall.State.ACTIVE, mCTUT.mForegroundCall.getState());
327        assertEquals(GsmCdmaCall.State.IDLE, mCTUT.mBackgroundCall.getState());
328    }
329
330    @Test @SmallTest
331    public void testVoiceCallStartListener(){
332        logd("register for voice call started event");
333        mCTUT.registerForVoiceCallStarted(mHandler, VOICE_CALL_STARTED_EVENT, null);
334        logd("voice call started");
335        testMOCallPickUp();
336        ArgumentCaptor<Message> mCaptorMessage = ArgumentCaptor.forClass(Message.class);
337        ArgumentCaptor<Long> mCaptorLong = ArgumentCaptor.forClass(Long.class);
338        verify(mHandler,times(1)).sendMessageAtTime(mCaptorMessage.capture(), mCaptorLong.capture());
339        assertEquals(VOICE_CALL_STARTED_EVENT, mCaptorMessage.getValue().what);
340
341    }
342
343    @Test @SmallTest
344    public void testVoiceCallEndedListener(){
345        logd("register for voice call ended event");
346        mCTUT.registerForVoiceCallEnded(mHandler, VOICE_CALL_ENDED_EVENT, null);
347        ArgumentCaptor<Message> mCaptorMessage = ArgumentCaptor.forClass(Message.class);
348        ArgumentCaptor<Long> mCaptorLong = ArgumentCaptor.forClass(Long.class);
349        testMOCallHangup();
350        verify(mHandler,times(1)).sendMessageAtTime(mCaptorMessage.capture(), mCaptorLong.capture());
351        assertEquals(VOICE_CALL_ENDED_EVENT, mCaptorMessage.getValue().what);
352    }
353
354    @Test @SmallTest
355    public void testUpdatePhoneType() {
356        // verify getCurrentCalls is called on init
357        verify(mSimulatedCommandsVerifier).getCurrentCalls(any(Message.class));
358
359        // update phone type
360        mCTUT.updatePhoneType();
361
362        // verify getCurrentCalls is called on updating phone type
363        verify(mSimulatedCommandsVerifier, times(2)).getCurrentCalls(any(Message.class));
364    }
365}
366
367