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