/* * Copyright (C) 2016 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.internal.telephony.cdma; import android.content.ContentValues; import android.content.Context; import android.content.Intent; import android.os.AsyncResult; import android.os.HandlerThread; import android.os.RemoteException; import android.os.UserHandle; import android.os.UserManager; import android.platform.test.annotations.Postsubmit; import android.provider.Telephony; import android.test.mock.MockContentResolver; import android.test.suitebuilder.annotation.MediumTest; import com.android.internal.telephony.FakeSmsContentProvider; import com.android.internal.telephony.InboundSmsHandler; import com.android.internal.telephony.SmsStorageMonitor; import com.android.internal.telephony.TelephonyTest; import com.android.internal.telephony.cdma.sms.SmsEnvelope; import com.android.internal.util.HexDump; import com.android.internal.util.IState; import com.android.internal.util.StateMachine; import com.android.internal.util.HexDump; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.mockito.ArgumentCaptor; import org.mockito.Mock; import java.lang.reflect.Field; import java.lang.reflect.Method; import static com.android.internal.telephony.TelephonyTestUtils.waitForMs; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.fail; import static org.mockito.Matchers.any; import static org.mockito.Mockito.anyBoolean; import static org.mockito.Mockito.anyInt; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; public class CdmaInboundSmsHandlerTest extends TelephonyTest { @Mock private SmsStorageMonitor mSmsStorageMonitor; @Mock private android.telephony.SmsMessage mSmsMessage; @Mock private SmsMessage mCdmaSmsMessage; private CdmaInboundSmsHandler mCdmaInboundSmsHandler; private CdmaInboundSmsHandlerTestHandler mCdmaInboundSmsHandlerTestHandler; private SmsEnvelope mSmsEnvelope = new SmsEnvelope(); private ContentValues mInboundSmsTrackerCV = new ContentValues(); private FakeSmsContentProvider mContentProvider; private class CdmaInboundSmsHandlerTestHandler extends HandlerThread { private CdmaInboundSmsHandlerTestHandler(String name) { super(name); } @Override public void onLooperPrepared() { mCdmaInboundSmsHandler = CdmaInboundSmsHandler.makeInboundSmsHandler(mContext, mSmsStorageMonitor, mPhone, null); setReady(true); } } private IState getCurrentState() { try { Method method = StateMachine.class.getDeclaredMethod("getCurrentState"); method.setAccessible(true); return (IState) method.invoke(mCdmaInboundSmsHandler); } catch (Exception e) { fail(e.toString()); return null; } } @Before public void setUp() throws Exception { super.setUp("CdmaInboundSmsHandlerTest"); Field field = SmsMessage.class.getDeclaredField("mEnvelope"); field.setAccessible(true); field.set(mCdmaSmsMessage, mSmsEnvelope); UserManager userManager = (UserManager) mContextFixture.getTestDouble(). getSystemService(Context.USER_SERVICE); doReturn(true).when(userManager).isUserUnlocked(); try { doReturn(new int[]{UserHandle.USER_SYSTEM}).when(mIActivityManager).getRunningUserIds(); } catch (RemoteException re) { fail("Unexpected RemoteException: " + re.getStackTrace()); } byte[] smsPdu = new byte[]{(byte)0xFF, (byte)0xFF, (byte)0xFF}; mSmsMessage.mWrappedSmsMessage = mCdmaSmsMessage; doReturn(smsPdu).when(mCdmaSmsMessage).getPdu(); mInboundSmsTrackerCV.put("destination_port", 1 << 16); mInboundSmsTrackerCV.put("pdu", HexDump.toHexString(smsPdu)); mInboundSmsTrackerCV.put("address", "1234567890"); mInboundSmsTrackerCV.put("reference_number", 1); mInboundSmsTrackerCV.put("sequence", 1); mInboundSmsTrackerCV.put("count", 1); mInboundSmsTrackerCV.put("date", System.currentTimeMillis()); mInboundSmsTrackerCV.put("message_body", "This is the message body of a single-part " + "message"); doReturn(true).when(mTelephonyManager).getSmsReceiveCapableForPhone(anyInt(), anyBoolean()); doReturn(true).when(mSmsStorageMonitor).isStorageAvailable(); doReturn(1).when(mInboundSmsTracker).getMessageCount(); doReturn(-1).when(mInboundSmsTracker).getDestPort(); doReturn(mInboundSmsTrackerCV).when(mInboundSmsTracker).getContentValues(); doReturn(smsPdu).when(mInboundSmsTracker).getPdu(); doReturn("This is the message body").when(mInboundSmsTracker).getMessageBody(); doReturn("1234567890").when(mInboundSmsTracker).getAddress(); mContentProvider = new FakeSmsContentProvider(); ((MockContentResolver)mContext.getContentResolver()).addProvider( Telephony.Sms.CONTENT_URI.getAuthority(), mContentProvider); mCdmaInboundSmsHandlerTestHandler = new CdmaInboundSmsHandlerTestHandler(TAG); mCdmaInboundSmsHandlerTestHandler.start(); waitUntilReady(); } @After public void tearDown() throws Exception { // wait for wakelock to be released; timeout at 10s int i = 0; while (mCdmaInboundSmsHandler.getWakeLock().isHeld() && i < 100) { waitForMs(100); i++; } assertFalse(mCdmaInboundSmsHandler.getWakeLock().isHeld()); mCdmaInboundSmsHandler = null; mContentProvider.shutdown(); mCdmaInboundSmsHandlerTestHandler.quitSafely(); super.tearDown(); } private void transitionFromStartupToIdle() { // verify initially in StartupState assertEquals("StartupState", getCurrentState().getName()); // trigger transition to IdleState mCdmaInboundSmsHandler.sendMessage(InboundSmsHandler.EVENT_START_ACCEPTING_SMS); waitForMs(50); assertEquals("IdleState", getCurrentState().getName()); } @Postsubmit @Test @MediumTest public void testNewSms() { transitionFromStartupToIdle(); // send new SMS to state machine and verify that triggers SMS_DELIVER_ACTION doReturn(SmsEnvelope.TELESERVICE_WMT).when(mCdmaSmsMessage).getTeleService(); mCdmaInboundSmsHandler.sendMessage(InboundSmsHandler.EVENT_NEW_SMS, new AsyncResult(null, mSmsMessage, null)); waitForMs(100); ArgumentCaptor<Intent> intentArgumentCaptor = ArgumentCaptor.forClass(Intent.class); verify(mContext).sendBroadcast(intentArgumentCaptor.capture()); assertEquals(Telephony.Sms.Intents.SMS_DELIVER_ACTION, intentArgumentCaptor.getValue().getAction()); assertEquals("WaitingState", getCurrentState().getName()); mContextFixture.sendBroadcastToOrderedBroadcastReceivers(); intentArgumentCaptor = ArgumentCaptor.forClass(Intent.class); verify(mContext, times(2)).sendBroadcast(intentArgumentCaptor.capture()); assertEquals(Telephony.Sms.Intents.SMS_RECEIVED_ACTION, intentArgumentCaptor.getAllValues().get(1).getAction()); assertEquals("WaitingState", getCurrentState().getName()); mContextFixture.sendBroadcastToOrderedBroadcastReceivers(); waitForMs(50); assertEquals("IdleState", getCurrentState().getName()); } @Test @MediumTest public void testNewSmsFromBlockedNumber_noBroadcastsSent() { String blockedNumber = "123456789"; doReturn(blockedNumber).when(mInboundSmsTracker).getAddress(); mFakeBlockedNumberContentProvider.mBlockedNumbers.add(blockedNumber); transitionFromStartupToIdle(); doReturn(SmsEnvelope.TELESERVICE_WMT).when(mCdmaSmsMessage).getTeleService(); mCdmaInboundSmsHandler.sendMessage(InboundSmsHandler.EVENT_NEW_SMS, new AsyncResult(null, mSmsMessage, null)); waitForMs(100); verify(mContext, never()).sendBroadcast(any(Intent.class)); assertEquals("IdleState", getCurrentState().getName()); } @Test @MediumTest public void testCtWdpParsing() { transitionFromStartupToIdle(); String pdu = "000000000000FDEA00000000000000000100000000000000000000001900031" + "040900112488ea794e074d69e1b7392c270326cde9e98"; SmsMessage msg = SmsMessage.createFromPdu(HexDump.hexStringToByteArray(pdu)); mSmsMessage.mWrappedSmsMessage = msg; mCdmaInboundSmsHandler.sendMessage(InboundSmsHandler.EVENT_NEW_SMS, new AsyncResult(null, mSmsMessage, null)); waitForMs(200); assertEquals(msg.getTeleService(), SmsEnvelope.TELESERVICE_CT_WAP); assertEquals("Test standard SMS", msg.getMessageBody()); assertNotNull(msg.getUserData()); } }