1 /* 2 * Copyright (C) 2015 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 org.junit.Assert.assertEquals; 23 import static org.junit.Assert.assertFalse; 24 import static org.junit.Assert.assertNotNull; 25 import static org.junit.Assert.assertTrue; 26 import static org.junit.Assume.assumeTrue; 27 28 import android.Manifest; 29 import android.annotation.Nullable; 30 import android.app.Activity; 31 import android.app.PendingIntent; 32 import android.content.BroadcastReceiver; 33 import android.content.ContentResolver; 34 import android.content.Context; 35 import android.content.Intent; 36 import android.content.IntentFilter; 37 import android.content.pm.PackageManager; 38 import android.net.Uri; 39 import android.os.PersistableBundle; 40 import android.os.SystemClock; 41 import android.telephony.CarrierConfigManager; 42 import android.telephony.SmsManager; 43 import android.telephony.SubscriptionManager; 44 import android.telephony.TelephonyManager; 45 import android.telephony.cts.util.DefaultSmsAppHelper; 46 import android.text.TextUtils; 47 import android.util.Log; 48 49 import com.android.compatibility.common.util.ApiTest; 50 import com.android.compatibility.common.util.ShellIdentityUtils; 51 import com.android.internal.telephony.flags.Flags; 52 53 import com.google.android.mms.ContentType; 54 import com.google.android.mms.InvalidHeaderValueException; 55 import com.google.android.mms.pdu.CharacterSets; 56 import com.google.android.mms.pdu.EncodedStringValue; 57 import com.google.android.mms.pdu.GenericPdu; 58 import com.google.android.mms.pdu.PduBody; 59 import com.google.android.mms.pdu.PduComposer; 60 import com.google.android.mms.pdu.PduHeaders; 61 import com.google.android.mms.pdu.PduParser; 62 import com.google.android.mms.pdu.PduPart; 63 import com.google.android.mms.pdu.SendConf; 64 import com.google.android.mms.pdu.SendReq; 65 66 import org.junit.After; 67 import org.junit.AfterClass; 68 import org.junit.Before; 69 import org.junit.BeforeClass; 70 import org.junit.Test; 71 72 import java.io.File; 73 import java.io.FileOutputStream; 74 import java.io.IOException; 75 import java.util.Random; 76 import java.util.concurrent.CountDownLatch; 77 import java.util.concurrent.TimeUnit; 78 79 /** 80 * Test sending MMS using {@link android.telephony.SmsManager}. 81 */ 82 public class MmsTest { 83 private static final String TAG = "MmsTest"; 84 85 private static final String ACTION_MMS_SENT = "CTS_MMS_SENT_ACTION"; 86 private static final String ACTION_MMS_DOWNLOAD = "CTS_MMS_DOWNLOAD_ACTION"; 87 public static final String ACTION_WAP_PUSH_DELIVER_DEFAULT_APP = 88 "CTS_WAP_PUSH_DELIVER_DEFAULT_APP_ACTION"; 89 private static final long DEFAULT_EXPIRY_TIME = 7 * 24 * 60 * 60; 90 private static final int DEFAULT_PRIORITY = PduHeaders.PRIORITY_NORMAL; 91 private static final long MESSAGE_ID = 912412L; 92 93 private static final String SUBJECT = "CTS MMS Test"; 94 private static final String MESSAGE_BODY = "CTS MMS test message body"; 95 private static final String TEXT_PART_FILENAME = "text_0.txt"; 96 private static final String sSmilText = 97 "<smil>" + 98 "<head>" + 99 "<layout>" + 100 "<root-layout/>" + 101 "<region height=\"100%%\" id=\"Text\" left=\"0%%\" top=\"0%%\" width=\"100%%\"/>" + 102 "</layout>" + 103 "</head>" + 104 "<body>" + 105 "<par dur=\"8000ms\">" + 106 "<text src=\"%s\" region=\"Text\"/>" + 107 "</par>" + 108 "</body>" + 109 "</smil>"; 110 111 private static final long SENT_TIMEOUT = 1000 * 60 * 5; // 5 minutes 112 private static final long NO_CALLS_TIMEOUT = 1000; // 1 second 113 114 private static final String PROVIDER_AUTHORITY = "telephonyctstest"; 115 116 private Random mRandom; 117 private SentReceiver mSentReceiver; 118 private SentReceiver mDeliveryReceiver; 119 private TelephonyManager mTelephonyManager; 120 @Nullable private String mOriginalDefaultSmsApp; 121 private static CarrierConfigReceiver sCarrierConfigReceiver; 122 123 private static class SentReceiver extends BroadcastReceiver { 124 private final Object mLock; 125 private boolean mSuccess; 126 private boolean mDone; 127 private int mExpectedErrorResultCode; 128 private String mAction; 129 SentReceiver(int expectedErrorResultCode, String action)130 SentReceiver(int expectedErrorResultCode, String action) { 131 mLock = new Object(); 132 mSuccess = false; 133 mDone = false; 134 mExpectedErrorResultCode = expectedErrorResultCode; 135 mAction = action; 136 } 137 138 @Override onReceive(Context context, Intent intent)139 public void onReceive(Context context, Intent intent) { 140 Log.i(TAG, "onReceive Action " + intent.getAction() + ", mAction " + mAction); 141 142 switch (intent.getAction()) { 143 case ACTION_MMS_SENT: 144 final int resultCode = getResultCode(); 145 if (resultCode == Activity.RESULT_OK) { 146 final byte[] response = intent.getByteArrayExtra(SmsManager.EXTRA_MMS_DATA); 147 if (response != null) { 148 final GenericPdu pdu = new PduParser( 149 response, shouldParseContentDisposition()).parse(); 150 if (pdu != null && pdu instanceof SendConf) { 151 final SendConf sendConf = (SendConf) pdu; 152 if (sendConf.getResponseStatus() == PduHeaders.RESPONSE_STATUS_OK) { 153 mSuccess = true; 154 } else { 155 Log.e(TAG, 156 "SendConf response status=" 157 + sendConf.getResponseStatus()); 158 } 159 } else { 160 Log.e(TAG, "Not a SendConf: " + (pdu != null 161 ? pdu.getClass().getCanonicalName() : "NULL")); 162 } 163 } else { 164 Log.e(TAG, "Empty response"); 165 } 166 } else { 167 Log.e(TAG, "Failure result=" + resultCode); 168 if (resultCode == mExpectedErrorResultCode) { 169 mSuccess = true; 170 } 171 if (resultCode == SmsManager.MMS_ERROR_HTTP_FAILURE) { 172 final int httpError = intent.getIntExtra( 173 SmsManager.EXTRA_MMS_HTTP_STATUS, 174 0); 175 Log.e(TAG, "HTTP failure=" + httpError); 176 } 177 } 178 break; 179 case ACTION_WAP_PUSH_DELIVER_DEFAULT_APP: 180 mSuccess = true; 181 break; 182 } 183 184 if (intent.getAction().equals(mAction)) { 185 synchronized (mLock) { 186 mDone = true; 187 mLock.notify(); 188 } 189 } 190 } 191 waitForSuccess(long timeout)192 public boolean waitForSuccess(long timeout) { 193 synchronized(mLock) { 194 final long startTime = SystemClock.elapsedRealtime(); 195 long waitTime = timeout; 196 while (!mDone && waitTime > 0) { 197 try { 198 mLock.wait(waitTime); 199 } catch (InterruptedException e) { 200 // Ignore 201 } 202 waitTime = timeout - (SystemClock.elapsedRealtime() - startTime); 203 } 204 Log.i(TAG, "Wait for sent: done=" + mDone + ", success=" + mSuccess); 205 return mDone && mSuccess; 206 } 207 } 208 verifyNoCalls(long timeout)209 public boolean verifyNoCalls(long timeout) { 210 synchronized (mLock) { 211 try { 212 mLock.wait(timeout); 213 } catch (InterruptedException e) { 214 // Ignore 215 } 216 return (!mDone && !mSuccess); 217 } 218 } 219 } 220 221 /** 222 * Setup before all tests. 223 */ 224 @BeforeClass beforeAllTests()225 public static void beforeAllTests() { 226 Log.i(TAG, "beforeAllTests"); 227 sCarrierConfigReceiver = new CarrierConfigReceiver(); 228 IntentFilter filter = new IntentFilter(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED); 229 // ACTION_CARRIER_CONFIG_CHANGED is sticky, so we will get a callback right away. 230 getInstrumentation().getContext().registerReceiver(sCarrierConfigReceiver, filter); 231 } 232 233 /** 234 * Clean up resources after all tests. 235 */ 236 @AfterClass afterAllTests()237 public static void afterAllTests() { 238 Log.i(TAG, "afterAllTests"); 239 240 // Ensure there are no CarrierConfig overrides. 241 overrideCarrierConfig(SmsManager.getDefaultSmsSubscriptionId(), null); 242 if (sCarrierConfigReceiver != null) { 243 getInstrumentation().getContext().unregisterReceiver(sCarrierConfigReceiver); 244 sCarrierConfigReceiver = null; 245 } 246 } 247 248 @Before setUp()249 public void setUp() throws Exception { 250 mRandom = new Random(); 251 mTelephonyManager = 252 (TelephonyManager) getContext().getSystemService(Context.TELEPHONY_SERVICE); 253 assumeTrue(getContext().getPackageManager().hasSystemFeature( 254 PackageManager.FEATURE_TELEPHONY_MESSAGING)); 255 mOriginalDefaultSmsApp = DefaultSmsAppHelper.getDefaultSmsApp(getContext()); 256 DefaultSmsAppHelper.stopBeingDefaultSmsApp(); 257 } 258 259 @After tearDown()260 public void tearDown() throws Exception { 261 if (!TextUtils.isEmpty(mOriginalDefaultSmsApp)) { 262 assertTrue(DefaultSmsAppHelper.setDefaultSmsApp(getContext(), mOriginalDefaultSmsApp)); 263 } 264 } 265 266 @Test 267 @ApiTest(apis = "android.telephony.SmsManager#sendMultimediaMessage") testSendMmsMessage()268 public void testSendMmsMessage() { 269 Log.i("MmsTest", "testSendMmsMessage"); 270 271 // Test non-default SMS app 272 sendMmsMessage(0L /* messageId */, Activity.RESULT_OK, SmsManager.getDefault(), false); 273 274 // Test default SMS app 275 DefaultSmsAppHelper.ensureDefaultSmsApp(); 276 sendMmsMessage(0L /* messageId */, Activity.RESULT_OK, SmsManager.getDefault(), true); 277 DefaultSmsAppHelper.stopBeingDefaultSmsApp(); 278 } 279 280 @Test 281 @ApiTest(apis = "android.telephony.SmsManager#sendMultimediaMessage") testSendMmsMessageWithInactiveSubscriptionId()282 public void testSendMmsMessageWithInactiveSubscriptionId() { 283 int inactiveSubId = 127; 284 285 // Test non-default SMS app 286 sendMmsMessage(0L /* messageId */, SmsManager.MMS_ERROR_INACTIVE_SUBSCRIPTION, 287 SmsManager.getSmsManagerForSubscriptionId(inactiveSubId), false); 288 289 // Test default SMS app 290 DefaultSmsAppHelper.ensureDefaultSmsApp(); 291 sendMmsMessage(0L /* messageId */, SmsManager.MMS_ERROR_INACTIVE_SUBSCRIPTION, 292 SmsManager.getSmsManagerForSubscriptionId(inactiveSubId), true); 293 DefaultSmsAppHelper.stopBeingDefaultSmsApp(); 294 } 295 296 @Test 297 @ApiTest(apis = "android.telephony.SmsManager#sendMultimediaMessage") testSendMmsMessageWithMmsDisabled()298 public void testSendMmsMessageWithMmsDisabled() { 299 if (!Flags.mmsDisabledError()) { 300 Log.i(TAG, "testSendMmsMessageWithMmsDisabled: mmsDisabledError is not enabled"); 301 return; 302 } 303 Log.i(TAG, "testSendMmsMessageWithMmsDisabled"); 304 305 // Disable MMS carrier config 306 PersistableBundle bundle = new PersistableBundle(); 307 bundle.putBoolean(SmsManager.MMS_CONFIG_MMS_ENABLED, false); 308 assertTrue(overrideCarrierConfig(SmsManager.getDefaultSmsSubscriptionId(), bundle)); 309 assertFalse(doesSupportMMS()); 310 311 // It takes some time for the new carrier config loaded to MmsConfigManager 312 waitFor(TimeUnit.SECONDS.toMillis(1)); 313 314 // Test non-default SMS app 315 sendMmsMessage(0L /* messageId */, SmsManager.MMS_ERROR_MMS_DISABLED_BY_CARRIER, 316 SmsManager.getDefault(), false); 317 318 // Test default SMS app 319 DefaultSmsAppHelper.ensureDefaultSmsApp(); 320 sendMmsMessage(0L /* messageId */, SmsManager.MMS_ERROR_MMS_DISABLED_BY_CARRIER, 321 SmsManager.getDefault(), true); 322 DefaultSmsAppHelper.stopBeingDefaultSmsApp(); 323 324 // Restore MMS config 325 if (doesSupportMMS()) { 326 bundle.putBoolean(SmsManager.MMS_CONFIG_MMS_ENABLED, true); 327 assertTrue(overrideCarrierConfig(SmsManager.getDefaultSmsSubscriptionId(), bundle)); 328 } 329 } 330 331 @Test 332 @ApiTest(apis = "android.telephony.SmsManager#sendMultimediaMessage") testSendMmsMessageWithMessageId()333 public void testSendMmsMessageWithMessageId() { 334 // Test non-default SMS app 335 sendMmsMessage(MESSAGE_ID, Activity.RESULT_OK, SmsManager.getDefault(), false); 336 337 // Test default SMS app 338 DefaultSmsAppHelper.ensureDefaultSmsApp(); 339 sendMmsMessage(MESSAGE_ID, Activity.RESULT_OK, SmsManager.getDefault(), true); 340 DefaultSmsAppHelper.stopBeingDefaultSmsApp(); 341 } 342 sendMmsMessage(long messageId, int expectedErrorResultCode, SmsManager smsManager, boolean defaultSmsApp)343 private void sendMmsMessage(long messageId, int expectedErrorResultCode, 344 SmsManager smsManager, boolean defaultSmsApp) { 345 if (!doesSupportMMS() 346 && expectedErrorResultCode != SmsManager.MMS_ERROR_MMS_DISABLED_BY_CARRIER) { 347 Log.i(TAG, "testSendMmsMessage skipped: no telephony available or MMS not supported"); 348 return; 349 } 350 351 String selfNumber; 352 getInstrumentation().getUiAutomation() 353 .adoptShellPermissionIdentity(Manifest.permission.READ_PRIVILEGED_PHONE_STATE); 354 try { 355 int subId = mTelephonyManager.getSubscriptionId(); 356 SubscriptionManager subscriptionManager = getContext() 357 .getSystemService(SubscriptionManager.class); 358 selfNumber = subscriptionManager.getPhoneNumber(subId); 359 } finally { 360 getInstrumentation().getUiAutomation().dropShellPermissionIdentity(); 361 } 362 assertFalse("[RERUN] SIM card does not provide phone number. Use a suitable SIM Card.", 363 TextUtils.isEmpty(selfNumber)); 364 365 Log.i(TAG, "testSendMmsMessage"); 366 367 final Context context = getContext(); 368 // Register sent receiver 369 mSentReceiver = new SentReceiver(expectedErrorResultCode, ACTION_MMS_SENT); 370 context.registerReceiver(mSentReceiver, new IntentFilter(ACTION_MMS_SENT), 371 Context.RECEIVER_EXPORTED); 372 373 mDeliveryReceiver = new SentReceiver(expectedErrorResultCode, 374 ACTION_WAP_PUSH_DELIVER_DEFAULT_APP); 375 context.registerReceiver(mDeliveryReceiver, 376 new IntentFilter(ACTION_WAP_PUSH_DELIVER_DEFAULT_APP), Context.RECEIVER_EXPORTED); 377 378 // Create local provider file for sending PDU 379 final String fileName = "send." + String.valueOf(Math.abs(mRandom.nextLong())) + ".dat"; 380 final File sendFile = new File(context.getCacheDir(), fileName); 381 final byte[] pdu = buildPdu(context, selfNumber, SUBJECT, MESSAGE_BODY); 382 assertNotNull(pdu); 383 assertTrue(writePdu(sendFile, pdu)); 384 final Uri contentUri = (new Uri.Builder()) 385 .authority(PROVIDER_AUTHORITY) 386 .path(fileName) 387 .scheme(ContentResolver.SCHEME_CONTENT) 388 .build(); 389 // Send 390 final PendingIntent pendingIntent = PendingIntent.getBroadcast( 391 context, 0, new Intent(ACTION_MMS_SENT).setPackage(context.getPackageName()), 392 PendingIntent.FLAG_MUTABLE); 393 if (messageId == 0L) { 394 smsManager.sendMultimediaMessage(context, 395 contentUri, null/*locationUrl*/, null/*configOverrides*/, pendingIntent); 396 } else { 397 smsManager.sendMultimediaMessage(context, 398 contentUri, null/*locationUrl*/, null/*configOverrides*/, pendingIntent, 399 messageId); 400 } 401 assertTrue(mSentReceiver.waitForSuccess(SENT_TIMEOUT)); 402 assertEquals(expectedErrorResultCode, mSentReceiver.getResultCode()); 403 404 if (expectedErrorResultCode == Activity.RESULT_OK) { 405 int carrierId = mTelephonyManager.getSimCarrierId(); 406 assertFalse("[RERUN] Carrier [carrier-id: " + carrierId + "] does not support " 407 + "loop back messages. Use another carrier.", 408 CarrierCapability.UNSUPPORT_LOOP_BACK_MESSAGES.contains(carrierId)); 409 } 410 411 if (defaultSmsApp && expectedErrorResultCode == Activity.RESULT_OK) { 412 // Default SMS App should receive android.provider.Telephony.WAP_PUSH_DELIVER 413 assertTrue(mDeliveryReceiver.waitForSuccess(SENT_TIMEOUT)); 414 } else { 415 // Non-default SMS App should not receive android.provider.Telephony.WAP_PUSH_DELIVER. 416 // Default SMS App will not receive android.provider.Telephony.WAP_PUSH_DELIVER in case 417 // of fail to send a message. 418 assertTrue(mDeliveryReceiver.verifyNoCalls(NO_CALLS_TIMEOUT)); 419 } 420 sendFile.delete(); 421 } 422 writePdu(File file, byte[] pdu)423 private static boolean writePdu(File file, byte[] pdu) { 424 FileOutputStream writer = null; 425 try { 426 writer = new FileOutputStream(file); 427 writer.write(pdu); 428 return true; 429 } catch (final IOException e) { 430 return false; 431 } finally { 432 if (writer != null) { 433 try { 434 writer.close(); 435 } catch (IOException e) { 436 } 437 } 438 } 439 } 440 buildPdu(Context context, String selfNumber, String subject, String text)441 private byte[] buildPdu(Context context, String selfNumber, String subject, String text) { 442 final SendReq req = new SendReq(); 443 // From, per spec 444 req.setFrom(new EncodedStringValue(selfNumber)); 445 // To 446 final String[] recipients = new String[1]; 447 recipients[0] = selfNumber; 448 final EncodedStringValue[] encodedNumbers = EncodedStringValue.encodeStrings(recipients); 449 if (encodedNumbers != null) { 450 req.setTo(encodedNumbers); 451 } 452 // Subject 453 if (!TextUtils.isEmpty(subject)) { 454 req.setSubject(new EncodedStringValue(subject)); 455 } 456 // Date 457 req.setDate(System.currentTimeMillis() / 1000); 458 // Body 459 final PduBody body = new PduBody(); 460 // Add text part. Always add a smil part for compatibility, without it there 461 // may be issues on some carriers/client apps 462 final int size = addTextPart(body, text, true/* add text smil */); 463 req.setBody(body); 464 // Message size 465 req.setMessageSize(size); 466 // Message class 467 req.setMessageClass(PduHeaders.MESSAGE_CLASS_PERSONAL_STR.getBytes()); 468 // Expiry 469 req.setExpiry(DEFAULT_EXPIRY_TIME); 470 // The following set methods throw InvalidHeaderValueException 471 try { 472 // Priority 473 req.setPriority(DEFAULT_PRIORITY); 474 // Delivery report 475 req.setDeliveryReport(PduHeaders.VALUE_NO); 476 // Read report 477 req.setReadReport(PduHeaders.VALUE_NO); 478 } catch (InvalidHeaderValueException e) { 479 return null; 480 } 481 482 return new PduComposer(context, req).make(); 483 } 484 addTextPart(PduBody pb, String message, boolean addTextSmil)485 private static int addTextPart(PduBody pb, String message, boolean addTextSmil) { 486 final PduPart part = new PduPart(); 487 // Set Charset if it's a text media. 488 part.setCharset(CharacterSets.UTF_8); 489 // Set Content-Type. 490 part.setContentType(ContentType.TEXT_PLAIN.getBytes()); 491 // Set Content-Location. 492 part.setContentLocation(TEXT_PART_FILENAME.getBytes()); 493 int index = TEXT_PART_FILENAME.lastIndexOf("."); 494 String contentId = (index == -1) ? TEXT_PART_FILENAME 495 : TEXT_PART_FILENAME.substring(0, index); 496 part.setContentId(contentId.getBytes()); 497 part.setData(message.getBytes()); 498 pb.addPart(part); 499 if (addTextSmil) { 500 final String smil = String.format(sSmilText, TEXT_PART_FILENAME); 501 addSmilPart(pb, smil); 502 } 503 return part.getData().length; 504 } 505 addSmilPart(PduBody pb, String smil)506 private static void addSmilPart(PduBody pb, String smil) { 507 final PduPart smilPart = new PduPart(); 508 smilPart.setContentId("smil".getBytes()); 509 smilPart.setContentLocation("smil.xml".getBytes()); 510 smilPart.setContentType(ContentType.APP_SMIL.getBytes()); 511 smilPart.setData(smil.getBytes()); 512 pb.addPart(0, smilPart); 513 } 514 shouldParseContentDisposition()515 private static boolean shouldParseContentDisposition() { 516 return SmsManager 517 .getDefault() 518 .getCarrierConfigValues() 519 .getBoolean(SmsManager.MMS_CONFIG_SUPPORT_MMS_CONTENT_DISPOSITION, true); 520 } 521 doesSupportMMS()522 private static boolean doesSupportMMS() { 523 return SmsManager 524 .getDefault() 525 .getCarrierConfigValues() 526 .getBoolean(SmsManager.MMS_CONFIG_MMS_ENABLED, true); 527 } 528 529 @Test testDownloadMultimediaMessage()530 public void testDownloadMultimediaMessage() { 531 downloadMultimediaMessage(0L /* messageId */); 532 } 533 534 @Test testDownloadMultimediaMessageWithMessageId()535 public void testDownloadMultimediaMessageWithMessageId() { 536 downloadMultimediaMessage(MESSAGE_ID); 537 } 538 downloadMultimediaMessage(long messageId)539 private void downloadMultimediaMessage(long messageId) { 540 if (!doesSupportMMS()) { 541 Log.i(TAG, "testSendMmsMessage skipped: no telephony available or MMS not supported"); 542 return; 543 } 544 545 Log.i(TAG, "testSendMmsMessage"); 546 // Prime the MmsService so that MMS config is loaded 547 final SmsManager smsManager = SmsManager.getDefault(); 548 smsManager.getCarrierConfigValues(); 549 // MMS config is loaded asynchronously. Wait a bit so it will be loaded. 550 waitFor(TimeUnit.SECONDS.toMillis(1)); 551 552 final Context context = getContext(); 553 // Create local provider file 554 final String fileName = "download." + String.valueOf(Math.abs(mRandom.nextLong())) + ".dat"; 555 final File sendFile = new File(context.getCacheDir(), fileName); 556 final Uri contentUri = (new Uri.Builder()) 557 .authority(PROVIDER_AUTHORITY) 558 .path(fileName) 559 .scheme(ContentResolver.SCHEME_CONTENT) 560 .build(); 561 562 final PendingIntent pendingIntent = PendingIntent.getBroadcast( 563 context, 0, new Intent(ACTION_MMS_DOWNLOAD).setPackage(context.getPackageName()), 564 PendingIntent.FLAG_MUTABLE); 565 566 if (messageId == 0L) { 567 // Verify the downloadMultimediaMessage function without messageId exists. This test 568 // doesn't actually verify downloading is successful, just that the function to 569 // initiate the downloading has been implemented. 570 smsManager.downloadMultimediaMessage(context, "foo/fake", contentUri, 571 null /* configOverrides */, pendingIntent); 572 } else { 573 // Verify the downloadMultimediaMessage function with messageId exists. This test 574 // doesn't actually verify downloading is successful, just that the function to 575 // initiate the downloading has been implemented. 576 smsManager.downloadMultimediaMessage(context, "foo/fake", contentUri, 577 null /* configOverrides */, pendingIntent, MESSAGE_ID); 578 } 579 } 580 581 private abstract static class BaseReceiver extends BroadcastReceiver { 582 protected CountDownLatch mLatch = new CountDownLatch(1); 583 clearQueue()584 void clearQueue() { 585 mLatch = new CountDownLatch(1); 586 } 587 waitForChanged()588 boolean waitForChanged() throws Exception { 589 return mLatch.await(5000, TimeUnit.MILLISECONDS); 590 } 591 } 592 593 private static class CarrierConfigReceiver extends BaseReceiver { 594 private int mSubId; 595 CarrierConfigReceiver()596 CarrierConfigReceiver() {} 597 setSubId(int subId)598 public void setSubId(int subId) { 599 mSubId = subId; 600 } 601 602 @Override onReceive(Context context, Intent intent)603 public void onReceive(Context context, Intent intent) { 604 if (CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED.equals(intent.getAction())) { 605 int subId = intent.getIntExtra(CarrierConfigManager.EXTRA_SUBSCRIPTION_INDEX, -1); 606 Log.d(TAG, "Carrier config changed for subId=" + subId 607 + ", mSubId=" + mSubId); 608 if (mSubId == subId) { 609 mLatch.countDown(); 610 } 611 } 612 } 613 } 614 overrideCarrierConfig(int subId, PersistableBundle bundle)615 private static boolean overrideCarrierConfig(int subId, PersistableBundle bundle) { 616 try { 617 CarrierConfigManager carrierConfigManager = getInstrumentation() 618 .getContext().getSystemService(CarrierConfigManager.class); 619 sCarrierConfigReceiver.clearQueue(); 620 sCarrierConfigReceiver.setSubId(subId); 621 ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(carrierConfigManager, 622 (m) -> m.overrideConfig(subId, bundle)); 623 return sCarrierConfigReceiver.waitForChanged(); 624 } catch (Exception ex) { 625 Log.e(TAG, "overrideCarrierConfig(), ex=" + ex); 626 return false; 627 } 628 } 629 waitFor(long timeoutMillis)630 private static void waitFor(long timeoutMillis) { 631 Object delayTimeout = new Object(); 632 synchronized (delayTimeout) { 633 try { 634 delayTimeout.wait(timeoutMillis); 635 } catch (InterruptedException ex) { 636 // Ignore the exception 637 Log.d(TAG, "waitFor: delayTimeout ex=" + ex); 638 } 639 } 640 } 641 } 642