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