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