1 /*
2  * Copyright (C) 2018 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.telecom.cts;
18 
19 import static android.telecom.cts.TestUtils.shouldTestTelecom;
20 import static android.telecom.cts.TestUtils.waitOnAllHandlers;
21 
22 import static com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity;
23 
24 import android.Manifest;
25 import android.app.role.RoleManager;
26 import android.content.ComponentName;
27 import android.content.ContentResolver;
28 import android.content.Context;
29 import android.content.Intent;
30 import android.content.ServiceConnection;
31 import android.content.pm.PackageManager;
32 import android.database.Cursor;
33 import android.net.Uri;
34 import android.os.Bundle;
35 import android.os.IBinder;
36 import android.os.Process;
37 import android.os.UserHandle;
38 
39 import android.provider.CallLog;
40 import android.telecom.Call;
41 import android.telecom.CallScreeningService;
42 import android.telecom.TelecomManager;
43 import android.telecom.cts.screeningtestapp.CallScreeningServiceControl;
44 import android.telecom.cts.screeningtestapp.CtsCallScreeningService;
45 import android.telecom.cts.screeningtestapp.ICallScreeningControl;
46 import android.text.TextUtils;
47 
48 import java.util.List;
49 import java.util.concurrent.CountDownLatch;
50 import java.util.concurrent.Executor;
51 import java.util.concurrent.LinkedBlockingQueue;
52 import java.util.concurrent.TimeUnit;
53 
54 public class ThirdPartyCallScreeningServiceTest extends BaseTelecomTestWithMockServices {
55     public static final String EXTRA_NETWORK_IDENTIFIED_EMERGENCY_CALL = "identifiedEmergencyCall";
56     private static final String TAG = ThirdPartyCallScreeningServiceTest.class.getSimpleName();
57     private static final String TEST_APP_NAME = "CTSCSTest";
58     private static final String TEST_APP_PACKAGE = "android.telecom.cts.screeningtestapp";
59     private static final String TEST_APP_COMPONENT =
60             "android.telecom.cts.screeningtestapp/"
61                     + "android.telecom.cts.screeningtestapp.CtsCallScreeningService";
62     private static final int ASYNC_TIMEOUT = 10000;
63     private static final String ROLE_CALL_SCREENING = RoleManager.ROLE_CALL_SCREENING;
64     private static final Uri TEST_OUTGOING_NUMBER = Uri.fromParts("tel", "6505551212", null);
65 
66     private ICallScreeningControl mCallScreeningControl;
67     private RoleManager mRoleManager;
68     private String mPreviousCallScreeningPackage;
69     private PackageManager mPackageManager;
70     private Uri mContactUri;
71     private ContentResolver mContentResolver;
72 
73     @Override
setUp()74     protected void setUp() throws Exception {
75         super.setUp();
76         if (!mShouldTestTelecom) {
77             return;
78         }
79         mRoleManager = (RoleManager) mContext.getSystemService(Context.ROLE_SERVICE);
80         mPackageManager = mContext.getPackageManager();
81         revokeReadContactPermission();
82         setupControlBinder();
83         setupConnectionService(null, FLAG_REGISTER | FLAG_ENABLE);
84         rememberPreviousCallScreeningApp();
85         // Ensure CTS app holds the call screening role.
86         addRoleHolder(ROLE_CALL_SCREENING,
87                 CtsCallScreeningService.class.getPackage().getName());
88         mContentResolver = getInstrumentation().getTargetContext().getContentResolver();
89     }
90 
91     @Override
tearDown()92     protected void tearDown() throws Exception {
93         super.tearDown();
94         if (!mShouldTestTelecom) {
95             return;
96         }
97 
98         if (mCallScreeningControl != null) {
99             mCallScreeningControl.reset();
100         }
101 
102         // Remove the test app from the screening role.
103         removeRoleHolder(ROLE_CALL_SCREENING, CtsCallScreeningService.class.getPackage().getName());
104 
105         if (!TextUtils.isEmpty(mPreviousCallScreeningPackage)) {
106             addRoleHolder(ROLE_CALL_SCREENING, mPreviousCallScreeningPackage);
107         }
108     }
109 
110     /**
111      * Verifies that a {@link android.telecom.CallScreeningService} can reject an incoming call.
112      * Ensures that the system logs the blocked call to the call log.
113      *
114      * @throws Exception
115      */
testRejectCall()116     public void testRejectCall() throws Exception {
117         if (!shouldTestTelecom(mContext)) {
118             return;
119         }
120 
121         // Tell the test app to block the call.
122         mCallScreeningControl.setCallResponse(true /* shouldDisallowCall */,
123                 true /* shouldRejectCall */, false /* shouldSilenceCall */,
124                 false /* shouldSkipCallLog */, true /* shouldSkipNotification */);
125 
126         addIncomingAndVerifyBlocked(false /* addContact */);
127     }
128 
129     /**
130      * Similar to {@link #testRejectCall()}, except the {@link android.telecom.CallScreeningService}
131      * tries to skip logging the call to the call log.  We verify that Telecom still logs the call
132      * to the call log, retaining the API behavior documented in
133      * {@link android.telecom.CallScreeningService#respondToCall(Call.Details, CallScreeningService.CallResponse)}
134      * @throws Exception
135      */
testRejectCallAndTryToSkipCallLog()136     public void testRejectCallAndTryToSkipCallLog() throws Exception {
137         if (!shouldTestTelecom(mContext)) {
138             return;
139         }
140 
141         // Tell the test app to block the call; also try to skip logging the call.
142         mCallScreeningControl.setCallResponse(true /* shouldDisallowCall */,
143                 true /* shouldRejectCall */, false /* shouldSilenceCall */,
144                 true /* shouldSkipCallLog */, true /* shouldSkipNotification */);
145 
146         addIncomingAndVerifyBlocked(false /* addContact */);
147     }
148 
149     /**
150      * Verifies that a {@link android.telecom.CallScreeningService} set the extra to silence a call.
151      * @throws Exception
152      */
testIncomingCallHasSilenceExtra()153     public void testIncomingCallHasSilenceExtra() throws Exception {
154         if (!shouldTestTelecom(mContext)) {
155             return;
156         }
157 
158         // Tell the test app to silence the call.
159         mCallScreeningControl.setCallResponse(false /* shouldDisallowCall */,
160             false /* shouldRejectCall */, true /* shouldSilenceCall */,
161             false /* shouldSkipCallLog */, false /* shouldSkipNotification */);
162 
163         addIncomingAndVerifyCallExtraForSilence(true);
164     }
165 
166     /**
167      * Verifies that a {@link android.telecom.CallScreeningService} did not set the extra to silence an incoming call.
168      * @throws Exception
169      */
testIncomingCallDoesNotHaveHaveSilenceExtra()170     public void testIncomingCallDoesNotHaveHaveSilenceExtra() throws Exception {
171         if (!shouldTestTelecom(mContext)) {
172             return;
173         }
174 
175         // Tell the test app to not silence the call.
176         mCallScreeningControl.setCallResponse(false /* shouldDisallowCall */,
177                 false /* shouldRejectCall */, false /* shouldSilenceCall */,
178                 false /* shouldSkipCallLog */, false /* shouldSkipNotification */);
179 
180         addIncomingAndVerifyCallExtraForSilence(false);
181     }
182 
testHasPermissionAndNoContactIncoming()183     public void testHasPermissionAndNoContactIncoming() throws Exception {
184         if (!shouldTestTelecom(mContext)) {
185             return;
186         }
187 
188         grantReadContactPermission();
189         verifyPermission(true);
190         // Tell the test app to block the call.
191         mCallScreeningControl.setCallResponse(true /* shouldDisallowCall */,
192                 true /* shouldRejectCall */, false /* shouldSilenceCall */,
193                 false /* shouldSkipCallLog */, true /* shouldSkipNotification */);
194         addIncomingAndVerifyBlocked(false /* addContact */);
195     }
196 
testNoPermissionAndNoContactIncoming()197     public void testNoPermissionAndNoContactIncoming() throws Exception {
198         if (!shouldTestTelecom(mContext)) {
199             return;
200         }
201 
202         verifyPermission(false);
203         // Tell the test app to block the call.
204         mCallScreeningControl.setCallResponse(true /* shouldDisallowCall */,
205                 true /* shouldRejectCall */, false /* shouldSilenceCall */,
206                 false /* shouldSkipCallLog */, true /* shouldSkipNotification */);
207         addIncomingAndVerifyBlocked(false /* addContact */);
208     }
209 
testHasPermissionAndHasContactIncoming()210     public void testHasPermissionAndHasContactIncoming() throws Exception {
211         if (!shouldTestTelecom(mContext)) {
212             return;
213         }
214 
215         grantReadContactPermission();
216         verifyPermission(true);
217         mCallScreeningControl.setCallResponse(true /* shouldDisallowCall */,
218                 true /* shouldRejectCall */, false /* shouldSilenceCall */,
219                 false /* shouldSkipCallLog */, true /* shouldSkipNotification */);
220         addIncomingAndVerifyBlocked(true /* addContact */);
221     }
222 
testNoPermissionAndHasContactIncoming()223     public void testNoPermissionAndHasContactIncoming() throws Exception {
224         if (!shouldTestTelecom(mContext)) {
225             return;
226         }
227 
228         verifyPermission(false);
229         mCallScreeningControl.setCallResponse(true /* shouldDisallowCall */,
230                 true /* shouldRejectCall */, false /* shouldSilenceCall */,
231                 false /* shouldSkipCallLog */, true /* shouldSkipNotification */);
232         addIncomingAndVerifyAllowed(true /* addContact */);
233     }
234 
testHasPermissionAndNoContactOutgoing()235     public void testHasPermissionAndNoContactOutgoing() throws Exception {
236         if (!shouldTestTelecom(mContext)) {
237             return;
238         }
239 
240         grantReadContactPermission();
241         verifyPermission(true);
242         placeOutgoingCall(false /* addContact */);
243         assertTrue(mCallScreeningControl.waitForBind());
244     }
245 
testNoPermissionAndNoContactOutgoing()246     public void testNoPermissionAndNoContactOutgoing() throws Exception {
247         if (!shouldTestTelecom(mContext)) {
248             return;
249         }
250 
251         verifyPermission(false);
252         placeOutgoingCall(false /* addContact */);
253         assertTrue(mCallScreeningControl.waitForBind());
254     }
255 
testHasPermissionAndHasContactOutgoing()256     public void testHasPermissionAndHasContactOutgoing() throws Exception {
257         if (!shouldTestTelecom(mContext)) {
258             return;
259         }
260 
261         grantReadContactPermission();
262         verifyPermission(true);
263         placeOutgoingCall(true /* addCountact */);
264         assertTrue(mCallScreeningControl.waitForBind());
265     }
266 
testNoPermissionAndHasContactOutgoing()267     public void testNoPermissionAndHasContactOutgoing() throws Exception {
268         if (!shouldTestTelecom(mContext)) {
269             return;
270         }
271 
272         verifyPermission(false);
273         placeOutgoingCall(true /* addCountact */);
274         assertFalse(mCallScreeningControl.waitForBind());
275     }
276 
testNoPostCallActivityWithoutRole()277     public void testNoPostCallActivityWithoutRole() throws Exception {
278         if (!shouldTestTelecom(mContext)) {
279             return;
280         }
281 
282         removeRoleHolder(ROLE_CALL_SCREENING, CtsCallScreeningService.class.getPackage().getName());
283         addIncomingAndVerifyAllowed(false);
284         assertFalse(mCallScreeningControl.waitForActivity());
285     }
286 
testAllowCall()287     public void testAllowCall() throws Exception {
288         if (!mShouldTestTelecom) {
289             return;
290         }
291 
292         mCallScreeningControl.setCallResponse(false /* shouldDisallowCall */,
293                 false /* shouldRejectCall */, false /* shouldSilenceCall */,
294                 false /* shouldSkipCallLog */, false /* shouldSkipNotification */);
295         addIncomingAndVerifyAllowed(false /* addContact */);
296         assertTrue(mCallScreeningControl.waitForActivity());
297     }
298 
testNoPostCallActivityWhenBlocked()299     public void testNoPostCallActivityWhenBlocked() throws Exception {
300         if (!mShouldTestTelecom) {
301             return;
302         }
303 
304         mCallScreeningControl.setCallResponse(true /* shouldDisallowCall */,
305                 true /* shouldRejectCall */, false /* shouldSilenceCall */,
306                 false /* shouldSkipCallLog */, true /* shouldSkipNotification */);
307         addIncomingAndVerifyBlocked(false /* addContact */);
308         assertFalse(mCallScreeningControl.waitForActivity());
309     }
310 
testNoPostCallActivityWhenAudioProcessing()311     public void testNoPostCallActivityWhenAudioProcessing() throws Exception {
312         if (!shouldTestTelecom(mContext)) {
313             return;
314         }
315 
316         mCallScreeningControl.setCallResponse(false /* shouldDisallowCall */,
317                 false /* shouldRejectCall */, false /* shouldSilenceCall */,
318                 false /* shouldSkipCallLog */, false /* shouldSkipNotification */);
319         Uri testNumber = createRandomTestNumber();
320         Bundle extras = new Bundle();
321         extras.putParcelable(TelecomManager.EXTRA_INCOMING_CALL_ADDRESS, testNumber);
322         mTelecomManager.addNewIncomingCall(TestUtils.TEST_PHONE_ACCOUNT_HANDLE, extras);
323 
324         // Wait until the new incoming call is processed.
325         waitOnAllHandlers(getInstrumentation());
326 
327         assertEquals(1, mInCallCallbacks.getService().getCallCount());
328         Call call = mInCallCallbacks.getService().getLastCall();
329         call.enterBackgroundAudioProcessing();
330 
331         waitOnAllHandlers(getInstrumentation());
332         mInCallCallbacks.getService().disconnectAllCalls();
333         assertFalse(mCallScreeningControl.waitForActivity());
334     }
335 
testNoPostCallActivityForOutgoingEmergencyCall()336     public void testNoPostCallActivityForOutgoingEmergencyCall() throws Exception {
337         if (!shouldTestTelecom(mContext)) {
338             return;
339         }
340 
341         setupForEmergencyCalling(TEST_EMERGENCY_NUMBER);
342         Bundle extras = new Bundle();
343         extras.putParcelable(TestUtils.EXTRA_PHONE_NUMBER, TEST_EMERGENCY_URI);
344         placeAndVerifyCall(extras);
345 
346         // Wait until the new incoming call is processed.
347         waitOnAllHandlers(getInstrumentation());
348         mInCallCallbacks.getService().disconnectAllCalls();
349         assertFalse(mCallScreeningControl.waitForActivity());
350     }
351 
testNoPostCallActivityForIncomingEmergencyCall()352     public void testNoPostCallActivityForIncomingEmergencyCall() throws Exception {
353         if (!shouldTestTelecom(mContext)) {
354             return;
355         }
356         setupForEmergencyCalling(TEST_EMERGENCY_NUMBER);
357         mCallScreeningControl.setCallResponse(false /* shouldDisallowCall */,
358                 false /* shouldRejectCall */, false /* shouldSilenceCall */,
359                 false /* shouldSkipCallLog */, false /* shouldSkipNotification */);
360         Bundle extras = new Bundle();
361         extras.putParcelable(TelecomManager.EXTRA_INCOMING_CALL_ADDRESS, TEST_EMERGENCY_URI);
362         extras.putBoolean(EXTRA_NETWORK_IDENTIFIED_EMERGENCY_CALL, true);
363         mTelecomManager.addNewIncomingCall(TestUtils.TEST_PHONE_ACCOUNT_HANDLE, extras);
364 
365         // Wait until the new incoming call is processed.
366         waitOnAllHandlers(getInstrumentation());
367         mInCallCallbacks.getService().disconnectAllCalls();
368 
369         assertFalse(mCallScreeningControl.waitForActivity());
370     }
371 
placeOutgoingCall(boolean addContact)372     private void placeOutgoingCall(boolean addContact) throws Exception {
373         // Setup content observer to notify us when we call log entry is added.
374         CountDownLatch callLogEntryLatch = getCallLogEntryLatch();
375 
376         Uri contactUri = null;
377         if (addContact) {
378             contactUri = TestUtils.insertContact(mContentResolver,
379                     TEST_OUTGOING_NUMBER.getSchemeSpecificPart());
380         }
381 
382         try {
383             Bundle extras = new Bundle();
384             extras.putParcelable(TestUtils.EXTRA_PHONE_NUMBER, TEST_OUTGOING_NUMBER);
385             // Create a new outgoing call.
386             placeAndVerifyCall(extras);
387 
388             mInCallCallbacks.getService().disconnectAllCalls();
389             assertNumCalls(mInCallCallbacks.getService(), 0);
390 
391             // Wait for it to log.
392             callLogEntryLatch.await(ASYNC_TIMEOUT, TimeUnit.MILLISECONDS);
393         } finally {
394             if (addContact) {
395                 assertEquals(1, TestUtils.deleteContact(mContentResolver, contactUri));
396             }
397         }
398     }
399 
addIncoming(boolean disconnectImmediately, boolean addContact)400     private Uri addIncoming(boolean disconnectImmediately, boolean addContact) throws Exception {
401         // Add call through TelecomManager; we can't use the test methods since they assume a call
402         // makes it through to the InCallService; this is blocked so it shouldn't.
403         Uri testNumber = createRandomTestNumber();
404         if (addContact) {
405             mContactUri = TestUtils.insertContact(mContentResolver,
406                     testNumber.getSchemeSpecificPart());
407         }
408 
409         // Setup content observer to notify us when we call log entry is added.
410         CountDownLatch callLogEntryLatch = getCallLogEntryLatch();
411 
412         Bundle extras = new Bundle();
413         extras.putParcelable(TelecomManager.EXTRA_INCOMING_CALL_ADDRESS, testNumber);
414         mTelecomManager.addNewIncomingCall(TestUtils.TEST_PHONE_ACCOUNT_HANDLE, extras);
415 
416         // Wait until the new incoming call is processed.
417         waitOnAllHandlers(getInstrumentation());
418 
419         if (disconnectImmediately) {
420             // Disconnect the call
421             mInCallCallbacks.getService().disconnectAllCalls();
422             assertNumCalls(mInCallCallbacks.getService(), 0);
423         }
424 
425         // Wait for the content observer to report that we have gotten a new call log entry.
426         callLogEntryLatch.await(ASYNC_TIMEOUT, TimeUnit.MILLISECONDS);
427         return testNumber;
428     }
429 
addIncomingAndVerifyAllowed(boolean addContact)430     private void addIncomingAndVerifyAllowed(boolean addContact) throws Exception {
431         Uri testNumber = addIncoming(true, addContact);
432 
433         // Query the latest entry into the call log.
434         Cursor callsCursor = mContentResolver.query(CallLog.Calls.CONTENT_URI, null,
435                 null, null, CallLog.Calls._ID + " DESC limit 1;");
436         int numberIndex = callsCursor.getColumnIndex(CallLog.Calls.NUMBER);
437         int callTypeIndex = callsCursor.getColumnIndex(CallLog.Calls.TYPE);
438         int blockReasonIndex = callsCursor.getColumnIndex(CallLog.Calls.BLOCK_REASON);
439         if (callsCursor.moveToNext()) {
440             String number = callsCursor.getString(numberIndex);
441             int callType = callsCursor.getInt(callTypeIndex);
442             int blockReason = callsCursor.getInt(blockReasonIndex);
443             assertEquals(testNumber.getSchemeSpecificPart(), number);
444             assertEquals(CallLog.Calls.INCOMING_TYPE, callType);
445             assertEquals(CallLog.Calls.BLOCK_REASON_NOT_BLOCKED, blockReason);
446         } else {
447             fail("Call not logged");
448         }
449 
450         if (addContact && mContactUri != null) {
451             assertEquals(1, TestUtils.deleteContact(mContentResolver, mContactUri));
452         }
453     }
454 
addIncomingAndVerifyBlocked(boolean addContact)455     private void addIncomingAndVerifyBlocked(boolean addContact) throws Exception {
456         Uri testNumber = addIncoming(false, addContact);
457 
458         // Query the latest entry into the call log.
459         Cursor callsCursor = mContentResolver.query(CallLog.Calls.CONTENT_URI, null,
460                 null, null, CallLog.Calls._ID + " DESC limit 1;");
461         int numberIndex = callsCursor.getColumnIndex(CallLog.Calls.NUMBER);
462         int callTypeIndex = callsCursor.getColumnIndex(CallLog.Calls.TYPE);
463         int blockReasonIndex = callsCursor.getColumnIndex(CallLog.Calls.BLOCK_REASON);
464         int callScreeningAppNameIndex = callsCursor.getColumnIndex(
465                 CallLog.Calls.CALL_SCREENING_APP_NAME);
466         int callScreeningCmpNameIndex = callsCursor.getColumnIndex(
467                 CallLog.Calls.CALL_SCREENING_COMPONENT_NAME);
468         if (callsCursor.moveToNext()) {
469             String number = callsCursor.getString(numberIndex);
470             int callType = callsCursor.getInt(callTypeIndex);
471             int blockReason = callsCursor.getInt(blockReasonIndex);
472             String screeningAppName = callsCursor.getString(callScreeningAppNameIndex);
473             String screeningComponentName = callsCursor.getString(callScreeningCmpNameIndex);
474             assertEquals(testNumber.getSchemeSpecificPart(), number);
475             assertEquals(CallLog.Calls.BLOCKED_TYPE, callType);
476             assertEquals(CallLog.Calls.BLOCK_REASON_CALL_SCREENING_SERVICE, blockReason);
477             assertEquals(TEST_APP_NAME, screeningAppName);
478             assertEquals(TEST_APP_COMPONENT, screeningComponentName);
479         } else {
480             fail("Blocked call was not logged.");
481         }
482 
483         if (addContact && mContactUri != null) {
484             assertEquals(1, TestUtils.deleteContact(mContentResolver, mContactUri));
485         }
486     }
487 
addIncomingAndVerifyCallExtraForSilence(boolean expectedIsSilentRingingExtraSet)488     private void addIncomingAndVerifyCallExtraForSilence(boolean expectedIsSilentRingingExtraSet)
489             throws Exception {
490         Uri testNumber = addIncoming(false, false);
491 
492         waitUntilConditionIsTrueOrTimeout(
493                 new Condition() {
494                     @Override
495                     public Object expected() {
496                         return true;
497                     }
498 
499                     @Override
500                     public Object actual() {
501                         // Verify that the call extra matches expectation
502                         Call call = mInCallCallbacks.getService().getLastCall();
503                         return expectedIsSilentRingingExtraSet ==
504                                 call.getDetails().getExtras().getBoolean(
505                                         Call.EXTRA_SILENT_RINGING_REQUESTED);
506                     }
507                 },
508                 TestUtils.WAIT_FOR_STATE_CHANGE_TIMEOUT_MS,
509                         "Call extra - verification failed, expected the extra " +
510                         "EXTRA_SILENT_RINGING_REQUESTED to be set:" +
511                         expectedIsSilentRingingExtraSet);
512     }
513 
514     /**
515      * Sets up a binder used to control the CallScreeningServiceCtsTestApp.
516      * This app is a standalone APK so that it can reside in a package name outside of the one the
517      * CTS test itself runs in (since that APK is where the CTS InCallService resides).
518      * @throws InterruptedException
519      */
setupControlBinder()520     private void setupControlBinder() throws InterruptedException {
521         Intent bindIntent = new Intent(CallScreeningServiceControl.CONTROL_INTERFACE_ACTION);
522         bindIntent.setComponent(CallScreeningServiceControl.CONTROL_INTERFACE_COMPONENT);
523         final CountDownLatch bindLatch = new CountDownLatch(1);
524 
525         boolean success = mContext.bindService(bindIntent, new ServiceConnection() {
526             @Override
527             public void onServiceConnected(ComponentName name, IBinder service) {
528                 mCallScreeningControl = ICallScreeningControl.Stub.asInterface(service);
529                 bindLatch.countDown();
530             }
531 
532             @Override
533             public void onServiceDisconnected(ComponentName name) {
534                 mCallScreeningControl = null;
535             }
536         }, Context.BIND_AUTO_CREATE);
537         if (!success) {
538             fail("Failed to get control interface -- bind error");
539         }
540         bindLatch.await(ASYNC_TIMEOUT, TimeUnit.MILLISECONDS);
541     }
542 
543     /**
544      * Use RoleManager to query the previous call screening app so we can restore it later.
545      */
rememberPreviousCallScreeningApp()546     private void rememberPreviousCallScreeningApp() {
547         runWithShellPermissionIdentity(() -> {
548             List<String> callScreeningApps = mRoleManager.getRoleHolders(ROLE_CALL_SCREENING);
549             if (!callScreeningApps.isEmpty()) {
550                 mPreviousCallScreeningPackage = callScreeningApps.get(0);
551             } else {
552                 mPreviousCallScreeningPackage = null;
553             }
554         });
555     }
556 
addRoleHolder(String roleName, String packageName)557     private void addRoleHolder(String roleName, String packageName)
558             throws Exception {
559         UserHandle user = Process.myUserHandle();
560         Executor executor = mContext.getMainExecutor();
561         LinkedBlockingQueue<Boolean> queue = new LinkedBlockingQueue(1);
562 
563         runWithShellPermissionIdentity(() -> mRoleManager.addRoleHolderAsUser(roleName,
564                 packageName, RoleManager.MANAGE_HOLDERS_FLAG_DONT_KILL_APP, user, executor,
565                 successful -> {
566                     try {
567                         queue.put(successful);
568                     } catch (InterruptedException e) {
569                         e.printStackTrace();
570                     }
571                 }));
572         boolean result = queue.poll(ASYNC_TIMEOUT, TimeUnit.MILLISECONDS);
573         assertTrue(result);
574     }
575 
removeRoleHolder(String roleName, String packageName)576     private void removeRoleHolder(String roleName, String packageName)
577             throws Exception {
578         UserHandle user = Process.myUserHandle();
579         Executor executor = mContext.getMainExecutor();
580         LinkedBlockingQueue<Boolean> queue = new LinkedBlockingQueue(1);
581 
582         runWithShellPermissionIdentity(() -> mRoleManager.removeRoleHolderAsUser(roleName,
583                 packageName, RoleManager.MANAGE_HOLDERS_FLAG_DONT_KILL_APP, user, executor,
584                 successful -> {
585                     try {
586                         queue.put(successful);
587                     } catch (InterruptedException e) {
588                         e.printStackTrace();
589                     }
590                 }));
591         boolean result = queue.poll(ASYNC_TIMEOUT, TimeUnit.MILLISECONDS);
592         assertTrue(result);
593     }
594 
grantReadContactPermission()595     private void grantReadContactPermission() {
596         runWithShellPermissionIdentity(() -> {
597             if (mPackageManager != null) {
598                 mPackageManager.grantRuntimePermission(TEST_APP_PACKAGE,
599                         Manifest.permission.READ_CONTACTS, mContext.getUser());
600             }});
601     }
602 
revokeReadContactPermission()603     private void revokeReadContactPermission() {
604         runWithShellPermissionIdentity(() -> {
605                 if (mPackageManager != null) {
606                     mPackageManager.revokeRuntimePermission(TEST_APP_PACKAGE,
607                             Manifest.permission.READ_CONTACTS, mContext.getUser());
608                 }});
609     }
610 
verifyPermission(boolean hasPermission)611     private void verifyPermission(boolean hasPermission) {
612         assertEquals(hasPermission,
613                 mPackageManager.checkPermission
614                         (Manifest.permission.READ_CONTACTS, TEST_APP_PACKAGE)
615                         == PackageManager.PERMISSION_GRANTED);
616     }
617 }
618