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 androidx.test.InstrumentationRegistry.getContext; 20 import static androidx.test.InstrumentationRegistry.getInstrumentation; 21 22 import static com.android.compatibility.common.util.BlockedNumberUtil.deleteBlockedNumber; 23 import static com.android.compatibility.common.util.BlockedNumberUtil.insertBlockedNumber; 24 25 import static org.hamcrest.Matchers.anyOf; 26 import static org.hamcrest.Matchers.emptyString; 27 import static org.hamcrest.Matchers.equalTo; 28 import static org.hamcrest.Matchers.greaterThan; 29 import static org.hamcrest.Matchers.startsWith; 30 import static org.junit.Assert.assertEquals; 31 import static org.junit.Assert.assertFalse; 32 import static org.junit.Assert.assertNotEquals; 33 import static org.junit.Assert.assertNotNull; 34 import static org.junit.Assert.assertThat; 35 import static org.junit.Assert.assertTrue; 36 import static org.junit.Assert.fail; 37 import static org.junit.Assume.assumeNoException; 38 import static org.junit.Assume.assumeTrue; 39 40 import android.Manifest; 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.net.Uri; 54 import android.os.AsyncTask; 55 import android.os.Bundle; 56 import android.os.ParcelFileDescriptor; 57 import android.os.RemoteCallback; 58 import android.os.SystemClock; 59 import android.provider.Telephony; 60 import android.telephony.SmsCbMessage; 61 import android.telephony.SmsManager; 62 import android.telephony.SmsMessage; 63 import android.telephony.SubscriptionManager; 64 import android.telephony.TelephonyManager; 65 import android.telephony.cdma.CdmaSmsCbProgramData; 66 import android.telephony.cts.util.DefaultSmsAppHelper; 67 import android.telephony.cts.util.TelephonyUtils; 68 import android.text.TextUtils; 69 import android.util.Log; 70 71 import androidx.test.InstrumentationRegistry; 72 73 import com.android.compatibility.common.util.ApiTest; 74 import com.android.compatibility.common.util.ShellIdentityUtils; 75 76 import org.junit.After; 77 import org.junit.Before; 78 import org.junit.Test; 79 80 import java.io.BufferedReader; 81 import java.io.FileInputStream; 82 import java.io.IOException; 83 import java.io.InputStream; 84 import java.io.InputStreamReader; 85 import java.nio.charset.StandardCharsets; 86 import java.util.ArrayList; 87 import java.util.Date; 88 import java.util.List; 89 import java.util.concurrent.Callable; 90 import java.util.concurrent.CompletableFuture; 91 import java.util.concurrent.TimeUnit; 92 93 /** 94 * Tests for {@link android.telephony.SmsManager}. 95 * 96 * Structured so tests can be reused to test {@link android.telephony.gsm.SmsManager} 97 */ 98 public class SmsManagerTest { 99 100 private static final String TAG = "SmsManagerTest"; 101 private static final String LONG_TEXT = 102 "This is a very long text. This text should be broken into three " + 103 "separate messages.This is a very long text. This text should be broken into " + 104 "three separate messages.This is a very long text. This text should be broken " + 105 "into three separate messages.This is a very long text. This text should be " + 106 "broken into three separate messages.";; 107 private static final String LONG_TEXT_WITH_32BIT_CHARS = 108 "Long dkkshsh jdjsusj kbsksbdf jfkhcu hhdiwoqiwyrygrvn?*?*!\";:'/,." 109 + "__?9#9292736&4;\"$+$+((]\\[\\℅©℅™^®°¥°¥=¢£}}£∆~¶~÷|√×." 110 + " ⛪⛲ "; 111 112 private static final String SMS_SEND_ACTION = "CTS_SMS_SEND_ACTION"; 113 private static final String SMS_DELIVERY_ACTION = "CTS_SMS_DELIVERY_ACTION"; 114 private static final String DATA_SMS_RECEIVED_ACTION = "android.intent.action.DATA_SMS_RECEIVED"; 115 public static final String SMS_DELIVER_DEFAULT_APP_ACTION = "CTS_SMS_DELIVERY_ACTION_DEFAULT_APP"; 116 public static final String LEGACY_SMS_APP = "android.telephony.cts.sms23"; 117 public static final String MODERN_SMS_APP = "android.telephony.cts.sms"; 118 private static final String SMS_RETRIEVER_APP = "android.telephony.cts.smsretriever"; 119 private static final String SMS_RETRIEVER_ACTION = "CTS_SMS_RETRIEVER_ACTION"; 120 private static final String FINANCIAL_SMS_APP = "android.telephony.cts.financialsms"; 121 122 private TelephonyManager mTelephonyManager; 123 private SubscriptionManager mSubscriptionManager; 124 private String mDestAddr; 125 private String mText; 126 private SmsBroadcastReceiver mSendReceiver; 127 private SmsBroadcastReceiver mDeliveryReceiver; 128 private SmsBroadcastReceiver mDataSmsReceiver; 129 private SmsBroadcastReceiver mSmsDeliverReceiver; 130 private SmsBroadcastReceiver mSmsReceivedReceiver; 131 private SmsBroadcastReceiver mSmsRetrieverReceiver; 132 private PendingIntent mSentIntent; 133 private PendingIntent mDeliveredIntent; 134 private Intent mSendIntent; 135 private Intent mDeliveryIntent; 136 private Context mContext; 137 private Uri mBlockedNumberUri; 138 private boolean mTestAppSetAsDefaultSmsApp; 139 private boolean mDeliveryReportSupported; 140 private static boolean mReceivedDataSms; 141 private static String mReceivedText; 142 private static boolean sHasShellPermissionIdentity = false; 143 private static long sMessageId = 0L; 144 145 private static final int TIME_OUT = 1000 * 60 * 10; 146 private static final int NO_CALLS_TIMEOUT_MILLIS = 1000; // 1 second 147 148 @Before setUp()149 public void setUp() throws Exception { 150 assumeTrue(getContext().getPackageManager().hasSystemFeature( 151 PackageManager.FEATURE_TELEPHONY_MESSAGING)); 152 153 mContext = getContext(); 154 mTelephonyManager = mContext.getSystemService(TelephonyManager.class); 155 mSubscriptionManager = mContext.getSystemService(SubscriptionManager.class); 156 mText = "This is a test message"; 157 158 executeWithShellPermissionIdentity(() -> { 159 mDestAddr = mSubscriptionManager.getPhoneNumber(mTelephonyManager.getSubscriptionId()); 160 }); 161 162 // exclude the networks that don't support SMS delivery report 163 String mccmnc = mTelephonyManager.getSimOperator(); 164 mDeliveryReportSupported = !(CarrierCapability.NO_DELIVERY_REPORTS.contains(mccmnc)); 165 166 // register receivers 167 mSendIntent = new Intent(SMS_SEND_ACTION).setPackage(mContext.getPackageName()); 168 mDeliveryIntent = new Intent(SMS_DELIVERY_ACTION).setPackage(mContext.getPackageName()); 169 170 IntentFilter sendIntentFilter = new IntentFilter(SMS_SEND_ACTION); 171 IntentFilter deliveryIntentFilter = new IntentFilter(SMS_DELIVERY_ACTION); 172 IntentFilter dataSmsReceivedIntentFilter = new IntentFilter(DATA_SMS_RECEIVED_ACTION); 173 IntentFilter smsDeliverIntentFilter = new IntentFilter(SMS_DELIVER_DEFAULT_APP_ACTION); 174 IntentFilter smsReceivedIntentFilter = 175 new IntentFilter(Telephony.Sms.Intents.SMS_RECEIVED_ACTION); 176 IntentFilter smsRetrieverIntentFilter = new IntentFilter(SMS_RETRIEVER_ACTION); 177 dataSmsReceivedIntentFilter.addDataScheme("sms"); 178 dataSmsReceivedIntentFilter.addDataAuthority("localhost", "19989"); 179 180 mSendReceiver = new SmsBroadcastReceiver(SMS_SEND_ACTION); 181 mDeliveryReceiver = new SmsBroadcastReceiver(SMS_DELIVERY_ACTION); 182 mDataSmsReceiver = new SmsBroadcastReceiver(DATA_SMS_RECEIVED_ACTION); 183 mSmsDeliverReceiver = new SmsBroadcastReceiver(SMS_DELIVER_DEFAULT_APP_ACTION); 184 mSmsReceivedReceiver = new SmsBroadcastReceiver(Telephony.Sms.Intents.SMS_RECEIVED_ACTION); 185 mSmsRetrieverReceiver = new SmsBroadcastReceiver(SMS_RETRIEVER_ACTION); 186 187 mContext.registerReceiver(mSendReceiver, sendIntentFilter, 188 Context.RECEIVER_EXPORTED_UNAUDITED); 189 mContext.registerReceiver(mDeliveryReceiver, deliveryIntentFilter, 190 Context.RECEIVER_EXPORTED_UNAUDITED); 191 mContext.registerReceiver(mDataSmsReceiver, dataSmsReceivedIntentFilter, 192 Context.RECEIVER_EXPORTED_UNAUDITED); 193 mContext.registerReceiver(mSmsDeliverReceiver, smsDeliverIntentFilter, 194 Context.RECEIVER_EXPORTED_UNAUDITED); 195 mContext.registerReceiver(mSmsReceivedReceiver, smsReceivedIntentFilter); 196 mContext.registerReceiver(mSmsRetrieverReceiver, smsRetrieverIntentFilter, 197 Context.RECEIVER_EXPORTED_UNAUDITED); 198 199 DefaultSmsAppHelper.stopBeingDefaultSmsApp(); 200 } 201 202 @After tearDown()203 public void tearDown() throws Exception { 204 if (mBlockedNumberUri != null) { 205 unblockNumber(mBlockedNumberUri); 206 mBlockedNumberUri = null; 207 } 208 if (mTestAppSetAsDefaultSmsApp) { 209 setDefaultSmsApp(false); 210 } 211 212 // unregister receivers 213 if (mSendReceiver != null) { 214 mContext.unregisterReceiver(mSendReceiver); 215 } 216 if (mDeliveryReceiver != null) { 217 mContext.unregisterReceiver(mDeliveryReceiver); 218 } 219 if (mDataSmsReceiver != null) { 220 mContext.unregisterReceiver(mDataSmsReceiver); 221 } 222 if (mSmsDeliverReceiver != null) { 223 mContext.unregisterReceiver(mSmsDeliverReceiver); 224 } 225 if (mSmsReceivedReceiver != null) { 226 mContext.unregisterReceiver(mSmsReceivedReceiver); 227 } 228 if (mSmsRetrieverReceiver != null) { 229 mContext.unregisterReceiver(mSmsRetrieverReceiver); 230 } 231 } 232 233 @Test testDivideMessage()234 public void testDivideMessage() { 235 ArrayList<String> dividedMessages = divideMessage(LONG_TEXT); 236 assertNotNull(dividedMessages); 237 if (TelephonyUtils.isSkt(mTelephonyManager)) { 238 assertTrue(isComplete(dividedMessages, 5, LONG_TEXT) 239 || isComplete(dividedMessages, 3, LONG_TEXT)); 240 } else if (TelephonyUtils.isKt(mTelephonyManager)) { 241 assertTrue(isComplete(dividedMessages, 4, LONG_TEXT) 242 || isComplete(dividedMessages, 3, LONG_TEXT)); 243 } else { 244 assertTrue(isComplete(dividedMessages, 3, LONG_TEXT)); 245 } 246 } 247 248 @Test testDivideUnicodeMessage()249 public void testDivideUnicodeMessage() { 250 ArrayList<String> dividedMessages = divideMessage(LONG_TEXT_WITH_32BIT_CHARS); 251 assertNotNull(dividedMessages); 252 assertTrue(isComplete(dividedMessages, 3, LONG_TEXT_WITH_32BIT_CHARS)); 253 for (String messagePiece : dividedMessages) { 254 assertFalse(Character.isHighSurrogate( 255 messagePiece.charAt(messagePiece.length() - 1))); 256 } 257 } 258 isComplete(List<String> dividedMessages, int numParts, String longText)259 private boolean isComplete(List<String> dividedMessages, int numParts, String longText) { 260 if (dividedMessages.size() != numParts) { 261 return false; 262 } 263 264 String actualMessage = ""; 265 for (int i = 0; i < numParts; i++) { 266 actualMessage += dividedMessages.get(i); 267 } 268 return longText.equals(actualMessage); 269 } 270 271 @Test testSmsRetriever()272 public void testSmsRetriever() throws Exception { 273 assertFalse("[RERUN] SIM card does not provide phone number. Use a suitable SIM Card.", 274 TextUtils.isEmpty(mDestAddr)); 275 276 String mccmnc = mTelephonyManager.getSimOperator(); 277 int carrierId = mTelephonyManager.getSimCarrierId(); 278 assertFalse("[RERUN] Carrier [carrier-id: " + carrierId + "] does not support " 279 + "loop back messages. Use another carrier.", 280 CarrierCapability.UNSUPPORT_LOOP_BACK_MESSAGES.contains(carrierId)); 281 282 init(); 283 284 CompletableFuture<Bundle> callbackResult = new CompletableFuture<>(); 285 286 mContext.startActivity(new Intent() 287 .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK) 288 .setComponent(new ComponentName( 289 SMS_RETRIEVER_APP, SMS_RETRIEVER_APP + ".MainActivity")) 290 .putExtra("callback", new RemoteCallback(callbackResult::complete))); 291 292 293 Bundle bundle = callbackResult.get(200, TimeUnit.SECONDS); 294 String token = bundle.getString("token"); 295 assertThat(bundle.getString("class"), startsWith(SMS_RETRIEVER_APP)); 296 assertNotNull(token); 297 298 String composedText = "testprefix1" + mText + token; 299 sendTextMessage(mDestAddr, composedText, null, null); 300 301 assertTrue("[RERUN] SMS retriever message not received. Check signal.", 302 mSmsRetrieverReceiver.waitForCalls(1, TIME_OUT)); 303 } 304 sendAndReceiveSms(boolean addMessageId, boolean defaultSmsApp)305 private void sendAndReceiveSms(boolean addMessageId, boolean defaultSmsApp) throws Exception { 306 // send single text sms 307 init(); 308 if (addMessageId) { 309 long fakeMessageId = 19812L; 310 sendTextMessageWithMessageId(mDestAddr, 311 String.valueOf(SystemClock.elapsedRealtimeNanos()), mSentIntent, 312 mDeliveredIntent, fakeMessageId); 313 } else { 314 sendTextMessage(mDestAddr, String.valueOf(SystemClock.elapsedRealtimeNanos()), 315 mSentIntent, mDeliveredIntent); 316 } 317 assertTrue("[RERUN] Could not send SMS. Check signal.", 318 mSendReceiver.waitForCalls(1, TIME_OUT)); 319 if (mDeliveryReportSupported) { 320 assertTrue("[RERUN] SMS message delivery notification not received. Check signal.", 321 mDeliveryReceiver.waitForCalls(1, TIME_OUT)); 322 } 323 324 assertTrue(mSmsReceivedReceiver.waitForCalls(1, TIME_OUT)); 325 // Received SMS should always contain a generated messageId 326 assertNotEquals(0L, sMessageId); 327 328 if (defaultSmsApp) { 329 // default app should receive SMS_DELIVER_ACTION 330 assertTrue(mSmsDeliverReceiver.waitForCalls(1, TIME_OUT)); 331 } else { 332 // non-default app should receive only SMS_RECEIVED_ACTION 333 assertTrue(mSmsDeliverReceiver.verifyNoCalls(NO_CALLS_TIMEOUT_MILLIS)); 334 } 335 } 336 sendAndReceiveMultipartSms(String mccmnc, boolean addMessageId, boolean defaultSmsApp)337 private void sendAndReceiveMultipartSms(String mccmnc, boolean addMessageId, 338 boolean defaultSmsApp) throws Exception { 339 sMessageId = 0L; 340 int numPartsSent = sendMultipartTextMessageIfSupported(mccmnc, addMessageId); 341 if (numPartsSent > 0) { 342 assertTrue("[RERUN] Could not send multi part SMS. Check signal.", 343 mSendReceiver.waitForCalls(numPartsSent, TIME_OUT)); 344 if (mDeliveryReportSupported) { 345 assertTrue("[RERUN] Multi part SMS message delivery notification not received. " 346 + "Check signal.", mDeliveryReceiver.waitForCalls(numPartsSent, TIME_OUT)); 347 } 348 349 assertTrue(mSmsReceivedReceiver.waitForCalls(1, TIME_OUT)); 350 // Received SMS should contain a generated messageId 351 assertNotEquals(0L, sMessageId); 352 353 if (defaultSmsApp) { 354 // default app should receive SMS_DELIVER_ACTION 355 assertTrue(mSmsDeliverReceiver.waitForCalls(1, TIME_OUT)); 356 } else { 357 // non-default app should receive only SMS_RECEIVED_ACTION 358 assertTrue(mSmsDeliverReceiver.verifyNoCalls(NO_CALLS_TIMEOUT_MILLIS)); 359 } 360 } else { 361 // This GSM network doesn't support Multipart SMS message. 362 // Skip the test. 363 } 364 } 365 sendDataSms(String mccmnc)366 private void sendDataSms(String mccmnc) throws Exception { 367 if (sendDataMessageIfSupported(mccmnc)) { 368 assertTrue("[RERUN] Could not send data SMS. Check signal.", 369 mSendReceiver.waitForCalls(1, TIME_OUT)); 370 if (mDeliveryReportSupported) { 371 assertTrue("[RERUN] Data SMS message delivery notification not received. " + 372 "Check signal.", mDeliveryReceiver.waitForCalls(1, TIME_OUT)); 373 } 374 mDataSmsReceiver.waitForCalls(1, TIME_OUT); 375 assertTrue("[RERUN] Data SMS message not received. Check signal.", mReceivedDataSms); 376 assertEquals(mReceivedText, mText); 377 } else { 378 // This GSM network doesn't support Data(binary) SMS message. 379 // Skip the test. 380 } 381 } 382 383 @Test(timeout = 10 * 60 * 1000) 384 @ApiTest(apis = { 385 "android.telephony.SmsManager#sendTextMessage", 386 "android.telephony.SmsManager#sendDataMessage", 387 "android.telephony.SmsManager#sendMultipartTextMessage"}) testSendAndReceiveMessages()388 public void testSendAndReceiveMessages() throws Exception { 389 // Test non-default SMS app 390 testSendAndReceiveMessages(false); 391 392 // Test default SMS app 393 DefaultSmsAppHelper.ensureDefaultSmsApp(); 394 testSendAndReceiveMessages(true); 395 DefaultSmsAppHelper.stopBeingDefaultSmsApp(); 396 } 397 testSendAndReceiveMessages(boolean defaultSmsApp)398 private void testSendAndReceiveMessages(boolean defaultSmsApp) throws Exception { 399 assertFalse("[RERUN] SIM card does not provide phone number. Use a suitable SIM Card.", 400 TextUtils.isEmpty(mDestAddr)); 401 402 String mccmnc = mTelephonyManager.getSimOperator(); 403 int carrierId = mTelephonyManager.getSimCarrierId(); 404 assertFalse("[RERUN] Carrier [carrier-id: " + carrierId + "] does not support " 405 + "loop back messages. Use another carrier.", 406 CarrierCapability.UNSUPPORT_LOOP_BACK_MESSAGES.contains(carrierId)); 407 408 // send/receive single text sms with and without messageId 409 sendAndReceiveSms(/* addMessageId= */ true, defaultSmsApp); 410 sendAndReceiveSms(/* addMessageId= */ false, defaultSmsApp); 411 412 413 if (mTelephonyManager.getPhoneType() == TelephonyManager.PHONE_TYPE_CDMA) { 414 // TODO: temp workaround, OCTET encoding for EMS not properly supported 415 return; 416 } 417 418 // send/receive data sms 419 sendDataSms(mccmnc); 420 421 // send/receive multi part text sms with and without messageId 422 sendAndReceiveMultipartSms(mccmnc, /* addMessageId= */ true, defaultSmsApp); 423 sendAndReceiveMultipartSms(mccmnc, /* addMessageId= */ false, defaultSmsApp); 424 } 425 426 @Test testSmsBlocking()427 public void testSmsBlocking() throws Exception { 428 assertFalse("[RERUN] SIM card does not provide phone number. Use a suitable SIM Card.", 429 TextUtils.isEmpty(mDestAddr)); 430 431 // disable suppressing blocking. 432 TelephonyUtils.endBlockSuppression(getInstrumentation()); 433 434 String mccmnc = mTelephonyManager.getSimOperator(); 435 // Setting default SMS App is needed to be able to block numbers. 436 setDefaultSmsApp(true); 437 blockNumber(mDestAddr); 438 439 // single-part SMS blocking 440 init(); 441 sendTextMessage(mDestAddr, String.valueOf(SystemClock.elapsedRealtimeNanos()), 442 mSentIntent, mDeliveredIntent); 443 assertTrue("[RERUN] Could not send SMS. Check signal.", 444 mSendReceiver.waitForCalls(1, TIME_OUT)); 445 assertTrue("Expected no messages to be received due to number blocking.", 446 mSmsReceivedReceiver.verifyNoCalls(NO_CALLS_TIMEOUT_MILLIS)); 447 assertTrue("Expected no messages to be delivered due to number blocking.", 448 mSmsDeliverReceiver.verifyNoCalls(NO_CALLS_TIMEOUT_MILLIS)); 449 450 // send data sms 451 if (!sendDataMessageIfSupported(mccmnc)) { 452 assertTrue("[RERUN] Could not send data SMS. Check signal.", 453 mSendReceiver.waitForCalls(1, TIME_OUT)); 454 if (mDeliveryReportSupported) { 455 assertTrue("[RERUN] Data SMS message delivery notification not received. " + 456 "Check signal.", mDeliveryReceiver.waitForCalls(1, TIME_OUT)); 457 } 458 assertTrue("Expected no messages to be delivered due to number blocking.", 459 mSmsDeliverReceiver.verifyNoCalls(NO_CALLS_TIMEOUT_MILLIS)); 460 } else { 461 // This GSM network doesn't support Data(binary) SMS message. 462 // Skip the test. 463 } 464 465 // multi-part SMS blocking 466 int numPartsSent = sendMultipartTextMessageIfSupported(mccmnc, /* addMessageId= */ false); 467 if (numPartsSent > 0) { 468 assertTrue("[RERUN] Could not send multi part SMS. Check signal.", 469 mSendReceiver.waitForCalls(numPartsSent, TIME_OUT)); 470 471 assertTrue("Expected no messages to be received due to number blocking.", 472 mSmsReceivedReceiver.verifyNoCalls(NO_CALLS_TIMEOUT_MILLIS)); 473 assertTrue("Expected no messages to be delivered due to number blocking.", 474 mSmsDeliverReceiver.verifyNoCalls(NO_CALLS_TIMEOUT_MILLIS)); 475 } else { 476 // This GSM network doesn't support Multipart SMS message. 477 // Skip the test. 478 } 479 } 480 481 @Test testGetSmsMessagesForFinancialAppPermissionRequestedNotGranted()482 public void testGetSmsMessagesForFinancialAppPermissionRequestedNotGranted() throws Exception { 483 CompletableFuture<Bundle> callbackResult = new CompletableFuture<>(); 484 485 mContext.startActivity(new Intent() 486 .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK) 487 .setComponent(new ComponentName(FINANCIAL_SMS_APP, FINANCIAL_SMS_APP + ".MainActivity")) 488 .putExtra("callback", new RemoteCallback(callbackResult::complete))); 489 490 Bundle bundle = callbackResult.get(500, TimeUnit.SECONDS); 491 492 assertThat(bundle.getString("class"), startsWith(FINANCIAL_SMS_APP)); 493 assertThat(bundle.getInt("rowNum"), equalTo(-1)); 494 } 495 496 @Test testGetSmsMessagesForFinancialAppPermissionRequestedGranted()497 public void testGetSmsMessagesForFinancialAppPermissionRequestedGranted() throws Exception { 498 CompletableFuture<Bundle> callbackResult = new CompletableFuture<>(); 499 String ctsPackageName = getInstrumentation().getContext().getPackageName(); 500 501 executeWithShellPermissionIdentity(() -> { 502 setModeForOps(FINANCIAL_SMS_APP, 503 AppOpsManager.MODE_ALLOWED, 504 AppOpsManager.OPSTR_SMS_FINANCIAL_TRANSACTIONS); 505 }); 506 mContext.startActivity(new Intent() 507 .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK) 508 .setComponent(new ComponentName(FINANCIAL_SMS_APP, FINANCIAL_SMS_APP + ".MainActivity")) 509 .putExtra("callback", new RemoteCallback(callbackResult::complete))); 510 511 512 Bundle bundle = callbackResult.get(500, TimeUnit.SECONDS); 513 514 assertThat(bundle.getString("class"), startsWith(FINANCIAL_SMS_APP)); 515 assertThat(bundle.getInt("rowNum"), equalTo(-1)); 516 } 517 518 @Test testSmsNotPersisted_failsWithoutCarrierPermissions()519 public void testSmsNotPersisted_failsWithoutCarrierPermissions() throws Exception { 520 assertFalse("[RERUN] SIM card does not provide phone number. Use a suitable SIM Card.", 521 TextUtils.isEmpty(mDestAddr)); 522 523 try { 524 getSmsManager().sendTextMessageWithoutPersisting(mDestAddr, null /*scAddress */, 525 mDestAddr, mSentIntent, mDeliveredIntent); 526 fail("We should get a SecurityException due to not having carrier privileges"); 527 } catch (SecurityException e) { 528 // Success 529 } 530 } 531 532 @Test testContentProviderAccessRestriction()533 public void testContentProviderAccessRestriction() throws Exception { 534 Uri dummySmsUri = null; 535 Context context = getInstrumentation().getContext(); 536 ContentResolver contentResolver = context.getContentResolver(); 537 int originalWriteSmsMode = -1; 538 String ctsPackageName = context.getPackageName(); 539 try { 540 // Insert some test sms 541 originalWriteSmsMode = context.getSystemService(AppOpsManager.class) 542 .unsafeCheckOpNoThrow(AppOpsManager.OPSTR_WRITE_SMS, 543 getPackageUid(ctsPackageName), ctsPackageName); 544 setModeForOps(ctsPackageName, 545 AppOpsManager.MODE_ALLOWED, AppOpsManager.OPSTR_WRITE_SMS); 546 ContentValues contentValues = new ContentValues(); 547 contentValues.put(Telephony.TextBasedSmsColumns.ADDRESS, "addr"); 548 contentValues.put(Telephony.TextBasedSmsColumns.READ, 1); 549 contentValues.put(Telephony.TextBasedSmsColumns.SUBJECT, "subj"); 550 contentValues.put(Telephony.TextBasedSmsColumns.BODY, "created_at_" 551 + new Date().toString().replace(" ", "_")); 552 553 dummySmsUri = contentResolver.insert(Telephony.Sms.CONTENT_URI, contentValues); 554 assertNotNull("Failed to insert test sms", dummySmsUri); 555 assertNotEquals("Failed to insert test sms", "0", dummySmsUri.getLastPathSegment()); 556 testSmsAccessAboutDefaultApp(LEGACY_SMS_APP); 557 testSmsAccessAboutDefaultApp(MODERN_SMS_APP); 558 } finally { 559 if (dummySmsUri != null && !"/0".equals(dummySmsUri.getLastPathSegment())) { 560 final Uri finalDummySmsUri = dummySmsUri; 561 executeWithShellPermissionIdentity(() -> contentResolver.delete(finalDummySmsUri, 562 null, null)); 563 } 564 if (originalWriteSmsMode >= 0) { 565 int finalOriginalWriteSmsMode = originalWriteSmsMode; 566 executeWithShellPermissionIdentity(() -> 567 setModeForOps(ctsPackageName, 568 finalOriginalWriteSmsMode, AppOpsManager.OPSTR_WRITE_SMS)); 569 } 570 } 571 } 572 testSmsAccessAboutDefaultApp(String pkg)573 private void testSmsAccessAboutDefaultApp(String pkg) 574 throws Exception { 575 String originalSmsApp = getSmsApp(); 576 assertNotEquals(pkg, originalSmsApp); 577 assertCanAccessSms(pkg); 578 try { 579 setSmsApp(pkg); 580 assertCanAccessSms(pkg); 581 } finally { 582 resetReadWriteSmsAppOps(pkg); 583 setSmsApp(originalSmsApp); 584 } 585 } 586 resetReadWriteSmsAppOps(String pkg)587 private void resetReadWriteSmsAppOps(String pkg) throws Exception { 588 setModeForOps(pkg, AppOpsManager.MODE_DEFAULT, 589 AppOpsManager.OPSTR_READ_SMS, AppOpsManager.OPSTR_WRITE_SMS); 590 } 591 setModeForOps(String pkg, int mode, String... ops)592 private void setModeForOps(String pkg, int mode, String... ops) throws Exception { 593 // We cannot reset these app ops to DEFAULT via current API, so we reset them manually here 594 // temporarily as we will rewrite how the default SMS app is setup later. 595 executeWithShellPermissionIdentity(() -> { 596 int uid = getPackageUid(pkg); 597 AppOpsManager appOpsManager = 598 getInstrumentation().getContext().getSystemService(AppOpsManager.class); 599 for (String op : ops) { 600 appOpsManager.setUidMode(op, uid, mode); 601 } 602 }); 603 } 604 getPackageUid(String pkg)605 private int getPackageUid(String pkg) throws PackageManager.NameNotFoundException { 606 return getInstrumentation().getContext().getPackageManager().getPackageUid(pkg, 0); 607 } 608 getSmsApp()609 private String getSmsApp() throws Exception { 610 return executeWithShellPermissionIdentity(() -> getInstrumentation() 611 .getContext() 612 .getSystemService(RoleManager.class) 613 .getRoleHolders(RoleManager.ROLE_SMS) 614 .get(0)); 615 } 616 setSmsApp(String pkg)617 private void setSmsApp(String pkg) throws Exception { 618 executeWithShellPermissionIdentity(() -> { 619 Context context = getInstrumentation().getContext(); 620 RoleManager roleManager = context.getSystemService(RoleManager.class); 621 CompletableFuture<Boolean> result = new CompletableFuture<>(); 622 if (roleManager.getRoleHoldersAsUser(RoleManager.ROLE_SMS, 623 context.getUser()).contains(pkg)) { 624 result.complete(true); 625 } else { 626 roleManager.addRoleHolderAsUser(RoleManager.ROLE_SMS, pkg, 627 RoleManager.MANAGE_HOLDERS_FLAG_DONT_KILL_APP, context.getUser(), 628 AsyncTask.THREAD_POOL_EXECUTOR, result::complete); 629 } 630 assertTrue(result.get(5, TimeUnit.SECONDS)); 631 }); 632 } 633 executeWithShellPermissionIdentity(Callable<T> callable)634 private <T> T executeWithShellPermissionIdentity(Callable<T> callable) throws Exception { 635 if (sHasShellPermissionIdentity) { 636 return callable.call(); 637 } 638 UiAutomation uiAutomation = getInstrumentation().getUiAutomation( 639 UiAutomation.FLAG_DONT_SUPPRESS_ACCESSIBILITY_SERVICES); 640 uiAutomation.adoptShellPermissionIdentity(); 641 try { 642 sHasShellPermissionIdentity = true; 643 return callable.call(); 644 } finally { 645 uiAutomation.dropShellPermissionIdentity(); 646 sHasShellPermissionIdentity = false; 647 } 648 } 649 executeWithShellPermissionIdentity(RunnableWithException runnable)650 private void executeWithShellPermissionIdentity(RunnableWithException runnable) 651 throws Exception { 652 executeWithShellPermissionIdentity(() -> { 653 runnable.run(); 654 return null; 655 }); 656 } 657 658 private interface RunnableWithException { run()659 void run() throws Exception; 660 } 661 assertCanAccessSms(String pkg)662 private void assertCanAccessSms(String pkg) throws Exception { 663 CompletableFuture<Bundle> callbackResult = new CompletableFuture<>(); 664 mContext.startActivity(new Intent() 665 .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK) 666 .setComponent(new ComponentName(pkg, pkg + ".MainActivity")) 667 .putExtra("callback", new RemoteCallback(callbackResult::complete))); 668 669 Bundle bundle = callbackResult.get(20, TimeUnit.SECONDS); 670 671 assertThat(bundle.getString("class"), startsWith(pkg)); 672 assertThat(bundle.getString("exceptionMessage"), anyOf(equalTo(null), emptyString())); 673 assertThat(bundle.getInt("queryCount"), greaterThan(0)); 674 } 675 init()676 private void init() { 677 mSendReceiver.reset(); 678 mDeliveryReceiver.reset(); 679 mDataSmsReceiver.reset(); 680 mSmsDeliverReceiver.reset(); 681 mSmsReceivedReceiver.reset(); 682 mSmsRetrieverReceiver.reset(); 683 mReceivedDataSms = false; 684 sMessageId = 0L; 685 mSentIntent = PendingIntent.getBroadcast(mContext, 0, mSendIntent, 686 PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_MUTABLE_UNAUDITED); 687 mDeliveredIntent = PendingIntent.getBroadcast(mContext, 0, mDeliveryIntent, 688 PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_MUTABLE_UNAUDITED); 689 } 690 691 /** 692 * Returns the number of parts sent in the message. If Multi-part SMS is not supported, 693 * returns 0. 694 */ sendMultipartTextMessageIfSupported(String mccmnc, boolean addMessageId)695 private int sendMultipartTextMessageIfSupported(String mccmnc, boolean addMessageId) { 696 int numPartsSent = 0; 697 if (!CarrierCapability.UNSUPPORT_MULTIPART_SMS_MESSAGES.contains(mccmnc)) { 698 init(); 699 ArrayList<String> parts = divideMessage(LONG_TEXT); 700 numPartsSent = parts.size(); 701 ArrayList<PendingIntent> sentIntents = new ArrayList<PendingIntent>(); 702 ArrayList<PendingIntent> deliveryIntents = new ArrayList<PendingIntent>(); 703 for (int i = 0; i < numPartsSent; i++) { 704 sentIntents.add(PendingIntent.getBroadcast(mContext, 0, mSendIntent, PendingIntent.FLAG_MUTABLE_UNAUDITED)); 705 deliveryIntents.add(PendingIntent.getBroadcast(mContext, 0, mDeliveryIntent, PendingIntent.FLAG_MUTABLE_UNAUDITED)); 706 } 707 sendMultiPartTextMessage(mDestAddr, parts, sentIntents, deliveryIntents, addMessageId); 708 } 709 return numPartsSent; 710 } 711 sendDataMessageIfSupported(String mccmnc)712 private boolean sendDataMessageIfSupported(String mccmnc) { 713 if (!CarrierCapability.UNSUPPORT_DATA_SMS_MESSAGES.contains(mccmnc)) { 714 byte[] data = mText.getBytes(); 715 short port = 19989; 716 717 init(); 718 sendDataMessage(mDestAddr, port, data, mSentIntent, mDeliveredIntent); 719 return true; 720 } 721 return false; 722 } 723 724 @Test testGetDefault()725 public void testGetDefault() { 726 assertNotNull(getSmsManager()); 727 } 728 729 @Test testGetSetSmscAddress()730 public void testGetSetSmscAddress() { 731 String smsc = null; 732 try { 733 smsc = getSmsManager().getSmscAddress(); 734 fail("SmsManager.getSmscAddress() should throw a SecurityException"); 735 } catch (SecurityException e) { 736 // expected 737 } 738 739 InstrumentationRegistry.getInstrumentation().getUiAutomation() 740 .adoptShellPermissionIdentity("android.permission.READ_PRIVILEGED_PHONE_STATE"); 741 try { 742 smsc = getSmsManager().getSmscAddress(); 743 } catch (SecurityException se) { 744 fail("Caller with READ_PRIVILEGED_PHONE_STATE should be able to call API"); 745 } finally { 746 InstrumentationRegistry.getInstrumentation().getUiAutomation() 747 .dropShellPermissionIdentity(); 748 } 749 750 try { 751 getSmsManager().setSmscAddress(smsc); 752 fail("SmsManager.setSmscAddress() should throw a SecurityException"); 753 } catch (SecurityException e) { 754 // expected 755 } 756 757 InstrumentationRegistry.getInstrumentation().getUiAutomation() 758 .adoptShellPermissionIdentity("android.permission.MODIFY_PHONE_STATE"); 759 try { 760 getSmsManager().setSmscAddress(smsc); 761 } catch (SecurityException se) { 762 fail("Caller with MODIFY_PHONE_STATE should be able to call API"); 763 } finally { 764 InstrumentationRegistry.getInstrumentation().getUiAutomation() 765 .dropShellPermissionIdentity(); 766 } 767 } 768 769 @Test testGetPremiumSmsConsent()770 public void testGetPremiumSmsConsent() { 771 try { 772 getSmsManager().getPremiumSmsConsent("fake package name"); 773 fail("SmsManager.getPremiumSmsConsent() should throw a SecurityException"); 774 } catch (SecurityException e) { 775 // expected 776 } 777 778 InstrumentationRegistry.getInstrumentation().getUiAutomation() 779 .adoptShellPermissionIdentity("android.permission.READ_PRIVILEGED_PHONE_STATE"); 780 try { 781 getSmsManager().getPremiumSmsConsent("fake package name"); 782 fail("Caller with permission but only phone/system uid is allowed"); 783 } catch (SecurityException se) { 784 // expected 785 } finally { 786 InstrumentationRegistry.getInstrumentation().getUiAutomation() 787 .dropShellPermissionIdentity(); 788 } 789 } 790 791 @Test testSetPremiumSmsConsent()792 public void testSetPremiumSmsConsent() { 793 try { 794 getSmsManager().setPremiumSmsConsent("fake package name", 0); 795 fail("SmsManager.setPremiumSmsConsent() should throw a SecurityException"); 796 } catch (SecurityException e) { 797 // expected 798 } 799 800 InstrumentationRegistry.getInstrumentation().getUiAutomation() 801 .adoptShellPermissionIdentity("android.permission.MODIFY_PHONE_STATE"); 802 try { 803 getSmsManager().setPremiumSmsConsent("fake package name", 0); 804 fail("Caller with permission but only phone/system uid is allowed"); 805 } catch (SecurityException se) { 806 // expected 807 } finally { 808 InstrumentationRegistry.getInstrumentation().getUiAutomation() 809 .dropShellPermissionIdentity(); 810 } 811 } 812 813 /** 814 * Verify that SmsManager.getSmsCapacityOnIcc requires Permission. 815 * <p> 816 * Requires Permission: 817 * {@link android.Manifest.permission#READ_PHONE_STATE}. 818 */ 819 @Test testGetSmsCapacityOnIcc()820 public void testGetSmsCapacityOnIcc() { 821 try { 822 getSmsManager().getSmsCapacityOnIcc(); 823 } catch (SecurityException e) { 824 fail("Caller with READ_PHONE_STATE should be able to call API"); 825 } 826 } 827 828 @Test testDisableCellBroadcastRange()829 public void testDisableCellBroadcastRange() { 830 try { 831 int ranType = SmsCbMessage.MESSAGE_FORMAT_3GPP; 832 executeWithShellPermissionIdentity(() -> { 833 getSmsManager().disableCellBroadcastRange( 834 CdmaSmsCbProgramData.CATEGORY_CMAS_PRESIDENTIAL_LEVEL_ALERT, 835 CdmaSmsCbProgramData.CATEGORY_CMAS_EXTREME_THREAT, 836 ranType); 837 }); 838 } catch (Exception e) { 839 // expected 840 } 841 } 842 843 @Test testEnableCellBroadcastRange()844 public void testEnableCellBroadcastRange() { 845 try { 846 int ranType = SmsCbMessage.MESSAGE_FORMAT_3GPP; 847 executeWithShellPermissionIdentity(() -> { 848 getSmsManager().enableCellBroadcastRange( 849 CdmaSmsCbProgramData.CATEGORY_CMAS_PRESIDENTIAL_LEVEL_ALERT, 850 CdmaSmsCbProgramData.CATEGORY_CMAS_EXTREME_THREAT, 851 ranType); 852 }); 853 } catch (Exception e) { 854 // expected 855 } 856 } 857 858 @Test testResetAllCellBroadcastRanges()859 public void testResetAllCellBroadcastRanges() { 860 try { 861 executeWithShellPermissionIdentity(() -> { 862 getSmsManager().resetAllCellBroadcastRanges(); 863 }); 864 } catch (Exception e) { 865 // expected 866 } 867 } 868 869 @Test testCreateForSubscriptionId()870 public void testCreateForSubscriptionId() { 871 int testSubId = 123; 872 SmsManager smsManager = mContext.getSystemService(SmsManager.class) 873 .createForSubscriptionId(testSubId); 874 assertEquals("getSubscriptionId() should be " + testSubId, testSubId, 875 smsManager.getSubscriptionId()); 876 } 877 878 /** 879 * Verify the API will not throw any exception when READ_PRIVILEGED_PHONE_STATE is granted. 880 */ 881 @Test testGetSmscIdentity()882 public void testGetSmscIdentity() { 883 try { 884 mTelephonyManager.getHalVersion(TelephonyManager.HAL_SERVICE_RADIO); 885 } catch (IllegalStateException e) { 886 assumeNoException("Skipping test because Telephony service is null", e); 887 } 888 SmsManager smsManager = getSmsManager(); 889 ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(smsManager, 890 SmsManager::getSmscIdentity, Manifest.permission.READ_PRIVILEGED_PHONE_STATE); 891 } 892 893 /** 894 * Verify the API will throw the SecurityException or not when no permissions are granted. 895 */ 896 @Test testGetSmscIdentity_Exception()897 public void testGetSmscIdentity_Exception() { 898 try { 899 mTelephonyManager.getHalVersion(TelephonyManager.HAL_SERVICE_RADIO); 900 } catch (IllegalStateException e) { 901 assumeNoException("Skipping test because Telephony service is null", e); 902 } 903 dropShellIdentity(); 904 try { 905 getSmsManager().getSmscIdentity(); 906 fail(); 907 } catch (SecurityException se) { 908 // API will throw SecurityException as no permission is granted to the caller 909 } 910 adoptShellIdentity(); 911 } 912 divideMessage(String text)913 protected ArrayList<String> divideMessage(String text) { 914 return getSmsManager().divideMessage(text); 915 } 916 getSmsManager()917 private android.telephony.SmsManager getSmsManager() { 918 return android.telephony.SmsManager.getDefault(); 919 } 920 sendMultiPartTextMessage(String destAddr, ArrayList<String> parts, ArrayList<PendingIntent> sentIntents, ArrayList<PendingIntent> deliveryIntents, boolean addMessageId)921 protected void sendMultiPartTextMessage(String destAddr, ArrayList<String> parts, 922 ArrayList<PendingIntent> sentIntents, ArrayList<PendingIntent> deliveryIntents, 923 boolean addMessageId) { 924 if (addMessageId) { 925 long fakeMessageId = 1278; 926 getSmsManager().sendMultipartTextMessage(destAddr, null, parts, sentIntents, 927 deliveryIntents, fakeMessageId); 928 } else if (mContext.getOpPackageName() != null) { 929 getSmsManager().sendMultipartTextMessage(destAddr, null, parts, sentIntents, 930 deliveryIntents, mContext.getOpPackageName(), mContext.getAttributionTag()); 931 } else { 932 getSmsManager().sendMultipartTextMessage(destAddr, null, parts, sentIntents, 933 deliveryIntents); 934 } 935 } 936 sendDataMessage(String destAddr,short port, byte[] data, PendingIntent sentIntent, PendingIntent deliveredIntent)937 protected void sendDataMessage(String destAddr,short port, byte[] data, PendingIntent sentIntent, PendingIntent deliveredIntent) { 938 getSmsManager().sendDataMessage(destAddr, null, port, data, sentIntent, deliveredIntent); 939 } 940 sendTextMessage(String destAddr, String text, PendingIntent sentIntent, PendingIntent deliveredIntent)941 protected void sendTextMessage(String destAddr, String text, PendingIntent sentIntent, 942 PendingIntent deliveredIntent) { 943 getSmsManager().sendTextMessage(destAddr, null, text, sentIntent, deliveredIntent); 944 } 945 sendTextMessageWithMessageId(String destAddr, String text, PendingIntent sentIntent, PendingIntent deliveredIntent, long messageId)946 protected void sendTextMessageWithMessageId(String destAddr, String text, 947 PendingIntent sentIntent, PendingIntent deliveredIntent, long messageId) { 948 getSmsManager().sendTextMessage(destAddr, null, text, sentIntent, deliveredIntent, 949 messageId); 950 } 951 blockNumber(String number)952 private void blockNumber(String number) { 953 mBlockedNumberUri = insertBlockedNumber(mContext, number); 954 if (mBlockedNumberUri == null) { 955 fail("Failed to insert into blocked number provider."); 956 } 957 } 958 unblockNumber(Uri uri)959 private void unblockNumber(Uri uri) { 960 deleteBlockedNumber(mContext, uri); 961 } 962 setDefaultSmsApp(boolean setToSmsApp)963 private void setDefaultSmsApp(boolean setToSmsApp) 964 throws Exception { 965 String command = String.format( 966 "appops set --user 0 %s WRITE_SMS %s", 967 mContext.getPackageName(), 968 setToSmsApp ? "allow" : "default"); 969 assertTrue("Setting default SMS app failed : " + setToSmsApp, 970 executeShellCommand(command).isEmpty()); 971 mTestAppSetAsDefaultSmsApp = setToSmsApp; 972 } 973 executeShellCommand(String command)974 private String executeShellCommand(String command) 975 throws IOException { 976 ParcelFileDescriptor pfd = 977 getInstrumentation().getUiAutomation().executeShellCommand(command); 978 BufferedReader br = null; 979 try (InputStream in = new FileInputStream(pfd.getFileDescriptor());) { 980 br = new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8)); 981 String str; 982 StringBuilder out = new StringBuilder(); 983 while ((str = br.readLine()) != null) { 984 out.append(str); 985 } 986 return out.toString(); 987 } finally { 988 if (br != null) { 989 br.close(); 990 } 991 } 992 } 993 994 private static class SmsBroadcastReceiver extends BroadcastReceiver { 995 private int mCalls; 996 private int mExpectedCalls; 997 private String mAction; 998 private Object mLock; 999 SmsBroadcastReceiver(String action)1000 SmsBroadcastReceiver(String action) { 1001 mAction = action; 1002 reset(); 1003 mLock = new Object(); 1004 } 1005 reset()1006 void reset() { 1007 mExpectedCalls = Integer.MAX_VALUE; 1008 mCalls = 0; 1009 } 1010 1011 @Override onReceive(Context context, Intent intent)1012 public void onReceive(Context context, Intent intent) { 1013 if(mAction.equals(DATA_SMS_RECEIVED_ACTION)){ 1014 StringBuilder sb = new StringBuilder(); 1015 Bundle bundle = intent.getExtras(); 1016 if (bundle != null) { 1017 Object[] obj = (Object[]) bundle.get("pdus"); 1018 String format = bundle.getString("format"); 1019 SmsMessage[] message = new SmsMessage[obj.length]; 1020 for (int i = 0; i < obj.length; i++) { 1021 message[i] = SmsMessage.createFromPdu((byte[]) obj[i], format); 1022 } 1023 1024 for (SmsMessage currentMessage : message) { 1025 byte[] binaryContent = currentMessage.getUserData(); 1026 String readableContent = new String(binaryContent); 1027 sb.append(readableContent); 1028 } 1029 } 1030 mReceivedDataSms = true; 1031 mReceivedText=sb.toString(); 1032 } 1033 if (mAction.equals(Telephony.Sms.Intents.SMS_RECEIVED_ACTION)) { 1034 sMessageId = intent.getLongExtra("messageId", 0L); 1035 } 1036 Log.i(TAG, "onReceive " + intent.getAction() + ", mAction " + mAction); 1037 if (intent.getAction().equals(mAction)) { 1038 synchronized (mLock) { 1039 mCalls += 1; 1040 mLock.notify(); 1041 } 1042 } 1043 } 1044 verifyNoCalls(long timeout)1045 public boolean verifyNoCalls(long timeout) throws InterruptedException { 1046 synchronized(mLock) { 1047 mLock.wait(timeout); 1048 return mCalls == 0; 1049 } 1050 } 1051 waitForCalls(int expectedCalls, long timeout)1052 public boolean waitForCalls(int expectedCalls, long timeout) throws InterruptedException { 1053 synchronized(mLock) { 1054 mExpectedCalls = expectedCalls; 1055 long startTime = SystemClock.elapsedRealtime(); 1056 1057 while (mCalls < mExpectedCalls) { 1058 long waitTime = timeout - (SystemClock.elapsedRealtime() - startTime); 1059 if (waitTime > 0) { 1060 mLock.wait(waitTime); 1061 } else { 1062 return false; // timed out 1063 } 1064 } 1065 return true; // success 1066 } 1067 } 1068 } 1069 1070 /** 1071 * Adopts shell permission identity 1072 */ adoptShellIdentity()1073 private static void adoptShellIdentity() { 1074 InstrumentationRegistry.getInstrumentation().getUiAutomation() 1075 .adoptShellPermissionIdentity(); 1076 } 1077 1078 /** 1079 * Drop shell permission identity 1080 */ dropShellIdentity()1081 private static void dropShellIdentity() { 1082 InstrumentationRegistry.getInstrumentation().getUiAutomation() 1083 .dropShellPermissionIdentity(); 1084 } 1085 } 1086