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