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