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 import static com.android.compatibility.common.util.BlockedNumberUtil.deleteBlockedNumber; 20 import static com.android.compatibility.common.util.BlockedNumberUtil.insertBlockedNumber; 21 22 import static androidx.test.InstrumentationRegistry.getContext; 23 import static androidx.test.InstrumentationRegistry.getInstrumentation; 24 25 import static org.junit.Assert.assertEquals; 26 import static org.junit.Assert.assertFalse; 27 import static org.junit.Assert.assertNotNull; 28 import static org.junit.Assert.assertNull; 29 import static org.junit.Assert.assertTrue; 30 import static org.junit.Assert.fail; 31 32 import static org.hamcrest.Matchers.anyOf; 33 import static org.hamcrest.Matchers.emptyString; 34 import static org.hamcrest.Matchers.equalTo; 35 import static org.hamcrest.Matchers.greaterThan; 36 import static org.hamcrest.Matchers.lessThanOrEqualTo; 37 import static org.hamcrest.Matchers.startsWith; 38 import static org.junit.Assert.assertNotEquals; 39 import static org.junit.Assert.assertThat; 40 41 import android.app.AppOpsManager; 42 import android.app.PendingIntent; 43 import android.app.UiAutomation; 44 import android.app.role.RoleManager; 45 import android.content.BroadcastReceiver; 46 import android.content.ComponentName; 47 import android.content.ContentResolver; 48 import android.content.ContentValues; 49 import android.content.Context; 50 import android.content.Intent; 51 import android.content.IntentFilter; 52 import android.content.pm.PackageManager; 53 import android.database.CursorWindow; 54 import android.net.Uri; 55 import android.os.AsyncTask; 56 import android.os.Bundle; 57 import android.os.ParcelFileDescriptor; 58 import android.os.RemoteCallback; 59 import android.os.SystemClock; 60 import android.provider.Settings; 61 import android.provider.Telephony; 62 import android.telephony.SmsManager; 63 import android.telephony.SmsMessage; 64 import android.telephony.TelephonyManager; 65 import android.text.TextUtils; 66 import android.util.Log; 67 68 import java.io.BufferedReader; 69 import java.io.FileInputStream; 70 import java.io.IOException; 71 import java.io.InputStream; 72 import java.io.InputStreamReader; 73 import java.nio.charset.StandardCharsets; 74 import java.util.ArrayList; 75 import java.util.Date; 76 import java.util.List; 77 import java.util.concurrent.Callable; 78 import java.util.concurrent.CompletableFuture; 79 import java.util.concurrent.CountDownLatch; 80 import java.util.concurrent.TimeUnit; 81 82 import org.junit.After; 83 import org.junit.Before; 84 import org.junit.Test; 85 86 /** 87 * Tests for {@link android.telephony.SmsManager}. 88 * 89 * Structured so tests can be reused to test {@link android.telephony.gsm.SmsManager} 90 */ 91 public class SmsManagerTest { 92 93 private static final String TAG = "SmsManagerTest"; 94 private static final String LONG_TEXT = 95 "This is a very long text. This text should be broken into three " + 96 "separate messages.This is a very long text. This text should be broken into " + 97 "three separate messages.This is a very long text. This text should be broken " + 98 "into three separate messages.This is a very long text. This text should be " + 99 "broken into three separate messages.";; 100 private static final String LONG_TEXT_WITH_32BIT_CHARS = 101 "Long dkkshsh jdjsusj kbsksbdf jfkhcu hhdiwoqiwyrygrvn?*?*!\";:'/,." 102 + "__?9#9292736&4;\"$+$+((]\\[\\^=}}~~|." 103 + " "; 104 105 private static final String SMS_SEND_ACTION = "CTS_SMS_SEND_ACTION"; 106 private static final String SMS_DELIVERY_ACTION = "CTS_SMS_DELIVERY_ACTION"; 107 private static final String DATA_SMS_RECEIVED_ACTION = "android.intent.action.DATA_SMS_RECEIVED"; 108 public static final String SMS_DELIVER_DEFAULT_APP_ACTION = "CTS_SMS_DELIVERY_ACTION_DEFAULT_APP"; 109 public static final String LEGACY_SMS_APP = "android.telephony.cts.sms23"; 110 public static final String MODERN_SMS_APP = "android.telephony.cts.sms"; 111 private static final String SMS_RETRIEVER_APP = "android.telephony.cts.smsretriever"; 112 private static final String SMS_RETRIEVER_ACTION = "CTS_SMS_RETRIEVER_ACTION"; 113 private static final String FINANCIAL_SMS_APP = "android.telephony.cts.financialsms"; 114 115 private TelephonyManager mTelephonyManager; 116 private PackageManager mPackageManager; 117 private String mDestAddr; 118 private String mText; 119 private SmsBroadcastReceiver mSendReceiver; 120 private SmsBroadcastReceiver mDeliveryReceiver; 121 private SmsBroadcastReceiver mDataSmsReceiver; 122 private SmsBroadcastReceiver mSmsDeliverReceiver; 123 private SmsBroadcastReceiver mSmsReceivedReceiver; 124 private SmsBroadcastReceiver mSmsRetrieverReceiver; 125 private PendingIntent mSentIntent; 126 private PendingIntent mDeliveredIntent; 127 private Intent mSendIntent; 128 private Intent mDeliveryIntent; 129 private Context mContext; 130 private Uri mBlockedNumberUri; 131 private boolean mTestAppSetAsDefaultSmsApp; 132 private boolean mDeliveryReportSupported; 133 private static boolean mReceivedDataSms; 134 private static String mReceivedText; 135 private static boolean sHasShellPermissionIdentity = false; 136 137 private static final int TIME_OUT = 1000 * 60 * 4; 138 private static final int NO_CALLS_TIMEOUT_MILLIS = 1000; // 1 second 139 140 @Before 141 public void setUp() throws Exception { 142 mContext = getContext(); 143 mTelephonyManager = 144 (TelephonyManager) getContext().getSystemService( 145 Context.TELEPHONY_SERVICE); 146 mPackageManager = mContext.getPackageManager(); 147 mDestAddr = mTelephonyManager.getLine1Number(); 148 mText = "This is a test message"; 149 150 if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) { 151 mDeliveryReportSupported = false; 152 } else { 153 // exclude the networks that don't support SMS delivery report 154 String mccmnc = mTelephonyManager.getSimOperator(); 155 mDeliveryReportSupported = !(CarrierCapability.NO_DELIVERY_REPORTS.contains(mccmnc)); 156 } 157 } 158 159 @After 160 public void tearDown() throws Exception { 161 if (mBlockedNumberUri != null) { 162 unblockNumber(mBlockedNumberUri); 163 mBlockedNumberUri = null; 164 } 165 if (mTestAppSetAsDefaultSmsApp) { 166 setDefaultSmsApp(false); 167 } 168 } 169 170 @Test 171 public void testDivideMessage() { 172 ArrayList<String> dividedMessages = divideMessage(LONG_TEXT); 173 assertNotNull(dividedMessages); 174 if (TelephonyUtils.isSkt(mTelephonyManager)) { 175 assertTrue(isComplete(dividedMessages, 5, LONG_TEXT) 176 || isComplete(dividedMessages, 3, LONG_TEXT)); 177 } else if (TelephonyUtils.isKt(mTelephonyManager)) { 178 assertTrue(isComplete(dividedMessages, 4, LONG_TEXT) 179 || isComplete(dividedMessages, 3, LONG_TEXT)); 180 } else { 181 assertTrue(isComplete(dividedMessages, 3, LONG_TEXT)); 182 } 183 } 184 185 @Test 186 public void testDivideUnicodeMessage() { 187 ArrayList<String> dividedMessages = divideMessage(LONG_TEXT_WITH_32BIT_CHARS); 188 assertNotNull(dividedMessages); 189 assertTrue(isComplete(dividedMessages, 3, LONG_TEXT_WITH_32BIT_CHARS)); 190 for (String messagePiece : dividedMessages) { 191 assertFalse(Character.isHighSurrogate( 192 messagePiece.charAt(messagePiece.length() - 1))); 193 } 194 } 195 196 private boolean isComplete(List<String> dividedMessages, int numParts, String longText) { 197 if (dividedMessages.size() != numParts) { 198 return false; 199 } 200 201 String actualMessage = ""; 202 for (int i = 0; i < numParts; i++) { 203 actualMessage += dividedMessages.get(i); 204 } 205 return longText.equals(actualMessage); 206 } 207 208 @Test 209 public void testSmsRetriever() throws Exception { 210 if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) { 211 return; 212 } 213 214 assertFalse("[RERUN] SIM card does not provide phone number. Use a suitable SIM Card.", 215 TextUtils.isEmpty(mDestAddr)); 216 217 String mccmnc = mTelephonyManager.getSimOperator(); 218 setupBroadcastReceivers(); 219 init(); 220 221 CompletableFuture<Bundle> callbackResult = new CompletableFuture<>(); 222 223 mContext.startActivity(new Intent() 224 .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK) 225 .setComponent(new ComponentName( 226 SMS_RETRIEVER_APP, SMS_RETRIEVER_APP + ".MainActivity")) 227 .putExtra("callback", new RemoteCallback(callbackResult::complete))); 228 229 230 Bundle bundle = callbackResult.get(200, TimeUnit.SECONDS); 231 String token = bundle.getString("token"); 232 assertThat(bundle.getString("class"), startsWith(SMS_RETRIEVER_APP)); 233 assertNotNull(token); 234 235 String composedText = "testprefix1" + mText + token; 236 sendTextMessage(mDestAddr, composedText, null, null); 237 238 assertTrue("[RERUN] SMS retriever message not received. Check signal.", 239 mSmsRetrieverReceiver.waitForCalls(1, TIME_OUT)); 240 } 241 242 @Test 243 public void testSendAndReceiveMessages() throws Exception { 244 if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) { 245 return; 246 } 247 248 assertFalse("[RERUN] SIM card does not provide phone number. Use a suitable SIM Card.", 249 TextUtils.isEmpty(mDestAddr)); 250 251 String mccmnc = mTelephonyManager.getSimOperator(); 252 setupBroadcastReceivers(); 253 254 // send single text sms 255 init(); 256 sendTextMessage(mDestAddr, mDestAddr, mSentIntent, mDeliveredIntent); 257 assertTrue("[RERUN] Could not send SMS. Check signal.", 258 mSendReceiver.waitForCalls(1, TIME_OUT)); 259 if (mDeliveryReportSupported) { 260 assertTrue("[RERUN] SMS message delivery notification not received. Check signal.", 261 mDeliveryReceiver.waitForCalls(1, TIME_OUT)); 262 } 263 // non-default app should receive only SMS_RECEIVED_ACTION 264 assertTrue(mSmsReceivedReceiver.waitForCalls(1, TIME_OUT)); 265 assertTrue(mSmsDeliverReceiver.waitForCalls(0, 0)); 266 267 // due to permission restrictions, currently there is no way to make this test app the 268 // default SMS app 269 270 if (mTelephonyManager.getPhoneType() == TelephonyManager.PHONE_TYPE_CDMA) { 271 // TODO: temp workaround, OCTET encoding for EMS not properly supported 272 return; 273 } 274 275 // send data sms 276 if (sendDataMessageIfSupported(mccmnc)) { 277 assertTrue("[RERUN] Could not send data SMS. Check signal.", 278 mSendReceiver.waitForCalls(1, TIME_OUT)); 279 if (mDeliveryReportSupported) { 280 assertTrue("[RERUN] Data SMS message delivery notification not received. " + 281 "Check signal.", mDeliveryReceiver.waitForCalls(1, TIME_OUT)); 282 } 283 mDataSmsReceiver.waitForCalls(1, TIME_OUT); 284 assertTrue("[RERUN] Data SMS message not received. Check signal.", mReceivedDataSms); 285 assertEquals(mReceivedText, mText); 286 } else { 287 // This GSM network doesn't support Data(binary) SMS message. 288 // Skip the test. 289 } 290 291 // send multi parts text sms 292 int numPartsSent = sendMultipartTextMessageIfSupported(mccmnc); 293 if (numPartsSent > 0) { 294 assertTrue("[RERUN] Could not send multi part SMS. Check signal.", 295 mSendReceiver.waitForCalls(numPartsSent, TIME_OUT)); 296 if (mDeliveryReportSupported) { 297 assertTrue("[RERUN] Multi part SMS message delivery notification not received. " + 298 "Check signal.", mDeliveryReceiver.waitForCalls(numPartsSent, TIME_OUT)); 299 } 300 // non-default app should receive only SMS_RECEIVED_ACTION 301 assertTrue(mSmsReceivedReceiver.waitForCalls(1, TIME_OUT)); 302 assertTrue(mSmsDeliverReceiver.waitForCalls(0, 0)); 303 } else { 304 // This GSM network doesn't support Multipart SMS message. 305 // Skip the test. 306 } 307 } 308 309 @Test 310 public void testSmsBlocking() throws Exception { 311 if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) { 312 return; 313 } 314 315 assertFalse("[RERUN] SIM card does not provide phone number. Use a suitable SIM Card.", 316 TextUtils.isEmpty(mDestAddr)); 317 318 String mccmnc = mTelephonyManager.getSimOperator(); 319 // Setting default SMS App is needed to be able to block numbers. 320 setDefaultSmsApp(true); 321 blockNumber(mDestAddr); 322 setupBroadcastReceivers(); 323 324 // single-part SMS blocking 325 init(); 326 sendTextMessage(mDestAddr, mDestAddr, mSentIntent, mDeliveredIntent); 327 assertTrue("[RERUN] Could not send SMS. Check signal.", 328 mSendReceiver.waitForCalls(1, TIME_OUT)); 329 assertTrue("Expected no messages to be received due to number blocking.", 330 mSmsReceivedReceiver.verifyNoCalls(NO_CALLS_TIMEOUT_MILLIS)); 331 assertTrue("Expected no messages to be delivered due to number blocking.", 332 mSmsDeliverReceiver.verifyNoCalls(NO_CALLS_TIMEOUT_MILLIS)); 333 334 // send data sms 335 if (!sendDataMessageIfSupported(mccmnc)) { 336 assertTrue("[RERUN] Could not send data SMS. Check signal.", 337 mSendReceiver.waitForCalls(1, TIME_OUT)); 338 if (mDeliveryReportSupported) { 339 assertTrue("[RERUN] Data SMS message delivery notification not received. " + 340 "Check signal.", mDeliveryReceiver.waitForCalls(1, TIME_OUT)); 341 } 342 assertTrue("Expected no messages to be delivered due to number blocking.", 343 mSmsDeliverReceiver.verifyNoCalls(NO_CALLS_TIMEOUT_MILLIS)); 344 } else { 345 // This GSM network doesn't support Data(binary) SMS message. 346 // Skip the test. 347 } 348 349 // multi-part SMS blocking 350 int numPartsSent = sendMultipartTextMessageIfSupported(mccmnc); 351 if (numPartsSent > 0) { 352 assertTrue("[RERUN] Could not send multi part SMS. Check signal.", 353 mSendReceiver.waitForCalls(numPartsSent, TIME_OUT)); 354 355 assertTrue("Expected no messages to be received due to number blocking.", 356 mSmsReceivedReceiver.verifyNoCalls(NO_CALLS_TIMEOUT_MILLIS)); 357 assertTrue("Expected no messages to be delivered due to number blocking.", 358 mSmsDeliverReceiver.verifyNoCalls(NO_CALLS_TIMEOUT_MILLIS)); 359 } else { 360 // This GSM network doesn't support Multipart SMS message. 361 // Skip the test. 362 } 363 } 364 365 @Test 366 public void testGetSmsMessagesForFinancialAppPermissionNotRequested() throws Exception { 367 final CountDownLatch latch = new CountDownLatch(1); 368 369 try { 370 getSmsManager().getSmsMessagesForFinancialApp(new Bundle(), 371 getInstrumentation().getContext().getMainExecutor(), 372 new SmsManager.FinancialSmsCallback() { 373 public void onFinancialSmsMessages(CursorWindow msgs) { 374 assertNull(msgs); 375 latch.countDown(); 376 }}); 377 assertTrue(latch.await(500, TimeUnit.MILLISECONDS)); 378 } catch (Exception e) { 379 // do nothing 380 } 381 } 382 383 @Test 384 public void testGetSmsMessagesForFinancialAppPermissionRequestedNotGranted() throws Exception { 385 CompletableFuture<Bundle> callbackResult = new CompletableFuture<>(); 386 387 mContext.startActivity(new Intent() 388 .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK) 389 .setComponent(new ComponentName(FINANCIAL_SMS_APP, FINANCIAL_SMS_APP + ".MainActivity")) 390 .putExtra("callback", new RemoteCallback(callbackResult::complete))); 391 392 Bundle bundle = callbackResult.get(500, TimeUnit.SECONDS); 393 394 assertThat(bundle.getString("class"), startsWith(FINANCIAL_SMS_APP)); 395 assertThat(bundle.getInt("rowNum"), equalTo(-1)); 396 } 397 398 @Test 399 public void testGetSmsMessagesForFinancialAppPermissionRequestedGranted() throws Exception { 400 CompletableFuture<Bundle> callbackResult = new CompletableFuture<>(); 401 String ctsPackageName = getInstrumentation().getContext().getPackageName(); 402 403 executeWithShellPermissionIdentity(() -> { 404 setModeForOps(FINANCIAL_SMS_APP, 405 AppOpsManager.MODE_ALLOWED, 406 AppOpsManager.OPSTR_SMS_FINANCIAL_TRANSACTIONS); 407 }); 408 mContext.startActivity(new Intent() 409 .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK) 410 .setComponent(new ComponentName(FINANCIAL_SMS_APP, FINANCIAL_SMS_APP + ".MainActivity")) 411 .putExtra("callback", new RemoteCallback(callbackResult::complete))); 412 413 414 Bundle bundle = callbackResult.get(500, TimeUnit.SECONDS); 415 416 assertThat(bundle.getString("class"), startsWith(FINANCIAL_SMS_APP)); 417 assertThat(bundle.getInt("rowNum"), equalTo(-1)); 418 } 419 420 @Test 421 public void testSmsNotPersisted_failsWithoutCarrierPermissions() throws Exception { 422 if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) { 423 return; 424 } 425 426 assertFalse("[RERUN] SIM card does not provide phone number. Use a suitable SIM Card.", 427 TextUtils.isEmpty(mDestAddr)); 428 429 try { 430 getSmsManager().sendTextMessageWithoutPersisting(mDestAddr, null /*scAddress */, 431 mDestAddr, mSentIntent, mDeliveredIntent); 432 fail("We should get a SecurityException due to not having carrier privileges"); 433 } catch (SecurityException e) { 434 // Success 435 } 436 } 437 438 @Test 439 public void testContentProviderAccessRestriction() throws Exception { 440 Uri dummySmsUri = null; 441 Context context = getInstrumentation().getContext(); 442 ContentResolver contentResolver = context.getContentResolver(); 443 int originalWriteSmsMode = -1; 444 String ctsPackageName = context.getPackageName(); 445 try { 446 // Insert some dummy sms 447 originalWriteSmsMode = context.getSystemService(AppOpsManager.class) 448 .unsafeCheckOpNoThrow(AppOpsManager.OPSTR_WRITE_SMS, 449 getPackageUid(ctsPackageName), ctsPackageName); 450 dummySmsUri = executeWithShellPermissionIdentity(() -> { 451 setModeForOps(ctsPackageName, 452 AppOpsManager.MODE_ALLOWED, AppOpsManager.OPSTR_WRITE_SMS); 453 ContentValues contentValues = new ContentValues(); 454 contentValues.put(Telephony.TextBasedSmsColumns.ADDRESS, "addr"); 455 contentValues.put(Telephony.TextBasedSmsColumns.READ, 1); 456 contentValues.put(Telephony.TextBasedSmsColumns.SUBJECT, "subj"); 457 contentValues.put(Telephony.TextBasedSmsColumns.BODY, "created_at_" + 458 new Date().toString().replace(" ", "_")); 459 return contentResolver.insert(Telephony.Sms.CONTENT_URI, contentValues); 460 }); 461 assertNotNull("Failed to insert dummy sms", dummySmsUri); 462 assertNotEquals("Failed to insert dummy sms", dummySmsUri.getLastPathSegment(), "0"); 463 testSmsAccessAboutDefaultApp(LEGACY_SMS_APP); 464 testSmsAccessAboutDefaultApp(MODERN_SMS_APP); 465 } finally { 466 if (dummySmsUri != null && !"/0".equals(dummySmsUri.getLastPathSegment())) { 467 final Uri finalDummySmsUri = dummySmsUri; 468 executeWithShellPermissionIdentity(() -> contentResolver.delete(finalDummySmsUri, 469 null, null)); 470 } 471 if (originalWriteSmsMode >= 0) { 472 int finalOriginalWriteSmsMode = originalWriteSmsMode; 473 executeWithShellPermissionIdentity(() -> 474 setModeForOps(ctsPackageName, 475 finalOriginalWriteSmsMode, AppOpsManager.OPSTR_WRITE_SMS)); 476 } 477 } 478 } 479 480 private void testSmsAccessAboutDefaultApp(String pkg) 481 throws Exception { 482 String originalSmsApp = getSmsApp(); 483 assertNotEquals(pkg, originalSmsApp); 484 assertCanAccessSms(pkg); 485 try { 486 setSmsApp(pkg); 487 assertCanAccessSms(pkg); 488 } finally { 489 resetReadWriteSmsAppOps(pkg); 490 setSmsApp(originalSmsApp); 491 } 492 } 493 494 private void resetReadWriteSmsAppOps(String pkg) throws Exception { 495 setModeForOps(pkg, AppOpsManager.MODE_DEFAULT, 496 AppOpsManager.OPSTR_READ_SMS, AppOpsManager.OPSTR_WRITE_SMS); 497 } 498 499 private void setModeForOps(String pkg, int mode, String... ops) throws Exception { 500 // We cannot reset these app ops to DEFAULT via current API, so we reset them manually here 501 // temporarily as we will rewrite how the default SMS app is setup later. 502 executeWithShellPermissionIdentity(() -> { 503 int uid = getPackageUid(pkg); 504 AppOpsManager appOpsManager = 505 getInstrumentation().getContext().getSystemService(AppOpsManager.class); 506 for (String op : ops) { 507 appOpsManager.setUidMode(op, uid, mode); 508 } 509 }); 510 } 511 512 private int getPackageUid(String pkg) throws PackageManager.NameNotFoundException { 513 return getInstrumentation().getContext().getPackageManager().getPackageUid(pkg, 0); 514 } 515 516 private String getSmsApp() throws Exception { 517 return executeWithShellPermissionIdentity(() -> getInstrumentation() 518 .getContext() 519 .getSystemService(RoleManager.class) 520 .getRoleHolders(RoleManager.ROLE_SMS) 521 .get(0)); 522 } 523 524 private void setSmsApp(String pkg) throws Exception { 525 executeWithShellPermissionIdentity(() -> { 526 Context context = getInstrumentation().getContext(); 527 CompletableFuture<Boolean> result = new CompletableFuture<>(); 528 context.getSystemService(RoleManager.class).addRoleHolderAsUser( 529 RoleManager.ROLE_SMS, pkg, RoleManager.MANAGE_HOLDERS_FLAG_DONT_KILL_APP, 530 context.getUser(), AsyncTask.THREAD_POOL_EXECUTOR, result::complete); 531 assertTrue(result.get(5, TimeUnit.SECONDS)); 532 }); 533 } 534 535 private <T> T executeWithShellPermissionIdentity(Callable<T> callable) throws Exception { 536 if (sHasShellPermissionIdentity) { 537 return callable.call(); 538 } 539 UiAutomation uiAutomation = getInstrumentation().getUiAutomation( 540 UiAutomation.FLAG_DONT_SUPPRESS_ACCESSIBILITY_SERVICES); 541 uiAutomation.adoptShellPermissionIdentity(); 542 try { 543 sHasShellPermissionIdentity = true; 544 return callable.call(); 545 } finally { 546 uiAutomation.dropShellPermissionIdentity(); 547 sHasShellPermissionIdentity = false; 548 } 549 } 550 551 private void executeWithShellPermissionIdentity(RunnableWithException runnable) 552 throws Exception { 553 executeWithShellPermissionIdentity(() -> { 554 runnable.run(); 555 return null; 556 }); 557 } 558 559 private interface RunnableWithException { 560 void run() throws Exception; 561 } 562 563 private void assertCanAccessSms(String pkg) throws Exception { 564 CompletableFuture<Bundle> callbackResult = new CompletableFuture<>(); 565 mContext.startActivity(new Intent() 566 .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK) 567 .setComponent(new ComponentName(pkg, pkg + ".MainActivity")) 568 .putExtra("callback", new RemoteCallback(callbackResult::complete))); 569 570 Bundle bundle = callbackResult.get(20, TimeUnit.SECONDS); 571 572 assertThat(bundle.getString("class"), startsWith(pkg)); 573 assertThat(bundle.getString("exceptionMessage"), anyOf(equalTo(null), emptyString())); 574 assertThat(bundle.getInt("queryCount"), greaterThan(0)); 575 } 576 577 private void init() { 578 mSendReceiver.reset(); 579 mDeliveryReceiver.reset(); 580 mDataSmsReceiver.reset(); 581 mSmsDeliverReceiver.reset(); 582 mSmsReceivedReceiver.reset(); 583 mSmsRetrieverReceiver.reset(); 584 mReceivedDataSms = false; 585 mSentIntent = PendingIntent.getBroadcast(mContext, 0, mSendIntent, 586 PendingIntent.FLAG_ONE_SHOT); 587 mDeliveredIntent = PendingIntent.getBroadcast(mContext, 0, mDeliveryIntent, 588 PendingIntent.FLAG_ONE_SHOT); 589 } 590 591 private void setupBroadcastReceivers() { 592 mSendIntent = new Intent(SMS_SEND_ACTION); 593 mDeliveryIntent = new Intent(SMS_DELIVERY_ACTION); 594 595 IntentFilter sendIntentFilter = new IntentFilter(SMS_SEND_ACTION); 596 IntentFilter deliveryIntentFilter = new IntentFilter(SMS_DELIVERY_ACTION); 597 IntentFilter dataSmsReceivedIntentFilter = new IntentFilter(DATA_SMS_RECEIVED_ACTION); 598 IntentFilter smsDeliverIntentFilter = new IntentFilter(SMS_DELIVER_DEFAULT_APP_ACTION); 599 IntentFilter smsReceivedIntentFilter = 600 new IntentFilter(Telephony.Sms.Intents.SMS_RECEIVED_ACTION); 601 IntentFilter smsRetrieverIntentFilter = new IntentFilter(SMS_RETRIEVER_ACTION); 602 dataSmsReceivedIntentFilter.addDataScheme("sms"); 603 dataSmsReceivedIntentFilter.addDataAuthority("localhost", "19989"); 604 605 mSendReceiver = new SmsBroadcastReceiver(SMS_SEND_ACTION); 606 mDeliveryReceiver = new SmsBroadcastReceiver(SMS_DELIVERY_ACTION); 607 mDataSmsReceiver = new SmsBroadcastReceiver(DATA_SMS_RECEIVED_ACTION); 608 mSmsDeliverReceiver = new SmsBroadcastReceiver(SMS_DELIVER_DEFAULT_APP_ACTION); 609 mSmsReceivedReceiver = new SmsBroadcastReceiver(Telephony.Sms.Intents.SMS_RECEIVED_ACTION); 610 mSmsRetrieverReceiver = new SmsBroadcastReceiver(SMS_RETRIEVER_ACTION); 611 612 mContext.registerReceiver(mSendReceiver, sendIntentFilter); 613 mContext.registerReceiver(mDeliveryReceiver, deliveryIntentFilter); 614 mContext.registerReceiver(mDataSmsReceiver, dataSmsReceivedIntentFilter); 615 mContext.registerReceiver(mSmsDeliverReceiver, smsDeliverIntentFilter); 616 mContext.registerReceiver(mSmsReceivedReceiver, smsReceivedIntentFilter); 617 mContext.registerReceiver(mSmsRetrieverReceiver, smsRetrieverIntentFilter); 618 } 619 620 /** 621 * Returns the number of parts sent in the message. If Multi-part SMS is not supported, 622 * returns 0. 623 */ 624 private int sendMultipartTextMessageIfSupported(String mccmnc) { 625 int numPartsSent = 0; 626 if (!CarrierCapability.UNSUPPORT_MULTIPART_SMS_MESSAGES.contains(mccmnc)) { 627 init(); 628 ArrayList<String> parts = divideMessage(LONG_TEXT); 629 numPartsSent = parts.size(); 630 ArrayList<PendingIntent> sentIntents = new ArrayList<PendingIntent>(); 631 ArrayList<PendingIntent> deliveryIntents = new ArrayList<PendingIntent>(); 632 for (int i = 0; i < numPartsSent; i++) { 633 sentIntents.add(PendingIntent.getBroadcast(mContext, 0, mSendIntent, 0)); 634 deliveryIntents.add(PendingIntent.getBroadcast(mContext, 0, mDeliveryIntent, 0)); 635 } 636 sendMultiPartTextMessage(mDestAddr, parts, sentIntents, deliveryIntents); 637 } 638 return numPartsSent; 639 } 640 641 private boolean sendDataMessageIfSupported(String mccmnc) { 642 if (!CarrierCapability.UNSUPPORT_DATA_SMS_MESSAGES.contains(mccmnc)) { 643 byte[] data = mText.getBytes(); 644 short port = 19989; 645 646 init(); 647 sendDataMessage(mDestAddr, port, data, mSentIntent, mDeliveredIntent); 648 return true; 649 } 650 return false; 651 } 652 653 @Test 654 public void testGetDefault() { 655 assertNotNull(getSmsManager()); 656 } 657 658 protected ArrayList<String> divideMessage(String text) { 659 return getSmsManager().divideMessage(text); 660 } 661 662 private android.telephony.SmsManager getSmsManager() { 663 return android.telephony.SmsManager.getDefault(); 664 } 665 666 protected void sendMultiPartTextMessage(String destAddr, ArrayList<String> parts, 667 ArrayList<PendingIntent> sentIntents, ArrayList<PendingIntent> deliveryIntents) { 668 getSmsManager().sendMultipartTextMessage(destAddr, null, parts, sentIntents, deliveryIntents); 669 } 670 671 protected void sendDataMessage(String destAddr,short port, byte[] data, PendingIntent sentIntent, PendingIntent deliveredIntent) { 672 getSmsManager().sendDataMessage(destAddr, null, port, data, sentIntent, deliveredIntent); 673 } 674 675 protected void sendTextMessage(String destAddr, String text, PendingIntent sentIntent, PendingIntent deliveredIntent) { 676 getSmsManager().sendTextMessage(destAddr, null, text, sentIntent, deliveredIntent); 677 } 678 679 private void blockNumber(String number) { 680 mBlockedNumberUri = insertBlockedNumber(mContext, number); 681 } 682 683 private void unblockNumber(Uri uri) { 684 deleteBlockedNumber(mContext, uri); 685 } 686 687 private void setDefaultSmsApp(boolean setToSmsApp) 688 throws Exception { 689 String command = String.format( 690 "appops set --user 0 %s WRITE_SMS %s", 691 mContext.getPackageName(), 692 setToSmsApp ? "allow" : "default"); 693 assertTrue("Setting default SMS app failed : " + setToSmsApp, 694 executeShellCommand(command).isEmpty()); 695 mTestAppSetAsDefaultSmsApp = setToSmsApp; 696 } 697 698 private String executeShellCommand(String command) 699 throws IOException { 700 ParcelFileDescriptor pfd = 701 getInstrumentation().getUiAutomation().executeShellCommand(command); 702 BufferedReader br = null; 703 try (InputStream in = new FileInputStream(pfd.getFileDescriptor());) { 704 br = new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8)); 705 String str; 706 StringBuilder out = new StringBuilder(); 707 while ((str = br.readLine()) != null) { 708 out.append(str); 709 } 710 return out.toString(); 711 } finally { 712 if (br != null) { 713 br.close(); 714 } 715 } 716 } 717 718 private static class SmsBroadcastReceiver extends BroadcastReceiver { 719 private int mCalls; 720 private int mExpectedCalls; 721 private String mAction; 722 private Object mLock; 723 724 SmsBroadcastReceiver(String action) { 725 mAction = action; 726 reset(); 727 mLock = new Object(); 728 } 729 730 void reset() { 731 mExpectedCalls = Integer.MAX_VALUE; 732 mCalls = 0; 733 } 734 735 @Override 736 public void onReceive(Context context, Intent intent) { 737 if(mAction.equals(DATA_SMS_RECEIVED_ACTION)){ 738 StringBuilder sb = new StringBuilder(); 739 Bundle bundle = intent.getExtras(); 740 if (bundle != null) { 741 Object[] obj = (Object[]) bundle.get("pdus"); 742 String format = bundle.getString("format"); 743 SmsMessage[] message = new SmsMessage[obj.length]; 744 for (int i = 0; i < obj.length; i++) { 745 message[i] = SmsMessage.createFromPdu((byte[]) obj[i], format); 746 } 747 748 for (SmsMessage currentMessage : message) { 749 byte[] binaryContent = currentMessage.getUserData(); 750 String readableContent = new String(binaryContent); 751 sb.append(readableContent); 752 } 753 } 754 mReceivedDataSms = true; 755 mReceivedText=sb.toString(); 756 } 757 Log.i(TAG, "onReceive " + intent.getAction()); 758 if (intent.getAction().equals(mAction)) { 759 synchronized (mLock) { 760 mCalls += 1; 761 mLock.notify(); 762 } 763 } 764 } 765 766 private boolean verifyNoCalls(long timeout) throws InterruptedException { 767 synchronized(mLock) { 768 mLock.wait(timeout); 769 return mCalls == 0; 770 } 771 } 772 773 public boolean waitForCalls(int expectedCalls, long timeout) throws InterruptedException { 774 synchronized(mLock) { 775 mExpectedCalls = expectedCalls; 776 long startTime = SystemClock.elapsedRealtime(); 777 778 while (mCalls < mExpectedCalls) { 779 long waitTime = timeout - (SystemClock.elapsedRealtime() - startTime); 780 if (waitTime > 0) { 781 mLock.wait(waitTime); 782 } else { 783 return false; // timed out 784 } 785 } 786 return true; // success 787 } 788 } 789 } 790 } 791