Home | History | Annotate | Download | only in cts
      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