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 */
16
17package com.android.internal.telephony;
18
19import static org.junit.Assert.assertEquals;
20import static org.junit.Assert.assertNull;
21import static org.junit.Assert.assertTrue;
22import static org.mockito.Matchers.any;
23import static org.mockito.Matchers.anyString;
24import static org.mockito.Matchers.isNull;
25import static org.mockito.Mockito.anyInt;
26import static org.mockito.Mockito.doReturn;
27import static org.mockito.Mockito.verify;
28import static org.mockito.Mockito.eq;
29import static org.mockito.Mockito.times;
30
31import android.app.ActivityManagerNative;
32import android.app.PendingIntent;
33import android.content.BroadcastReceiver;
34import android.content.Context;
35import android.content.Intent;
36import android.content.IntentFilter;
37import android.os.HandlerThread;
38import android.os.Message;
39import android.test.suitebuilder.annotation.SmallTest;
40import android.util.Singleton;
41
42import static com.android.internal.telephony.TelephonyTestUtils.waitForMs;
43
44import org.junit.After;
45import org.junit.Before;
46import org.junit.Test;
47import org.mockito.ArgumentCaptor;
48import org.mockito.Mock;
49
50public class ImsSMSDispatcherTest extends TelephonyTest {
51    @Mock
52    private SMSDispatcher.SmsTracker mTracker;
53
54    private ImsSMSDispatcher mImsSmsDispatcher;
55    private ImsSmsDispatcherTestHandler mImsSmsDispatcherTestHandler;
56    private boolean mReceivedTestIntent = false;
57    private Object mLock = new Object();
58    private static final String TEST_INTENT = "com.android.internal.telephony.TEST_INTENT";
59    private BroadcastReceiver mTestReceiver = new BroadcastReceiver() {
60        @Override
61        public void onReceive(Context context, Intent intent) {
62            logd("onReceive");
63            synchronized (mLock) {
64                mReceivedTestIntent = true;
65            }
66        }
67    };
68
69    private class ImsSmsDispatcherTestHandler extends HandlerThread {
70
71        private ImsSmsDispatcherTestHandler(String name) {
72            super(name);
73        }
74
75        @Override
76        public void onLooperPrepared() {
77            mImsSmsDispatcher = new ImsSMSDispatcher(mPhone, mSmsStorageMonitor,
78                    mSmsUsageMonitor);
79            //Initial state of RIL is power on, need to wait util RADIO_ON msg get handled
80            waitForMs(200);
81            setReady(true);
82        }
83    }
84
85    @Before
86    public void setUp() throws Exception {
87        super.setUp(getClass().getSimpleName());
88        setupMockPackagePermissionChecks();
89
90        mImsSmsDispatcherTestHandler = new ImsSmsDispatcherTestHandler(getClass().getSimpleName());
91        mImsSmsDispatcherTestHandler.start();
92        waitUntilReady();
93    }
94
95    @After
96    public void tearDown() throws Exception {
97        mImsSmsDispatcher = null;
98        mImsSmsDispatcherTestHandler.quitSafely();
99        super.tearDown();
100    }
101
102    @Test @SmallTest
103    public void testSmsHandleStateUpdate() throws Exception {
104        assertEquals(SmsConstants.FORMAT_UNKNOWN, mImsSmsDispatcher.getImsSmsFormat());
105        //Mock ImsNetWorkStateChange with GSM phone type
106        switchImsSmsFormat(PhoneConstants.PHONE_TYPE_GSM);
107        assertEquals(SmsConstants.FORMAT_3GPP, mImsSmsDispatcher.getImsSmsFormat());
108        assertTrue(mImsSmsDispatcher.isIms());
109
110        //Mock ImsNetWorkStateChange with Cdma Phone type
111        switchImsSmsFormat(PhoneConstants.PHONE_TYPE_CDMA);
112        assertEquals(SmsConstants.FORMAT_3GPP2, mImsSmsDispatcher.getImsSmsFormat());
113        assertTrue(mImsSmsDispatcher.isIms());
114    }
115
116    @Test @SmallTest
117    public void testSendImsGmsTest() throws Exception {
118        switchImsSmsFormat(PhoneConstants.PHONE_TYPE_GSM);
119        mImsSmsDispatcher.sendText("111"/* desAddr*/, "222" /*scAddr*/, TAG,
120                null, null, null, null, false);
121        verify(mSimulatedCommandsVerifier).sendImsGsmSms(eq("038122f2"),
122                eq("0100038111f1000014c9f67cda9c12d37378983e4697e5d4f29c0e"), eq(0), eq(0),
123                any(Message.class));
124    }
125
126    @Test @SmallTest
127    public void testSendImsGmsTestWithOutDesAddr() throws Exception {
128        switchImsSmsFormat(PhoneConstants.PHONE_TYPE_GSM);
129        mImsSmsDispatcher.sendText(null, "222" /*scAddr*/, TAG,
130                null, null, null, null, false);
131        verify(mSimulatedCommandsVerifier, times(0)).sendImsGsmSms(anyString(), anyString(),
132                anyInt(), anyInt(), any(Message.class));
133    }
134
135    @Test @SmallTest
136    public void testSendImsCdmaTest() throws Exception {
137        switchImsSmsFormat(PhoneConstants.PHONE_TYPE_CDMA);
138        mImsSmsDispatcher.sendText("111"/* desAddr*/, "222" /*scAddr*/, TAG,
139                null, null, null, null, false);
140        verify(mSimulatedCommandsVerifier).sendImsCdmaSms((byte[])any(), eq(0), eq(0),
141                any(Message.class));
142    }
143
144    @Test @SmallTest
145    public void testSendRetrySmsCdmaTest() throws Exception {
146        // newFormat will be based on voice technology
147        ArgumentCaptor<byte[]> captor = ArgumentCaptor.forClass(byte[].class);
148        switchImsSmsFormat(PhoneConstants.PHONE_TYPE_CDMA);
149        replaceInstance(SMSDispatcher.SmsTracker.class, "mFormat", mTracker,
150                SmsConstants.FORMAT_3GPP2);
151        doReturn(PhoneConstants.PHONE_TYPE_CDMA).when(mPhone).getPhoneType();
152        mImsSmsDispatcher.sendRetrySms(mTracker);
153        verify(mSimulatedCommandsVerifier).sendImsCdmaSms(captor.capture(), eq(0), eq(0),
154                any(Message.class));
155        assertEquals(1, captor.getAllValues().size());
156        assertNull(captor.getAllValues().get(0));
157    }
158
159    @Test @SmallTest
160    public void testSendRetrySmsGsmTest() throws Exception {
161        // newFormat will be based on voice technology will be GSM if phone type is not CDMA
162        switchImsSmsFormat(PhoneConstants.PHONE_TYPE_GSM);
163        replaceInstance(SMSDispatcher.SmsTracker.class, "mFormat", mTracker,
164                SmsConstants.FORMAT_3GPP);
165        mImsSmsDispatcher.sendRetrySms(mTracker);
166        verify(mSimulatedCommandsVerifier).sendImsGsmSms((String)isNull(), (String)isNull(), eq(0),
167                eq(0), any(Message.class));
168    }
169
170    @Test @SmallTest
171    public void testInjectNullSmsPdu() throws Exception {
172        // unmock ActivityManager to be able to register receiver, create real PendingIntent and
173        // receive TEST_INTENT
174        restoreInstance(Singleton.class, "mInstance", mIActivityManagerSingleton);
175        restoreInstance(ActivityManagerNative.class, "gDefault", null);
176
177        Context realContext = TestApplication.getAppContext();
178        realContext.registerReceiver(mTestReceiver, new IntentFilter(TEST_INTENT));
179
180        PendingIntent pendingIntent = PendingIntent.getBroadcast(realContext, 0,
181                new Intent(TEST_INTENT), 0);
182
183        // inject null sms pdu. This should cause intent to be received since pdu is null.
184        mImsSmsDispatcher.injectSmsPdu(null, SmsConstants.FORMAT_3GPP, pendingIntent);
185        waitForMs(100);
186        synchronized (mLock) {
187            assertEquals(true, mReceivedTestIntent);
188        }
189    }
190
191    private void switchImsSmsFormat(int phoneType) {
192        mSimulatedCommands.setImsRegistrationState(new int[]{1, phoneType});
193        mSimulatedCommands.notifyImsNetworkStateChanged();
194        /* wait for async msg get handled */
195        waitForMs(200);
196    }
197}