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