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.imsphone;
17
18import android.os.AsyncResult;
19import android.os.Bundle;
20import android.os.Handler;
21import android.os.Looper;
22import android.os.Message;
23import android.telephony.DisconnectCause;
24import android.telephony.PhoneNumberUtils;
25import android.telephony.ServiceState;
26import android.test.suitebuilder.annotation.MediumTest;
27import android.test.suitebuilder.annotation.SmallTest;
28
29import com.android.ims.ImsCallProfile;
30import com.android.internal.telephony.Call;
31import com.android.internal.telephony.Connection;
32import com.android.internal.telephony.GsmCdmaCall;
33import com.android.internal.telephony.PhoneConstants;
34import com.android.internal.telephony.TelephonyTest;
35
36import org.junit.After;
37import org.junit.Assert;
38import org.junit.Before;
39import org.junit.Test;
40import org.mockito.Mock;
41import org.mockito.invocation.InvocationOnMock;
42import org.mockito.stubbing.Answer;
43
44import java.lang.reflect.Field;
45
46import static com.android.internal.telephony.TelephonyTestUtils.waitForMs;
47import static org.junit.Assert.assertEquals;
48import static org.junit.Assert.assertFalse;
49import static org.junit.Assert.assertNull;
50import static org.junit.Assert.assertTrue;
51import static org.mockito.Mockito.any;
52import static org.mockito.Mockito.anyChar;
53import static org.mockito.Mockito.doAnswer;
54import static org.mockito.Mockito.doReturn;
55import static org.mockito.Mockito.eq;
56import static org.mockito.Mockito.times;
57import static org.mockito.Mockito.verify;
58
59public class ImsPhoneConnectionTest extends TelephonyTest {
60    private ImsPhoneConnection mConnectionUT;
61    private Bundle mBundle = new Bundle();
62    @Mock
63    private ImsPhoneCall mForeGroundCall;
64    @Mock
65    private ImsPhoneCall mBackGroundCall;
66    @Mock
67    private ImsPhoneCall mRingGroundCall;
68
69    @Before
70    public void setUp() throws Exception {
71        super.setUp(getClass().getSimpleName());
72        replaceInstance(Handler.class, "mLooper", mImsCT, Looper.getMainLooper());
73        replaceInstance(ImsPhoneCallTracker.class, "mForegroundCall", mImsCT, mForeGroundCall);
74        replaceInstance(ImsPhoneCallTracker.class, "mBackgroundCall", mImsCT, mBackGroundCall);
75        replaceInstance(ImsPhoneCallTracker.class, "mRingingCall", mImsCT, mRingGroundCall);
76        replaceInstance(ImsPhoneCallTracker.class, "mPhone", mImsCT, mImsPhone);
77
78        mImsCallProfile.mCallExtras = mBundle;
79        doReturn(ImsPhoneCall.State.IDLE).when(mForeGroundCall).getState();
80    }
81
82    @After
83    public void tearDown() throws Exception {
84        super.tearDown();
85    }
86
87    @Test
88    @SmallTest
89    public void testImsConnectionSanity() {
90        logd("Testing initial state of MT ImsPhoneConnection");
91        mConnectionUT = new ImsPhoneConnection(mImsPhone, mImsCall, mImsCT, mForeGroundCall, false);
92
93        assertEquals(ImsPhoneCall.State.IDLE, mConnectionUT.getState());
94        assertEquals(PhoneConstants.PRESENTATION_UNKNOWN, mConnectionUT.getNumberPresentation());
95        assertEquals(PhoneConstants.PRESENTATION_UNKNOWN, mConnectionUT.getCnapNamePresentation());
96        assertEquals(Connection.PostDialState.NOT_STARTED, mConnectionUT.getPostDialState());
97        assertEquals(0, mConnectionUT.getDisconnectTime());
98        assertEquals(0, mConnectionUT.getHoldDurationMillis());
99        assertNull(mConnectionUT.getOrigDialString());
100        assertFalse(mConnectionUT.isMultiparty());
101        assertFalse(mConnectionUT.isConferenceHost());
102        verify(mForeGroundCall, times(1)).attach((Connection) any(),
103                eq(ImsPhoneCall.State.INCOMING));
104
105        logd("Testing initial state of MO ImsPhoneConnection");
106        mConnectionUT = new ImsPhoneConnection(mImsPhone, String.format("+1 (700).555-41NN%c1234",
107                PhoneNumberUtils.PAUSE), mImsCT, mForeGroundCall, false);
108        assertEquals(PhoneConstants.PRESENTATION_ALLOWED, mConnectionUT.getNumberPresentation());
109        assertEquals(PhoneConstants.PRESENTATION_ALLOWED, mConnectionUT.getCnapNamePresentation());
110        assertEquals("+1 (700).555-41NN,1234", mConnectionUT.getOrigDialString());
111        verify(mForeGroundCall, times(1)).attachFake((Connection) any(),
112                eq(ImsPhoneCall.State.DIALING));
113    }
114
115    @Test
116    @SmallTest
117    public void testImsUpdateStateForeGround() {
118        // MO Foreground Connection dailing -> active
119        mConnectionUT = new ImsPhoneConnection(mImsPhone, "+1 (700).555-41NN1234", mImsCT,
120                mForeGroundCall, false);
121        // initially in dialing state
122        doReturn(Call.State.DIALING).when(mForeGroundCall).getState();
123        assertTrue(mConnectionUT.update(mImsCall, Call.State.ACTIVE));
124        // for Ringing/Dialing upadte postDialState
125        assertEquals(Connection.PostDialState.COMPLETE, mConnectionUT.getPostDialState());
126        verify(mForeGroundCall, times(1)).update(eq(mConnectionUT), eq(mImsCall),
127                eq(Call.State.ACTIVE));
128    }
129
130    @Test
131    @SmallTest
132    public void testImsUpdateStateBackGround() {
133        // MT background Connection dialing -> active
134        mConnectionUT = new ImsPhoneConnection(mImsPhone, mImsCall, mImsCT, mBackGroundCall, false);
135        doReturn(Call.State.HOLDING).when(mBackGroundCall).getState();
136        assertTrue(mConnectionUT.update(mImsCall, Call.State.ACTIVE));
137        verify(mBackGroundCall, times(1)).detach(eq(mConnectionUT));
138        verify(mForeGroundCall, times(1)).attach(eq(mConnectionUT));
139        verify(mForeGroundCall, times(1)).update(eq(mConnectionUT), eq(mImsCall),
140                eq(Call.State.ACTIVE));
141        assertEquals(Connection.PostDialState.NOT_STARTED, mConnectionUT.getPostDialState());
142    }
143
144    @Test
145    @SmallTest
146    public void testImsUpdateStatePendingHold() {
147        mConnectionUT = new ImsPhoneConnection(mImsPhone, "+1 (700).555-41NN1234", mImsCT,
148                mForeGroundCall, false);
149        doReturn(true).when(mImsCall).isPendingHold();
150        assertFalse(mConnectionUT.update(mImsCall, Call.State.ACTIVE));
151        verify(mForeGroundCall, times(0)).update(eq(mConnectionUT), eq(mImsCall),
152                eq(Call.State.ACTIVE));
153        assertEquals(Connection.PostDialState.NOT_STARTED, mConnectionUT.getPostDialState());
154    }
155
156    @Test
157    @SmallTest
158    public void testUpdateAddressDisplay() {
159        mConnectionUT = new ImsPhoneConnection(mImsPhone, mImsCall, mImsCT, mForeGroundCall, false);
160        assertEquals(PhoneConstants.PRESENTATION_UNKNOWN, mConnectionUT.getNumberPresentation());
161        assertEquals(PhoneConstants.PRESENTATION_UNKNOWN, mConnectionUT.getCnapNamePresentation());
162        doReturn(ImsCallProfile.OIR_PRESENTATION_PAYPHONE).when(mImsCallProfile)
163                .getCallExtraInt(eq(ImsCallProfile.EXTRA_CNAP));
164        doReturn(ImsCallProfile.OIR_PRESENTATION_NOT_RESTRICTED).when(mImsCallProfile)
165                .getCallExtraInt(eq(ImsCallProfile.EXTRA_OIR));
166
167        mConnectionUT.updateAddressDisplay(mImsCall);
168        assertEquals(ImsCallProfile.OIRToPresentation(ImsCallProfile.OIR_PRESENTATION_PAYPHONE),
169                mConnectionUT.getCnapNamePresentation());
170        assertEquals(ImsCallProfile.OIRToPresentation(
171                        ImsCallProfile.OIR_PRESENTATION_NOT_RESTRICTED),
172                mConnectionUT.getNumberPresentation());
173    }
174
175    @Test
176    @SmallTest
177    public void testConnectionDisconnect() {
178        //Mock we have an active connection
179        testImsUpdateStateForeGround();
180        waitForMs(50);
181        mConnectionUT.onDisconnect(DisconnectCause.LOCAL);
182        assertEquals(DisconnectCause.LOCAL, mConnectionUT.getDisconnectCause());
183        assertEquals(GsmCdmaCall.State.DISCONNECTED, mConnectionUT.getState());
184        assertTrue(mConnectionUT.getDisconnectTime() <= System.currentTimeMillis());
185        assertTrue(mConnectionUT.getDurationMillis() >= 50);
186    }
187
188    @Test
189    @SmallTest
190    public void testPostDialWait() {
191        mConnectionUT = new ImsPhoneConnection(mImsPhone, String.format("+1 (700).555-41NN%c1234",
192                PhoneNumberUtils.WAIT), mImsCT, mForeGroundCall, false);
193        doReturn(Call.State.DIALING).when(mForeGroundCall).getState();
194        doAnswer(new Answer() {
195            @Override
196            public Void answer(InvocationOnMock invocation) throws Throwable {
197                Message msg = (Message) invocation.getArguments()[1];
198                AsyncResult.forMessage(msg);
199                msg.sendToTarget();
200                return  null;
201            }
202        }).when(mImsCT).sendDtmf(anyChar(), (Message) any());
203        // process post dial string during update
204        assertTrue(mConnectionUT.update(mImsCall, Call.State.ACTIVE));
205        assertEquals(Connection.PostDialState.WAIT, mConnectionUT.getPostDialState());
206        mConnectionUT.proceedAfterWaitChar();
207        waitForMs(50);
208        assertEquals(Connection.PostDialState.COMPLETE, mConnectionUT.getPostDialState());
209    }
210
211    @Test
212    @MediumTest
213    public void testPostDialPause() {
214        mConnectionUT = new ImsPhoneConnection(mImsPhone, String.format("+1 (700).555-41NN%c1234",
215                PhoneNumberUtils.PAUSE), mImsCT, mForeGroundCall, false);
216        doReturn(Call.State.DIALING).when(mForeGroundCall).getState();
217        doAnswer(new Answer() {
218            @Override
219            public Void answer(InvocationOnMock invocation) throws Throwable {
220                Message msg = (Message) invocation.getArguments()[1];
221                AsyncResult.forMessage(msg);
222                msg.sendToTarget();
223                return null;
224            }
225        }).when(mImsCT).sendDtmf(anyChar(), (Message) any());
226
227        // process post dial string during update
228        assertTrue(mConnectionUT.update(mImsCall, Call.State.ACTIVE));
229        assertEquals(Connection.PostDialState.STARTED, mConnectionUT.getPostDialState());
230        try {
231            Field field = ImsPhoneConnection.class.getDeclaredField("PAUSE_DELAY_MILLIS");
232            field.setAccessible(true);
233            waitForMs((Integer) field.get(null) + 50);
234        } catch (Exception ex) {
235            Assert.fail("unexpected exception thrown" + ex.getMessage());
236        }
237        assertEquals(Connection.PostDialState.COMPLETE, mConnectionUT.getPostDialState());
238    }
239
240    @Test
241    @SmallTest
242    public void testSetWifi() {
243        mConnectionUT = new ImsPhoneConnection(mImsPhone, mImsCall, mImsCT, mForeGroundCall, false);
244        assertFalse(mConnectionUT.isWifi());
245        // ImsCall.isWifiCall is tested elsewhere
246        doReturn(true).when(mImsCall).isWifiCall();
247        mBundle.putString(ImsCallProfile.EXTRA_CALL_RAT_TYPE,
248                ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN + "");
249        assertTrue(mConnectionUT.update(mImsCall, Call.State.ACTIVE));
250        assertTrue(mConnectionUT.isWifi());
251        //keep using the wifi state from extra, not update
252        assertFalse(mConnectionUT.updateWifiState());
253    }
254
255    @Test
256    @SmallTest
257    public void testSetWifi2() {
258        mConnectionUT = new ImsPhoneConnection(mImsPhone, mImsCall, mImsCT, mForeGroundCall, false);
259        assertFalse(mConnectionUT.isWifi());
260        // ImsCall.isWifiCall is tested elsewhere
261        doReturn(true).when(mImsCall).isWifiCall();
262        // Tests to make sure that the EXTRA_CALL_RAT_TYPE_ALT string is set correctly for newer
263        // devices.
264        mBundle.putString(ImsCallProfile.EXTRA_CALL_RAT_TYPE_ALT,
265                ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN + "");
266        assertTrue(mConnectionUT.update(mImsCall, Call.State.ACTIVE));
267        assertTrue(mConnectionUT.isWifi());
268        //keep using the wifi state from extra, not update
269        assertFalse(mConnectionUT.updateWifiState());
270    }
271}
272