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         Bundle extras = new Bundle();
382         extras.putParcelable(TestUtils.EXTRA_PHONE_NUMBER, TEST_OUTGOING_NUMBER);
383         // Create a new outgoing call.
384         placeAndVerifyCall(extras);
385 
386         if (addContact) {
387             assertEquals(1, TestUtils.deleteContact(mContentResolver, contactUri));
388         }
389 
390         mInCallCallbacks.getService().disconnectAllCalls();
391         assertNumCalls(mInCallCallbacks.getService(), 0);
392 
393         // Wait for it to log.
394         callLogEntryLatch.await(ASYNC_TIMEOUT, TimeUnit.MILLISECONDS);
395     }
396 
addIncoming(boolean disconnectImmediately, boolean addContact)397     private Uri addIncoming(boolean disconnectImmediately, boolean addContact) throws Exception {
398         // Add call through TelecomManager; we can't use the test methods since they assume a call
399         // makes it through to the InCallService; this is blocked so it shouldn't.
400         Uri testNumber = createRandomTestNumber();
401         if (addContact) {
402             mContactUri = TestUtils.insertContact(mContentResolver,
403                     testNumber.getSchemeSpecificPart());
404         }
405 
406         // Setup content observer to notify us when we call log entry is added.
407         CountDownLatch callLogEntryLatch = getCallLogEntryLatch();
408 
409         Bundle extras = new Bundle();
410         extras.putParcelable(TelecomManager.EXTRA_INCOMING_CALL_ADDRESS, testNumber);
411         mTelecomManager.addNewIncomingCall(TestUtils.TEST_PHONE_ACCOUNT_HANDLE, extras);
412 
413         // Wait until the new incoming call is processed.
414         waitOnAllHandlers(getInstrumentation());
415 
416         if (disconnectImmediately) {
417             // Disconnect the call
418             mInCallCallbacks.getService().disconnectAllCalls();
419             assertNumCalls(mInCallCallbacks.getService(), 0);
420         }
421 
422         // Wait for the content observer to report that we have gotten a new call log entry.
423         callLogEntryLatch.await(ASYNC_TIMEOUT, TimeUnit.MILLISECONDS);
424         return testNumber;
425     }
426 
addIncomingAndVerifyAllowed(boolean addContact)427     private void addIncomingAndVerifyAllowed(boolean addContact) throws Exception {
428         Uri testNumber = addIncoming(true, addContact);
429 
430         // Query the latest entry into the call log.
431         Cursor callsCursor = mContentResolver.query(CallLog.Calls.CONTENT_URI, null,
432                 null, null, CallLog.Calls._ID + " DESC limit 1;");
433         int numberIndex = callsCursor.getColumnIndex(CallLog.Calls.NUMBER);
434         int callTypeIndex = callsCursor.getColumnIndex(CallLog.Calls.TYPE);
435         int blockReasonIndex = callsCursor.getColumnIndex(CallLog.Calls.BLOCK_REASON);
436         if (callsCursor.moveToNext()) {
437             String number = callsCursor.getString(numberIndex);
438             int callType = callsCursor.getInt(callTypeIndex);
439             int blockReason = callsCursor.getInt(blockReasonIndex);
440             assertEquals(testNumber.getSchemeSpecificPart(), number);
441             assertEquals(CallLog.Calls.INCOMING_TYPE, callType);
442             assertEquals(CallLog.Calls.BLOCK_REASON_NOT_BLOCKED, blockReason);
443         } else {
444             fail("Call not logged");
445         }
446 
447         if (addContact && mContactUri != null) {
448             assertEquals(1, TestUtils.deleteContact(mContentResolver, mContactUri));
449         }
450     }
451 
addIncomingAndVerifyBlocked(boolean addContact)452     private void addIncomingAndVerifyBlocked(boolean addContact) throws Exception {
453         Uri testNumber = addIncoming(false, addContact);
454 
455         // Query the latest entry into the call log.
456         Cursor callsCursor = mContentResolver.query(CallLog.Calls.CONTENT_URI, null,
457                 null, null, CallLog.Calls._ID + " DESC limit 1;");
458         int numberIndex = callsCursor.getColumnIndex(CallLog.Calls.NUMBER);
459         int callTypeIndex = callsCursor.getColumnIndex(CallLog.Calls.TYPE);
460         int blockReasonIndex = callsCursor.getColumnIndex(CallLog.Calls.BLOCK_REASON);
461         int callScreeningAppNameIndex = callsCursor.getColumnIndex(
462                 CallLog.Calls.CALL_SCREENING_APP_NAME);
463         int callScreeningCmpNameIndex = callsCursor.getColumnIndex(
464                 CallLog.Calls.CALL_SCREENING_COMPONENT_NAME);
465         if (callsCursor.moveToNext()) {
466             String number = callsCursor.getString(numberIndex);
467             int callType = callsCursor.getInt(callTypeIndex);
468             int blockReason = callsCursor.getInt(blockReasonIndex);
469             String screeningAppName = callsCursor.getString(callScreeningAppNameIndex);
470             String screeningComponentName = callsCursor.getString(callScreeningCmpNameIndex);
471             assertEquals(testNumber.getSchemeSpecificPart(), number);
472             assertEquals(CallLog.Calls.BLOCKED_TYPE, callType);
473             assertEquals(CallLog.Calls.BLOCK_REASON_CALL_SCREENING_SERVICE, blockReason);
474             assertEquals(TEST_APP_NAME, screeningAppName);
475             assertEquals(TEST_APP_COMPONENT, screeningComponentName);
476         } else {
477             fail("Blocked call was not logged.");
478         }
479 
480         if (addContact && mContactUri != null) {
481             assertEquals(1, TestUtils.deleteContact(mContentResolver, mContactUri));
482         }
483     }
484 
addIncomingAndVerifyCallExtraForSilence(boolean expectedIsSilentRingingExtraSet)485     private void addIncomingAndVerifyCallExtraForSilence(boolean expectedIsSilentRingingExtraSet)
486             throws Exception {
487         Uri testNumber = addIncoming(false, false);
488 
489         waitUntilConditionIsTrueOrTimeout(
490                 new Condition() {
491                     @Override
492                     public Object expected() {
493                         return true;
494                     }
495 
496                     @Override
497                     public Object actual() {
498                         // Verify that the call extra matches expectation
499                         Call call = mInCallCallbacks.getService().getLastCall();
500                         return expectedIsSilentRingingExtraSet ==
501                                 call.getDetails().getExtras().getBoolean(
502                                         Call.EXTRA_SILENT_RINGING_REQUESTED);
503                     }
504                 },
505                 TestUtils.WAIT_FOR_STATE_CHANGE_TIMEOUT_MS,
506                         "Call extra - verification failed, expected the extra " +
507                         "EXTRA_SILENT_RINGING_REQUESTED to be set:" +
508                         expectedIsSilentRingingExtraSet);
509     }
510 
511     /**
512      * Sets up a binder used to control the CallScreeningServiceCtsTestApp.
513      * This app is a standalone APK so that it can reside in a package name outside of the one the
514      * CTS test itself runs in (since that APK is where the CTS InCallService resides).
515      * @throws InterruptedException
516      */
setupControlBinder()517     private void setupControlBinder() throws InterruptedException {
518         Intent bindIntent = new Intent(CallScreeningServiceControl.CONTROL_INTERFACE_ACTION);
519         bindIntent.setComponent(CallScreeningServiceControl.CONTROL_INTERFACE_COMPONENT);
520         final CountDownLatch bindLatch = new CountDownLatch(1);
521 
522         boolean success = mContext.bindService(bindIntent, new ServiceConnection() {
523             @Override
524             public void onServiceConnected(ComponentName name, IBinder service) {
525                 mCallScreeningControl = ICallScreeningControl.Stub.asInterface(service);
526                 bindLatch.countDown();
527             }
528 
529             @Override
530             public void onServiceDisconnected(ComponentName name) {
531                 mCallScreeningControl = null;
532             }
533         }, Context.BIND_AUTO_CREATE);
534         if (!success) {
535             fail("Failed to get control interface -- bind error");
536         }
537         bindLatch.await(ASYNC_TIMEOUT, TimeUnit.MILLISECONDS);
538     }
539 
540     /**
541      * Use RoleManager to query the previous call screening app so we can restore it later.
542      */
rememberPreviousCallScreeningApp()543     private void rememberPreviousCallScreeningApp() {
544         runWithShellPermissionIdentity(() -> {
545             List<String> callScreeningApps = mRoleManager.getRoleHolders(ROLE_CALL_SCREENING);
546             if (!callScreeningApps.isEmpty()) {
547                 mPreviousCallScreeningPackage = callScreeningApps.get(0);
548             } else {
549                 mPreviousCallScreeningPackage = null;
550             }
551         });
552     }
553 
addRoleHolder(String roleName, String packageName)554     private void addRoleHolder(String roleName, String packageName)
555             throws Exception {
556         UserHandle user = Process.myUserHandle();
557         Executor executor = mContext.getMainExecutor();
558         LinkedBlockingQueue<Boolean> queue = new LinkedBlockingQueue(1);
559 
560         runWithShellPermissionIdentity(() -> mRoleManager.addRoleHolderAsUser(roleName,
561                 packageName, RoleManager.MANAGE_HOLDERS_FLAG_DONT_KILL_APP, user, executor,
562                 successful -> {
563                     try {
564                         queue.put(successful);
565                     } catch (InterruptedException e) {
566                         e.printStackTrace();
567                     }
568                 }));
569         boolean result = queue.poll(ASYNC_TIMEOUT, TimeUnit.MILLISECONDS);
570         assertTrue(result);
571     }
572 
removeRoleHolder(String roleName, String packageName)573     private void removeRoleHolder(String roleName, String packageName)
574             throws Exception {
575         UserHandle user = Process.myUserHandle();
576         Executor executor = mContext.getMainExecutor();
577         LinkedBlockingQueue<Boolean> queue = new LinkedBlockingQueue(1);
578 
579         runWithShellPermissionIdentity(() -> mRoleManager.removeRoleHolderAsUser(roleName,
580                 packageName, RoleManager.MANAGE_HOLDERS_FLAG_DONT_KILL_APP, user, executor,
581                 successful -> {
582                     try {
583                         queue.put(successful);
584                     } catch (InterruptedException e) {
585                         e.printStackTrace();
586                     }
587                 }));
588         boolean result = queue.poll(ASYNC_TIMEOUT, TimeUnit.MILLISECONDS);
589         assertTrue(result);
590     }
591 
grantReadContactPermission()592     private void grantReadContactPermission() {
593         runWithShellPermissionIdentity(() -> {
594             if (mPackageManager != null) {
595                 mPackageManager.grantRuntimePermission(TEST_APP_PACKAGE,
596                         Manifest.permission.READ_CONTACTS, mContext.getUser());
597             }});
598     }
599 
revokeReadContactPermission()600     private void revokeReadContactPermission() {
601         runWithShellPermissionIdentity(() -> {
602                 if (mPackageManager != null) {
603                     mPackageManager.revokeRuntimePermission(TEST_APP_PACKAGE,
604                             Manifest.permission.READ_CONTACTS, mContext.getUser());
605                 }});
606     }
607 
verifyPermission(boolean hasPermission)608     private void verifyPermission(boolean hasPermission) {
609         assertEquals(hasPermission,
610                 mPackageManager.checkPermission
611                         (Manifest.permission.READ_CONTACTS, TEST_APP_PACKAGE)
612                         == PackageManager.PERMISSION_GRANTED);
613     }
614 }
615