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