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.gsm;
18
19import static android.telephony.SmsManager.RESULT_ERROR_SHORT_CODE_NEVER_ALLOWED;
20
21import static com.android.internal.telephony.SmsUsageMonitor.CATEGORY_POSSIBLE_PREMIUM_SHORT_CODE;
22import static com.android.internal.telephony.SmsUsageMonitor.PREMIUM_SMS_PERMISSION_NEVER_ALLOW;
23import static com.android.internal.telephony.TelephonyTestUtils.waitForMs;
24
25import static org.junit.Assert.assertEquals;
26import static org.mockito.Matchers.any;
27import static org.mockito.Matchers.anyInt;
28import static org.mockito.Matchers.anyString;
29import static org.mockito.Mockito.doReturn;
30import static org.mockito.Mockito.times;
31import static org.mockito.Mockito.verify;
32import static org.mockito.Mockito.when;
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.location.Country;
41import android.location.CountryDetector;
42import android.os.HandlerThread;
43import android.os.Message;
44import android.os.SystemProperties;
45import android.provider.Settings;
46import android.provider.Telephony;
47import android.support.test.filters.FlakyTest;
48import android.telephony.SmsManager;
49import android.test.suitebuilder.annotation.MediumTest;
50import android.test.suitebuilder.annotation.SmallTest;
51import android.util.Singleton;
52
53import com.android.internal.telephony.ContextFixture;
54import com.android.internal.telephony.ISub;
55import com.android.internal.telephony.SMSDispatcher;
56import com.android.internal.telephony.SmsDispatchersController;
57import com.android.internal.telephony.TelephonyTest;
58import com.android.internal.telephony.TelephonyTestUtils;
59import com.android.internal.telephony.TestApplication;
60
61import org.junit.After;
62import org.junit.Before;
63import org.junit.Ignore;
64import org.junit.Test;
65import org.mockito.ArgumentCaptor;
66import org.mockito.Mock;
67
68import java.util.HashMap;
69
70public class GsmSmsDispatcherTest extends TelephonyTest {
71
72    private static final long TIMEOUT_MS = 500;
73
74    @Mock
75    private android.telephony.SmsMessage mSmsMessage;
76    @Mock
77    private SmsMessage mGsmSmsMessage;
78    @Mock
79    private SmsDispatchersController mSmsDispatchersController;
80    @Mock
81    private GsmInboundSmsHandler mGsmInboundSmsHandler;
82    @Mock
83    private CountryDetector mCountryDetector;
84    @Mock
85    private SMSDispatcher.SmsTracker mSmsTracker;
86    @Mock
87    private ISub.Stub mISubStub;
88    private Object mLock = new Object();
89    private boolean mReceivedTestIntent = false;
90    private static final String TEST_INTENT = "com.android.internal.telephony.TEST_INTENT";
91    private BroadcastReceiver mTestReceiver = new BroadcastReceiver() {
92        @Override
93        public void onReceive(Context context, Intent intent) {
94            logd("onReceive");
95            synchronized (mLock) {
96                mReceivedTestIntent = true;
97            }
98        }
99    };
100
101    private GsmSMSDispatcher mGsmSmsDispatcher;
102    private GsmSmsDispatcherTestHandler mGsmSmsDispatcherTestHandler;
103
104    private class GsmSmsDispatcherTestHandler extends HandlerThread {
105
106        private GsmSmsDispatcherTestHandler(String name) {
107            super(name);
108        }
109
110        @Override
111        public void onLooperPrepared() {
112            mGsmSmsDispatcher = new GsmSMSDispatcher(mPhone, mSmsDispatchersController,
113                    mGsmInboundSmsHandler);
114            setReady(true);
115        }
116    }
117
118    @Before
119    public void setUp() throws Exception {
120
121        super.setUp(getClass().getSimpleName());
122
123        // Note that this replaces only cached services in ServiceManager. If a service is not found
124        // in the cache, a real instance is used.
125        mServiceManagerMockedServices.put("isub", mISubStub);
126
127        doReturn(mSmsUsageMonitor).when(mSmsDispatchersController).getUsageMonitor();
128        mGsmSmsDispatcherTestHandler = new GsmSmsDispatcherTestHandler(getClass().getSimpleName());
129        mGsmSmsDispatcherTestHandler.start();
130        waitUntilReady();
131    }
132
133    @After
134    public void tearDown() throws Exception {
135        mGsmSmsDispatcher = null;
136        mGsmSmsDispatcherTestHandler.quit();
137        super.tearDown();
138    }
139
140    @Test @SmallTest
141    public void testSmsStatus() {
142        mSimulatedCommands.notifySmsStatus(new byte[]{(byte)0xFF, (byte)0xFF, (byte)0xFF});
143        TelephonyTestUtils.waitForMs(50);
144        verify(mSimulatedCommandsVerifier).acknowledgeLastIncomingGsmSms(true,
145                Telephony.Sms.Intents.RESULT_SMS_HANDLED, null);
146    }
147
148    @Test @MediumTest
149    public void testSendSmsToRegularNumber_doesNotNotifyblockedNumberProvider() throws Exception {
150        setupMockPackagePermissionChecks();
151
152        mContextFixture.setSystemService(Context.COUNTRY_DETECTOR, mCountryDetector);
153        when(mCountryDetector.detectCountry())
154                .thenReturn(new Country("US", Country.COUNTRY_SOURCE_SIM));
155
156        mGsmSmsDispatcher.sendText("6501002000", "121" /*scAddr*/, "test sms",
157                null, null, null, null, false, -1, false, -1);
158
159        verify(mSimulatedCommandsVerifier).sendSMS(anyString(), anyString(), any(Message.class));
160        // Blocked number provider is notified about the emergency contact asynchronously.
161        TelephonyTestUtils.waitForMs(50);
162        assertEquals(0, mFakeBlockedNumberContentProvider.mNumEmergencyContactNotifications);
163    }
164
165    @FlakyTest
166    @Ignore
167    @Test @MediumTest
168    public void testSendSmsToEmergencyNumber_notifiesBlockedNumberProvider() throws Exception {
169        setupMockPackagePermissionChecks();
170
171        mContextFixture.setSystemService(Context.COUNTRY_DETECTOR, mCountryDetector);
172        when(mCountryDetector.detectCountry())
173                .thenReturn(new Country("US", Country.COUNTRY_SOURCE_SIM));
174
175        mGsmSmsDispatcher.sendText(
176                getEmergencyNumberFromSystemPropertiesOrDefault(), "121" /*scAddr*/, "test sms",
177                null, null, null, null, false, -1, false, -1);
178
179        verify(mSimulatedCommandsVerifier).sendSMS(anyString(), anyString(), any(Message.class));
180        // Blocked number provider is notified about the emergency contact asynchronously.
181        TelephonyTestUtils.waitForMs(50);
182        assertEquals(1, mFakeBlockedNumberContentProvider.mNumEmergencyContactNotifications);
183    }
184
185    @Test @SmallTest
186    public void testSmsMessageValidityPeriod() throws Exception {
187        int vp;
188        vp = SmsMessage.getRelativeValidityPeriod(-5);
189        assertEquals(-1, vp);
190
191        vp = SmsMessage.getRelativeValidityPeriod(100);
192        assertEquals(100 / 5 - 1, vp);
193    }
194
195    private String getEmergencyNumberFromSystemPropertiesOrDefault() {
196        String systemEmergencyNumbers = SystemProperties.get("ril.ecclist");
197        if (systemEmergencyNumbers == null) {
198            return "911";
199        } else {
200            return systemEmergencyNumbers.split(",")[0];
201        }
202    }
203
204    @Test
205    @SmallTest
206    @FlakyTest
207    @Ignore
208    public void testSendTextWithInvalidDestAddr() throws Exception {
209        // unmock ActivityManager to be able to register receiver, create real PendingIntent and
210        // receive TEST_INTENT
211        restoreInstance(Singleton.class, "mInstance", mIActivityManagerSingleton);
212        restoreInstance(ActivityManager.class, "IActivityManagerSingleton", null);
213        Context realContext = TestApplication.getAppContext();
214        realContext.registerReceiver(mTestReceiver, new IntentFilter(TEST_INTENT));
215        PendingIntent pendingIntent = PendingIntent.getBroadcast(realContext, 0,
216                new Intent(TEST_INTENT), 0);
217        // send invalid dest address: +
218        mGsmSmsDispatcher.sendText("+", "222" /*scAddr*/, TAG,
219                pendingIntent, null, null, null, false, -1, false, -1);
220        waitForMs(500);
221        verify(mSimulatedCommandsVerifier, times(0)).sendSMS(anyString(), anyString(),
222                any(Message.class));
223        synchronized (mLock) {
224            assertEquals(true, mReceivedTestIntent);
225            assertEquals(SmsManager.RESULT_ERROR_NULL_PDU, mTestReceiver.getResultCode());
226        }
227    }
228
229    @Test
230    public void testSendRawPduWithEventStopSending() throws Exception {
231        setupMockPackagePermissionChecks();
232        mContextFixture.removeCallingOrSelfPermission(ContextFixture.PERMISSION_ENABLE_ALL);
233
234        // return a fake value to pass getData()
235        HashMap data = new HashMap<String, String>();
236        data.put("pdu", new byte[1]);
237        when(mSmsTracker.getData()).thenReturn(data);
238
239        // Set values to return to simulate EVENT_STOP_SENDING
240        when(mSmsUsageMonitor.checkDestination(any(), any()))
241                .thenReturn(CATEGORY_POSSIBLE_PREMIUM_SHORT_CODE);
242        when(mSmsUsageMonitor.getPremiumSmsPermission(any()))
243                .thenReturn(PREMIUM_SMS_PERMISSION_NEVER_ALLOW);
244        when(mSmsTracker.getAppPackageName()).thenReturn("");
245
246        // Settings.Global.DEVICE_PROVISIONED to 1
247        Settings.Global.putInt(mContext.getContentResolver(),
248                Settings.Global.DEVICE_PROVISIONED, 1);
249
250        mGsmSmsDispatcher.sendRawPdu(mSmsTracker);
251        waitForHandlerAction(mGsmSmsDispatcher, TIMEOUT_MS);
252
253        verify(mSmsUsageMonitor, times(1)).checkDestination(any(), any());
254        verify(mSmsUsageMonitor, times(1)).getPremiumSmsPermission(any());
255        ArgumentCaptor<Integer> argumentCaptor = ArgumentCaptor
256                .forClass(Integer.class);
257        verify(mSmsTracker, times(1)).onFailed(any(), argumentCaptor.capture(), anyInt());
258        assertEquals(RESULT_ERROR_SHORT_CODE_NEVER_ALLOWED, (int) argumentCaptor.getValue());
259    }
260}
261