Home | History | Annotate | Download | only in cts
      1 /*
      2  * Copyright (C) 2009 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 
     17 package android.telephony.cts;
     18 
     19 
     20 import android.app.PendingIntent;
     21 import android.app.UiAutomation;
     22 import android.content.BroadcastReceiver;
     23 import android.content.ContentValues;
     24 import android.content.Context;
     25 import android.content.Intent;
     26 import android.content.IntentFilter;
     27 import android.content.pm.PackageManager;
     28 import android.net.Uri;
     29 import android.os.Bundle;
     30 import android.os.ParcelFileDescriptor;
     31 import android.os.SystemClock;
     32 import android.provider.BlockedNumberContract;
     33 import android.provider.Telephony;
     34 import android.telephony.SmsMessage;
     35 import android.telephony.TelephonyManager;
     36 import android.test.AndroidTestCase;
     37 import android.test.InstrumentationTestCase;
     38 import android.text.TextUtils;
     39 import android.util.Log;
     40 
     41 import java.io.BufferedReader;
     42 import java.io.FileInputStream;
     43 import java.io.IOException;
     44 import java.io.InputStream;
     45 import java.io.InputStreamReader;
     46 import java.nio.charset.StandardCharsets;
     47 import java.util.ArrayList;
     48 import java.util.Arrays;
     49 import java.util.List;
     50 
     51 /**
     52  * Tests for {@link android.telephony.SmsManager}.
     53  *
     54  * Structured so tests can be reused to test {@link android.telephony.gsm.SmsManager}
     55  */
     56 public class SmsManagerTest extends InstrumentationTestCase {
     57 
     58     private static final String TAG = "SmsManagerTest";
     59     private static final String LONG_TEXT =
     60         "This is a very long text. This text should be broken into three " +
     61         "separate messages.This is a very long text. This text should be broken into " +
     62         "three separate messages.This is a very long text. This text should be broken " +
     63         "into three separate messages.This is a very long text. This text should be " +
     64         "broken into three separate messages.";;
     65     private static final String LONG_TEXT_WITH_32BIT_CHARS =
     66         "Long dkkshsh jdjsusj kbsksbdf jfkhcu hhdiwoqiwyrygrvn?*?*!\";:'/,."
     67         + "__?9#9292736&4;\"$+$+((]\\[\\^=}}~~|."
     68         + "  ";
     69 
     70     private static final String SMS_SEND_ACTION = "CTS_SMS_SEND_ACTION";
     71     private static final String SMS_DELIVERY_ACTION = "CTS_SMS_DELIVERY_ACTION";
     72     private static final String DATA_SMS_RECEIVED_ACTION = "android.intent.action.DATA_SMS_RECEIVED";
     73     public static final String SMS_DELIVER_DEFAULT_APP_ACTION = "CTS_SMS_DELIVERY_ACTION_DEFAULT_APP";
     74 
     75     private TelephonyManager mTelephonyManager;
     76     private PackageManager mPackageManager;
     77     private String mDestAddr;
     78     private String mText;
     79     private SmsBroadcastReceiver mSendReceiver;
     80     private SmsBroadcastReceiver mDeliveryReceiver;
     81     private SmsBroadcastReceiver mDataSmsReceiver;
     82     private SmsBroadcastReceiver mSmsDeliverReceiver;
     83     private SmsBroadcastReceiver mSmsReceivedReceiver;
     84     private PendingIntent mSentIntent;
     85     private PendingIntent mDeliveredIntent;
     86     private Intent mSendIntent;
     87     private Intent mDeliveryIntent;
     88     private Context mContext;
     89     private Uri mBlockedNumberUri;
     90     private boolean mTestAppSetAsDefaultSmsApp;
     91     private boolean mDeliveryReportSupported;
     92     private static boolean mReceivedDataSms;
     93     private static String mReceivedText;
     94 
     95     private static final int TIME_OUT = 1000 * 60 * 5;
     96     private static final int NO_CALLS_TIMEOUT_MILLIS = 1000; // 1 second
     97 
     98     @Override
     99     protected void setUp() throws Exception {
    100         super.setUp();
    101         mContext = getInstrumentation().getContext();
    102         mTelephonyManager =
    103             (TelephonyManager) getInstrumentation().getContext().getSystemService(
    104                     Context.TELEPHONY_SERVICE);
    105         mPackageManager = mContext.getPackageManager();
    106         mDestAddr = mTelephonyManager.getLine1Number();
    107         mText = "This is a test message";
    108 
    109         if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) {
    110             mDeliveryReportSupported = false;
    111         } else {
    112             // exclude the networks that don't support SMS delivery report
    113             String mccmnc = mTelephonyManager.getSimOperator();
    114             mDeliveryReportSupported = !(CarrierCapability.NO_DELIVERY_REPORTS.contains(mccmnc));
    115         }
    116     }
    117 
    118     @Override
    119     protected void tearDown() throws Exception {
    120         if (mBlockedNumberUri != null) {
    121             mContext.getContentResolver().delete(mBlockedNumberUri, null, null);
    122             mBlockedNumberUri = null;
    123         }
    124         if (mTestAppSetAsDefaultSmsApp) {
    125             setDefaultSmsApp(false);
    126         }
    127     }
    128 
    129     public void testDivideMessage() {
    130         ArrayList<String> dividedMessages = divideMessage(LONG_TEXT);
    131         assertNotNull(dividedMessages);
    132         if (TelephonyUtils.isSkt(mTelephonyManager)) {
    133             assertTrue(isComplete(dividedMessages, 5, LONG_TEXT)
    134                     || isComplete(dividedMessages, 3, LONG_TEXT));
    135         } else if (TelephonyUtils.isKt(mTelephonyManager)) {
    136             assertTrue(isComplete(dividedMessages, 4, LONG_TEXT)
    137                     || isComplete(dividedMessages, 3, LONG_TEXT));
    138         } else {
    139             assertTrue(isComplete(dividedMessages, 3, LONG_TEXT));
    140         }
    141     }
    142 
    143     public void testDivideUnicodeMessage() {
    144         ArrayList<String> dividedMessages = divideMessage(LONG_TEXT_WITH_32BIT_CHARS);
    145         assertNotNull(dividedMessages);
    146         assertTrue(isComplete(dividedMessages, 3, LONG_TEXT_WITH_32BIT_CHARS));
    147         for (String messagePiece : dividedMessages) {
    148             assertFalse(Character.isHighSurrogate(
    149                     messagePiece.charAt(messagePiece.length() - 1)));
    150         }
    151     }
    152 
    153     private boolean isComplete(List<String> dividedMessages, int numParts, String longText) {
    154         if (dividedMessages.size() != numParts) {
    155             return false;
    156         }
    157 
    158         String actualMessage = "";
    159         for (int i = 0; i < numParts; i++) {
    160             actualMessage += dividedMessages.get(i);
    161         }
    162         return longText.equals(actualMessage);
    163     }
    164 
    165     public void testSendAndReceiveMessages() throws Exception {
    166         if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) {
    167             return;
    168         }
    169 
    170         assertFalse("[RERUN] SIM card does not provide phone number. Use a suitable SIM Card.",
    171                 TextUtils.isEmpty(mDestAddr));
    172 
    173         String mccmnc = mTelephonyManager.getSimOperator();
    174         setupBroadcastReceivers();
    175 
    176         // send single text sms
    177         init();
    178         sendTextMessage(mDestAddr, mDestAddr, mSentIntent, mDeliveredIntent);
    179         assertTrue("[RERUN] Could not send SMS. Check signal.",
    180                 mSendReceiver.waitForCalls(1, TIME_OUT));
    181         if (mDeliveryReportSupported) {
    182             assertTrue("[RERUN] SMS message delivery notification not received. Check signal.",
    183                     mDeliveryReceiver.waitForCalls(1, TIME_OUT));
    184         }
    185         // non-default app should receive only SMS_RECEIVED_ACTION
    186         assertTrue(mSmsReceivedReceiver.waitForCalls(1, TIME_OUT));
    187         assertTrue(mSmsDeliverReceiver.waitForCalls(0, 0));
    188 
    189         // due to permission restrictions, currently there is no way to make this test app the
    190         // default SMS app
    191 
    192         if (mTelephonyManager.getPhoneType() == TelephonyManager.PHONE_TYPE_CDMA) {
    193             // TODO: temp workaround, OCTET encoding for EMS not properly supported
    194             return;
    195         }
    196 
    197         // send data sms
    198         if (sendDataMessageIfSupported(mccmnc)) {
    199             assertTrue("[RERUN] Could not send data SMS. Check signal.",
    200                     mSendReceiver.waitForCalls(1, TIME_OUT));
    201             if (mDeliveryReportSupported) {
    202                 assertTrue("[RERUN] Data SMS message delivery notification not received. " +
    203                         "Check signal.", mDeliveryReceiver.waitForCalls(1, TIME_OUT));
    204             }
    205             mDataSmsReceiver.waitForCalls(1, TIME_OUT);
    206             assertTrue("[RERUN] Data SMS message not received. Check signal.", mReceivedDataSms);
    207             assertEquals(mReceivedText, mText);
    208         } else {
    209             // This GSM network doesn't support Data(binary) SMS message.
    210             // Skip the test.
    211         }
    212 
    213         // send multi parts text sms
    214         int numPartsSent = sendMultipartTextMessageIfSupported(mccmnc);
    215         if (numPartsSent > 0) {
    216             assertTrue("[RERUN] Could not send multi part SMS. Check signal.",
    217                     mSendReceiver.waitForCalls(numPartsSent, TIME_OUT));
    218             if (mDeliveryReportSupported) {
    219                 assertTrue("[RERUN] Multi part SMS message delivery notification not received. " +
    220                         "Check signal.", mDeliveryReceiver.waitForCalls(numPartsSent, TIME_OUT));
    221             }
    222             // non-default app should receive only SMS_RECEIVED_ACTION
    223             assertTrue(mSmsReceivedReceiver.waitForCalls(1, TIME_OUT));
    224             assertTrue(mSmsDeliverReceiver.waitForCalls(0, 0));
    225         } else {
    226             // This GSM network doesn't support Multipart SMS message.
    227             // Skip the test.
    228         }
    229     }
    230 
    231     public void testSmsBlocking() throws Exception {
    232         if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) {
    233             return;
    234         }
    235 
    236         assertFalse("[RERUN] SIM card does not provide phone number. Use a suitable SIM Card.",
    237                 TextUtils.isEmpty(mDestAddr));
    238 
    239         String mccmnc = mTelephonyManager.getSimOperator();
    240         // Setting default SMS App is needed to be able to block numbers.
    241         setDefaultSmsApp(true);
    242         blockNumber(mDestAddr);
    243         setupBroadcastReceivers();
    244 
    245         // single-part SMS blocking
    246         init();
    247         sendTextMessage(mDestAddr, mDestAddr, mSentIntent, mDeliveredIntent);
    248         assertTrue("[RERUN] Could not send SMS. Check signal.",
    249                 mSendReceiver.waitForCalls(1, TIME_OUT));
    250         assertTrue("Expected no messages to be received due to number blocking.",
    251                 mSmsReceivedReceiver.verifyNoCalls(NO_CALLS_TIMEOUT_MILLIS));
    252         assertTrue("Expected no messages to be delivered due to number blocking.",
    253                 mSmsDeliverReceiver.verifyNoCalls(NO_CALLS_TIMEOUT_MILLIS));
    254 
    255         // send data sms
    256         if (!sendDataMessageIfSupported(mccmnc)) {
    257             assertTrue("[RERUN] Could not send data SMS. Check signal.",
    258                     mSendReceiver.waitForCalls(1, TIME_OUT));
    259             if (mDeliveryReportSupported) {
    260                 assertTrue("[RERUN] Data SMS message delivery notification not received. " +
    261                         "Check signal.", mDeliveryReceiver.waitForCalls(1, TIME_OUT));
    262             }
    263             assertTrue("Expected no messages to be delivered due to number blocking.",
    264                     mSmsDeliverReceiver.verifyNoCalls(NO_CALLS_TIMEOUT_MILLIS));
    265         } else {
    266             // This GSM network doesn't support Data(binary) SMS message.
    267             // Skip the test.
    268         }
    269 
    270         // multi-part SMS blocking
    271         int numPartsSent = sendMultipartTextMessageIfSupported(mccmnc);
    272         if (numPartsSent > 0) {
    273             assertTrue("[RERUN] Could not send multi part SMS. Check signal.",
    274                     mSendReceiver.waitForCalls(numPartsSent, TIME_OUT));
    275 
    276             assertTrue("Expected no messages to be received due to number blocking.",
    277                     mSmsReceivedReceiver.verifyNoCalls(NO_CALLS_TIMEOUT_MILLIS));
    278             assertTrue("Expected no messages to be delivered due to number blocking.",
    279                     mSmsDeliverReceiver.verifyNoCalls(NO_CALLS_TIMEOUT_MILLIS));
    280         } else {
    281             // This GSM network doesn't support Multipart SMS message.
    282             // Skip the test.
    283         }
    284     }
    285 
    286 
    287     public void testSmsNotPersisted_failsWithoutCarrierPermissions() throws Exception {
    288         if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) {
    289             return;
    290         }
    291 
    292         assertFalse("[RERUN] SIM card does not provide phone number. Use a suitable SIM Card.",
    293                 TextUtils.isEmpty(mDestAddr));
    294 
    295         try {
    296             getSmsManager().sendTextMessageWithoutPersisting(mDestAddr, null /*scAddress */,
    297                     mDestAddr, mSentIntent, mDeliveredIntent);
    298             fail("We should get a SecurityException due to not having carrier privileges");
    299         } catch (SecurityException e) {
    300             // Success
    301         }
    302     }
    303 
    304     private void init() {
    305         mSendReceiver.reset();
    306         mDeliveryReceiver.reset();
    307         mDataSmsReceiver.reset();
    308         mSmsDeliverReceiver.reset();
    309         mSmsReceivedReceiver.reset();
    310         mReceivedDataSms = false;
    311         mSentIntent = PendingIntent.getBroadcast(mContext, 0, mSendIntent,
    312                 PendingIntent.FLAG_ONE_SHOT);
    313         mDeliveredIntent = PendingIntent.getBroadcast(mContext, 0, mDeliveryIntent,
    314                 PendingIntent.FLAG_ONE_SHOT);
    315     }
    316 
    317     private void setupBroadcastReceivers() {
    318         mSendIntent = new Intent(SMS_SEND_ACTION);
    319         mDeliveryIntent = new Intent(SMS_DELIVERY_ACTION);
    320 
    321         IntentFilter sendIntentFilter = new IntentFilter(SMS_SEND_ACTION);
    322         IntentFilter deliveryIntentFilter = new IntentFilter(SMS_DELIVERY_ACTION);
    323         IntentFilter dataSmsReceivedIntentFilter = new IntentFilter(DATA_SMS_RECEIVED_ACTION);
    324         IntentFilter smsDeliverIntentFilter = new IntentFilter(SMS_DELIVER_DEFAULT_APP_ACTION);
    325         IntentFilter smsReceivedIntentFilter =
    326                 new IntentFilter(Telephony.Sms.Intents.SMS_RECEIVED_ACTION);
    327         dataSmsReceivedIntentFilter.addDataScheme("sms");
    328         dataSmsReceivedIntentFilter.addDataAuthority("localhost", "19989");
    329 
    330         mSendReceiver = new SmsBroadcastReceiver(SMS_SEND_ACTION);
    331         mDeliveryReceiver = new SmsBroadcastReceiver(SMS_DELIVERY_ACTION);
    332         mDataSmsReceiver = new SmsBroadcastReceiver(DATA_SMS_RECEIVED_ACTION);
    333         mSmsDeliverReceiver = new SmsBroadcastReceiver(SMS_DELIVER_DEFAULT_APP_ACTION);
    334         mSmsReceivedReceiver = new SmsBroadcastReceiver(Telephony.Sms.Intents.SMS_RECEIVED_ACTION);
    335 
    336         mContext.registerReceiver(mSendReceiver, sendIntentFilter);
    337         mContext.registerReceiver(mDeliveryReceiver, deliveryIntentFilter);
    338         mContext.registerReceiver(mDataSmsReceiver, dataSmsReceivedIntentFilter);
    339         mContext.registerReceiver(mSmsDeliverReceiver, smsDeliverIntentFilter);
    340         mContext.registerReceiver(mSmsReceivedReceiver, smsReceivedIntentFilter);
    341     }
    342 
    343     /**
    344      * Returns the number of parts sent in the message. If Multi-part SMS is not supported,
    345      * returns 0.
    346      */
    347     private int sendMultipartTextMessageIfSupported(String mccmnc) {
    348         int numPartsSent = 0;
    349         if (!CarrierCapability.UNSUPPORT_MULTIPART_SMS_MESSAGES.contains(mccmnc)) {
    350             init();
    351             ArrayList<String> parts = divideMessage(LONG_TEXT);
    352             numPartsSent = parts.size();
    353             ArrayList<PendingIntent> sentIntents = new ArrayList<PendingIntent>();
    354             ArrayList<PendingIntent> deliveryIntents = new ArrayList<PendingIntent>();
    355             for (int i = 0; i < numPartsSent; i++) {
    356                 sentIntents.add(PendingIntent.getBroadcast(mContext, 0, mSendIntent, 0));
    357                 deliveryIntents.add(PendingIntent.getBroadcast(mContext, 0, mDeliveryIntent, 0));
    358             }
    359             sendMultiPartTextMessage(mDestAddr, parts, sentIntents, deliveryIntents);
    360         }
    361         return numPartsSent;
    362     }
    363 
    364     private boolean sendDataMessageIfSupported(String mccmnc) {
    365         if (!CarrierCapability.UNSUPPORT_DATA_SMS_MESSAGES.contains(mccmnc)) {
    366             byte[] data = mText.getBytes();
    367             short port = 19989;
    368 
    369             init();
    370             sendDataMessage(mDestAddr, port, data, mSentIntent, mDeliveredIntent);
    371             return true;
    372         }
    373         return false;
    374     }
    375 
    376     public void testGetDefault() {
    377         assertNotNull(getSmsManager());
    378     }
    379 
    380     protected ArrayList<String> divideMessage(String text) {
    381         return getSmsManager().divideMessage(text);
    382     }
    383 
    384     private android.telephony.SmsManager getSmsManager() {
    385         return android.telephony.SmsManager.getDefault();
    386     }
    387 
    388     protected void sendMultiPartTextMessage(String destAddr, ArrayList<String> parts,
    389             ArrayList<PendingIntent> sentIntents, ArrayList<PendingIntent> deliveryIntents) {
    390         getSmsManager().sendMultipartTextMessage(destAddr, null, parts, sentIntents, deliveryIntents);
    391     }
    392 
    393     protected void sendDataMessage(String destAddr,short port, byte[] data, PendingIntent sentIntent, PendingIntent deliveredIntent) {
    394         getSmsManager().sendDataMessage(destAddr, null, port, data, sentIntent, deliveredIntent);
    395     }
    396 
    397     protected void sendTextMessage(String destAddr, String text, PendingIntent sentIntent, PendingIntent deliveredIntent) {
    398         getSmsManager().sendTextMessage(destAddr, null, text, sentIntent, deliveredIntent);
    399     }
    400 
    401     private void blockNumber(String phoneNumber) {
    402         ContentValues cv = new ContentValues();
    403         cv.put(BlockedNumberContract.BlockedNumbers.COLUMN_ORIGINAL_NUMBER, phoneNumber);
    404         mBlockedNumberUri = mContext.getContentResolver().insert(
    405                 BlockedNumberContract.BlockedNumbers.CONTENT_URI, cv);
    406     }
    407 
    408     private void setDefaultSmsApp(boolean setToSmsApp)
    409             throws Exception {
    410         String command = String.format(
    411                 "appops set %s WRITE_SMS %s",
    412                 mContext.getPackageName(),
    413                 setToSmsApp ? "allow" : "default");
    414         assertTrue("Setting default SMS app failed : " + setToSmsApp,
    415                 executeShellCommand(command).isEmpty());
    416         mTestAppSetAsDefaultSmsApp = setToSmsApp;
    417     }
    418 
    419     private String executeShellCommand(String command)
    420             throws IOException {
    421         ParcelFileDescriptor pfd =
    422                 getInstrumentation().getUiAutomation().executeShellCommand(command);
    423         BufferedReader br = null;
    424         try (InputStream in = new FileInputStream(pfd.getFileDescriptor());) {
    425             br = new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8));
    426             String str;
    427             StringBuilder out = new StringBuilder();
    428             while ((str = br.readLine()) != null) {
    429                 out.append(str);
    430             }
    431             return out.toString();
    432         } finally {
    433             if (br != null) {
    434                 br.close();
    435             }
    436         }
    437     }
    438 
    439     private static class SmsBroadcastReceiver extends BroadcastReceiver {
    440         private int mCalls;
    441         private int mExpectedCalls;
    442         private String mAction;
    443         private Object mLock;
    444 
    445         SmsBroadcastReceiver(String action) {
    446             mAction = action;
    447             reset();
    448             mLock = new Object();
    449         }
    450 
    451         void reset() {
    452             mExpectedCalls = Integer.MAX_VALUE;
    453             mCalls = 0;
    454         }
    455 
    456         @Override
    457         public void onReceive(Context context, Intent intent) {
    458             if(mAction.equals(DATA_SMS_RECEIVED_ACTION)){
    459                 StringBuilder sb = new StringBuilder();
    460                 Bundle bundle = intent.getExtras();
    461                 if (bundle != null) {
    462                     Object[] obj = (Object[]) bundle.get("pdus");
    463                     String format = bundle.getString("format");
    464                     SmsMessage[] message = new SmsMessage[obj.length];
    465                     for (int i = 0; i < obj.length; i++) {
    466                         message[i] = SmsMessage.createFromPdu((byte[]) obj[i], format);
    467                     }
    468 
    469                     for (SmsMessage currentMessage : message) {
    470                         byte[] binaryContent = currentMessage.getUserData();
    471                         String readableContent = new String(binaryContent);
    472                         sb.append(readableContent);
    473                     }
    474                 }
    475                 mReceivedDataSms = true;
    476                 mReceivedText=sb.toString();
    477             }
    478             Log.i(TAG, "onReceive " + intent.getAction());
    479             if (intent.getAction().equals(mAction)) {
    480                 synchronized (mLock) {
    481                     mCalls += 1;
    482                     mLock.notify();
    483                 }
    484             }
    485         }
    486 
    487         private boolean verifyNoCalls(long timeout) throws InterruptedException {
    488             synchronized(mLock) {
    489                 mLock.wait(timeout);
    490                 return mCalls == 0;
    491             }
    492         }
    493 
    494         public boolean waitForCalls(int expectedCalls, long timeout) throws InterruptedException {
    495             synchronized(mLock) {
    496                 mExpectedCalls = expectedCalls;
    497                 long startTime = SystemClock.elapsedRealtime();
    498 
    499                 while (mCalls < mExpectedCalls) {
    500                     long waitTime = timeout - (SystemClock.elapsedRealtime() - startTime);
    501                     if (waitTime > 0) {
    502                         mLock.wait(waitTime);
    503                     } else {
    504                         return false;  // timed out
    505                     }
    506                 }
    507                 return true;  // success
    508             }
    509         }
    510     }
    511 }
    512