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