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.app.role.cts; 18 19 import static com.android.compatibility.common.util.SystemUtil.callWithShellPermissionIdentity; 20 import static com.android.compatibility.common.util.SystemUtil.runShellCommand; 21 import static com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity; 22 import static com.google.common.truth.Truth.assertThat; 23 24 import static org.junit.Assert.fail; 25 26 import android.app.Activity; 27 import android.app.AppOpsManager; 28 import android.app.Instrumentation; 29 import android.app.role.OnRoleHoldersChangedListener; 30 import android.app.role.RoleManager; 31 import android.content.ComponentName; 32 import android.content.Context; 33 import android.content.Intent; 34 import android.content.pm.PackageManager; 35 import android.content.pm.PermissionInfo; 36 import android.os.Process; 37 import android.os.UserHandle; 38 import android.support.test.uiautomator.By; 39 import android.support.test.uiautomator.UiDevice; 40 import android.support.test.uiautomator.UiObject2; 41 import android.support.test.uiautomator.Until; 42 import android.util.Log; 43 import android.util.Pair; 44 45 import androidx.annotation.NonNull; 46 import androidx.annotation.Nullable; 47 import androidx.test.InstrumentationRegistry; 48 import androidx.test.filters.FlakyTest; 49 import androidx.test.rule.ActivityTestRule; 50 import androidx.test.runner.AndroidJUnit4; 51 52 import com.android.compatibility.common.util.AppOpsUtils; 53 import com.android.compatibility.common.util.ThrowingRunnable; 54 55 import org.junit.After; 56 import org.junit.Before; 57 import org.junit.Rule; 58 import org.junit.Test; 59 import org.junit.runner.RunWith; 60 61 import java.io.ByteArrayOutputStream; 62 import java.io.IOException; 63 import java.nio.charset.StandardCharsets; 64 import java.util.Collections; 65 import java.util.List; 66 import java.util.Objects; 67 import java.util.concurrent.CompletableFuture; 68 import java.util.concurrent.TimeUnit; 69 import java.util.concurrent.TimeoutException; 70 import java.util.function.Consumer; 71 72 /** 73 * Tests {@link RoleManager}. 74 */ 75 @RunWith(AndroidJUnit4.class) 76 public class RoleManagerTest { 77 78 private static final String LOG_TAG = "RoleManagerTest"; 79 80 private static final long TIMEOUT_MILLIS = 15 * 1000; 81 82 private static final long UNEXPECTED_TIMEOUT_MILLIS = 1000; 83 84 private static final String ROLE_NAME = RoleManager.ROLE_BROWSER; 85 86 private static final String APP_APK_PATH = "/data/local/tmp/cts/role/CtsRoleTestApp.apk"; 87 private static final String APP_PACKAGE_NAME = "android.app.role.cts.app"; 88 private static final String APP_IS_ROLE_HELD_ACTIVITY_NAME = APP_PACKAGE_NAME 89 + ".IsRoleHeldActivity"; 90 private static final String APP_IS_ROLE_HELD_EXTRA_IS_ROLE_HELD = APP_PACKAGE_NAME 91 + ".extra.IS_ROLE_HELD"; 92 private static final String APP_REQUEST_ROLE_ACTIVITY_NAME = APP_PACKAGE_NAME 93 + ".RequestRoleActivity"; 94 95 private static final String PERMISSION_MANAGE_ROLES_FROM_CONTROLLER = 96 "com.android.permissioncontroller.permission.MANAGE_ROLES_FROM_CONTROLLER"; 97 98 private static final Instrumentation sInstrumentation = 99 InstrumentationRegistry.getInstrumentation(); 100 private static final Context sContext = InstrumentationRegistry.getTargetContext(); 101 private static final PackageManager sPackageManager = sContext.getPackageManager(); 102 private static final RoleManager sRoleManager = sContext.getSystemService(RoleManager.class); 103 private static final UiDevice sUiDevice = UiDevice.getInstance(sInstrumentation); 104 105 @Rule 106 public ActivityTestRule<WaitForResultActivity> mActivityRule = 107 new ActivityTestRule<>(WaitForResultActivity.class); 108 109 private String mRoleHolder; 110 private int mCurrentUserId; 111 112 @Before 113 public void saveRoleHolder() throws Exception { 114 List<String> roleHolders = getRoleHolders(ROLE_NAME); 115 mRoleHolder = !roleHolders.isEmpty() ? roleHolders.get(0) : null; 116 117 if (Objects.equals(mRoleHolder, APP_PACKAGE_NAME)) { 118 removeRoleHolder(ROLE_NAME, APP_PACKAGE_NAME); 119 mRoleHolder = null; 120 } 121 } 122 123 @After 124 public void restoreRoleHolder() throws Exception { 125 removeRoleHolder(ROLE_NAME, APP_PACKAGE_NAME); 126 127 if (mRoleHolder != null) { 128 addRoleHolder(ROLE_NAME, mRoleHolder); 129 } 130 131 assertIsRoleHolder(ROLE_NAME, APP_PACKAGE_NAME, false); 132 } 133 134 @Before 135 public void installApp() throws Exception { 136 mCurrentUserId = Process.myUserHandle().getIdentifier(); 137 installPackage(APP_APK_PATH); 138 } 139 140 @After 141 public void uninstallApp() throws Exception { 142 uninstallPackage(APP_PACKAGE_NAME); 143 } 144 145 @Before 146 public void wakeUpScreen() throws IOException { 147 runShellCommand(sInstrumentation, "input keyevent KEYCODE_WAKEUP"); 148 } 149 150 @Test 151 public void requestRoleIntentHasPermissionControllerPackage() throws Exception { 152 Intent intent = sRoleManager.createRequestRoleIntent(ROLE_NAME); 153 154 assertThat(intent.getPackage()).isEqualTo( 155 sPackageManager.getPermissionControllerPackageName()); 156 } 157 158 @Test 159 public void requestRoleIntentHasExtraRoleName() throws Exception { 160 Intent intent = sRoleManager.createRequestRoleIntent(ROLE_NAME); 161 162 assertThat(intent.getStringExtra(Intent.EXTRA_ROLE_NAME)).isEqualTo(ROLE_NAME); 163 } 164 165 @FlakyTest 166 @Test 167 public void requestRoleAndDenyThenIsNotRoleHolder() throws Exception { 168 requestRole(ROLE_NAME); 169 respondToRoleRequest(false); 170 171 assertIsRoleHolder(ROLE_NAME, APP_PACKAGE_NAME, false); 172 } 173 174 @FlakyTest 175 @Test 176 public void requestRoleAndAllowThenIsRoleHolder() throws Exception { 177 requestRole(ROLE_NAME); 178 respondToRoleRequest(true); 179 180 assertIsRoleHolder(ROLE_NAME, APP_PACKAGE_NAME, true); 181 } 182 183 @FlakyTest 184 @Test 185 public void requestRoleFirstTimeNoDontAskAgain() throws Exception { 186 requestRole(ROLE_NAME); 187 UiObject2 dontAskAgainCheck = findDontAskAgainCheck(false); 188 189 assertThat(dontAskAgainCheck).isNull(); 190 191 respondToRoleRequest(false); 192 } 193 194 @FlakyTest 195 @Test 196 public void requestRoleAndDenyThenHasDontAskAgain() throws Exception { 197 requestRole(ROLE_NAME); 198 respondToRoleRequest(false); 199 200 requestRole(ROLE_NAME); 201 UiObject2 dontAskAgainCheck = findDontAskAgainCheck(); 202 203 assertThat(dontAskAgainCheck).isNotNull(); 204 205 respondToRoleRequest(false); 206 } 207 208 @FlakyTest 209 @Test 210 public void requestRoleAndDenyWithDontAskAgainReturnsCanceled() throws Exception { 211 requestRole(ROLE_NAME); 212 respondToRoleRequest(false); 213 214 requestRole(ROLE_NAME); 215 findDontAskAgainCheck().click(); 216 Pair<Integer, Intent> result = clickButtonAndWaitForResult(true); 217 218 assertThat(result.first).isEqualTo(Activity.RESULT_CANCELED); 219 } 220 221 @FlakyTest 222 @Test 223 public void requestRoleAndDenyWithDontAskAgainThenDeniedAutomatically() throws Exception { 224 requestRole(ROLE_NAME); 225 respondToRoleRequest(false); 226 227 requestRole(ROLE_NAME); 228 findDontAskAgainCheck().click(); 229 clickButtonAndWaitForResult(true); 230 231 requestRole(ROLE_NAME); 232 Pair<Integer, Intent> result = waitForResult(); 233 234 assertThat(result.first).isEqualTo(Activity.RESULT_CANCELED); 235 } 236 237 @FlakyTest 238 @Test 239 public void requestRoleAndDenyWithDontAskAgainAndClearDataThenShowsUiWithoutDontAskAgain() 240 throws Exception { 241 requestRole(ROLE_NAME); 242 respondToRoleRequest(false); 243 244 requestRole(ROLE_NAME); 245 findDontAskAgainCheck().click(); 246 clickButtonAndWaitForResult(true); 247 248 clearPackageData(APP_PACKAGE_NAME); 249 // Wait for the don't ask again to be forgotten. 250 Thread.sleep(2000); 251 252 requestRole(ROLE_NAME); 253 UiObject2 dontAskAgainCheck = findDontAskAgainCheck(false); 254 255 assertThat(dontAskAgainCheck).isNull(); 256 257 respondToRoleRequest(false); 258 } 259 260 @FlakyTest 261 @Test 262 public void requestRoleAndDenyWithDontAskAgainAndReinstallThenShowsUiWithoutDontAskAgain() 263 throws Exception { 264 requestRole(ROLE_NAME); 265 respondToRoleRequest(false); 266 267 requestRole(ROLE_NAME); 268 findDontAskAgainCheck().click(); 269 clickButtonAndWaitForResult(true); 270 271 uninstallPackage(APP_PACKAGE_NAME); 272 // Wait for the don't ask again to be forgotten. 273 Thread.sleep(2000); 274 installPackage(APP_APK_PATH); 275 276 requestRole(ROLE_NAME); 277 UiObject2 dontAskAgainCheck = findDontAskAgainCheck(false); 278 279 assertThat(dontAskAgainCheck).isNull(); 280 281 respondToRoleRequest(false); 282 } 283 284 @Test 285 public void requestAssistantRoleThenDeniedAutomatically() throws InterruptedException { 286 requestRole(RoleManager.ROLE_ASSISTANT); 287 Pair<Integer, Intent> result = waitForResult(); 288 289 assertThat(result.first).isEqualTo(Activity.RESULT_CANCELED); 290 } 291 292 private void requestRole(@NonNull String roleName) { 293 Intent intent = new Intent() 294 .setComponent(new ComponentName(APP_PACKAGE_NAME, APP_REQUEST_ROLE_ACTIVITY_NAME)) 295 .putExtra(Intent.EXTRA_ROLE_NAME, roleName); 296 mActivityRule.getActivity().startActivityToWaitForResult(intent); 297 } 298 299 private void respondToRoleRequest(boolean allow) throws InterruptedException, IOException { 300 if (allow) { 301 UiObject2 item = sUiDevice.wait(Until.findObject(By.text(APP_PACKAGE_NAME)), 302 TIMEOUT_MILLIS); 303 if (item == null) { 304 dumpWindowHierarchy(); 305 fail("Cannot find item to click"); 306 } 307 item.click(); 308 } 309 Pair<Integer, Intent> result = clickButtonAndWaitForResult(allow); 310 int expectedResult = allow ? Activity.RESULT_OK : Activity.RESULT_CANCELED; 311 312 assertThat(result.first).isEqualTo(expectedResult); 313 } 314 315 @Nullable 316 private UiObject2 findDontAskAgainCheck(boolean expected) { 317 return sUiDevice.wait(Until.findObject(By.text("Don\u2019t ask again")), expected 318 ? TIMEOUT_MILLIS : UNEXPECTED_TIMEOUT_MILLIS); 319 } 320 321 @Nullable 322 private UiObject2 findDontAskAgainCheck() { 323 return findDontAskAgainCheck(true); 324 } 325 326 @NonNull 327 private Pair<Integer, Intent> clickButtonAndWaitForResult(boolean positive) throws IOException, 328 InterruptedException { 329 String buttonId = positive ? "android:id/button1" : "android:id/button2"; 330 UiObject2 button = sUiDevice.wait(Until.findObject(By.res(buttonId)), TIMEOUT_MILLIS); 331 if (button == null) { 332 dumpWindowHierarchy(); 333 fail("Cannot find button to click"); 334 } 335 button.click(); 336 return waitForResult(); 337 } 338 339 private void dumpWindowHierarchy() throws InterruptedException, IOException { 340 ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); 341 sUiDevice.dumpWindowHierarchy(outputStream); 342 String windowHierarchy = outputStream.toString(StandardCharsets.UTF_8.name()); 343 344 Log.w(LOG_TAG, "Window hierarchy:"); 345 for (String line : windowHierarchy.split("\n")) { 346 Thread.sleep(10); 347 Log.w(LOG_TAG, line); 348 } 349 } 350 351 @NonNull 352 private Pair<Integer, Intent> waitForResult() throws InterruptedException { 353 return mActivityRule.getActivity().waitForActivityResult(TIMEOUT_MILLIS); 354 } 355 356 private void clearPackageData(@NonNull String packageName) { 357 runShellCommand("pm clear --user " + mCurrentUserId + " " + packageName); 358 } 359 360 private void installPackage(@NonNull String apkPath) { 361 runShellCommand("pm install -r --user " + mCurrentUserId + " " + apkPath); 362 } 363 364 private void uninstallPackage(@NonNull String packageName) { 365 runShellCommand("pm uninstall --user " + mCurrentUserId + " " + packageName); 366 } 367 368 @Test 369 public void roleIsAvailable() { 370 assertThat(sRoleManager.isRoleAvailable(ROLE_NAME)).isTrue(); 371 } 372 373 @Test 374 public void dontAddRoleHolderThenRoleIsNotHeld() throws Exception { 375 assertRoleIsHeld(ROLE_NAME, false); 376 } 377 378 @Test 379 public void addRoleHolderThenRoleIsHeld() throws Exception { 380 addRoleHolder(ROLE_NAME, APP_PACKAGE_NAME); 381 382 assertRoleIsHeld(ROLE_NAME, true); 383 } 384 385 @Test 386 public void addAndRemoveRoleHolderThenRoleIsNotHeld() throws Exception { 387 addRoleHolder(ROLE_NAME, APP_PACKAGE_NAME); 388 removeRoleHolder(ROLE_NAME, APP_PACKAGE_NAME); 389 390 assertRoleIsHeld(ROLE_NAME, false); 391 } 392 393 private void assertRoleIsHeld(@NonNull String roleName, boolean isHeld) 394 throws InterruptedException { 395 Intent intent = new Intent() 396 .setComponent(new ComponentName(APP_PACKAGE_NAME, APP_IS_ROLE_HELD_ACTIVITY_NAME)) 397 .putExtra(Intent.EXTRA_ROLE_NAME, roleName); 398 WaitForResultActivity activity = mActivityRule.getActivity(); 399 activity.startActivityToWaitForResult(intent); 400 Pair<Integer, Intent> result = activity.waitForActivityResult(TIMEOUT_MILLIS); 401 402 assertThat(result.first).isEqualTo(Activity.RESULT_OK); 403 assertThat(result.second).isNotNull(); 404 assertThat(result.second.hasExtra(APP_IS_ROLE_HELD_EXTRA_IS_ROLE_HELD)).isTrue(); 405 assertThat(result.second.getBooleanExtra(APP_IS_ROLE_HELD_EXTRA_IS_ROLE_HELD, false)) 406 .isEqualTo(isHeld); 407 } 408 409 @Test 410 public void dontAddRoleHolderThenIsNotRoleHolder() throws Exception { 411 assertIsRoleHolder(ROLE_NAME, APP_PACKAGE_NAME, false); 412 } 413 414 @Test 415 public void addRoleHolderThenIsRoleHolder() throws Exception { 416 addRoleHolder(ROLE_NAME, APP_PACKAGE_NAME); 417 418 assertIsRoleHolder(ROLE_NAME, APP_PACKAGE_NAME, true); 419 } 420 421 @Test 422 public void addAndRemoveRoleHolderThenIsNotRoleHolder() throws Exception { 423 addRoleHolder(ROLE_NAME, APP_PACKAGE_NAME); 424 removeRoleHolder(ROLE_NAME, APP_PACKAGE_NAME); 425 426 assertIsRoleHolder(ROLE_NAME, APP_PACKAGE_NAME, false); 427 } 428 429 @Test 430 public void addAndClearRoleHoldersThenIsNotRoleHolder() throws Exception { 431 addRoleHolder(ROLE_NAME, APP_PACKAGE_NAME); 432 clearRoleHolders(ROLE_NAME); 433 434 assertIsRoleHolder(ROLE_NAME, APP_PACKAGE_NAME, false); 435 } 436 437 @Test 438 public void addOnRoleHoldersChangedListenerAndAddRoleHolderThenIsNotified() throws Exception { 439 assertOnRoleHoldersChangedListenerIsNotified(() -> addRoleHolder(ROLE_NAME, 440 APP_PACKAGE_NAME)); 441 } 442 443 @Test 444 public void addOnRoleHoldersChangedListenerAndRemoveRoleHolderThenIsNotified() 445 throws Exception { 446 addRoleHolder(ROLE_NAME, APP_PACKAGE_NAME); 447 448 assertOnRoleHoldersChangedListenerIsNotified(() -> removeRoleHolder(ROLE_NAME, 449 APP_PACKAGE_NAME)); 450 } 451 452 @Test 453 public void addOnRoleHoldersChangedListenerAndClearRoleHoldersThenIsNotified() 454 throws Exception { 455 addRoleHolder(ROLE_NAME, APP_PACKAGE_NAME); 456 457 assertOnRoleHoldersChangedListenerIsNotified(() -> clearRoleHolders(ROLE_NAME)); 458 } 459 460 private void assertOnRoleHoldersChangedListenerIsNotified(@NonNull ThrowingRunnable runnable) 461 throws Exception { 462 ListenerFuture future = new ListenerFuture(); 463 UserHandle user = Process.myUserHandle(); 464 runWithShellPermissionIdentity(() -> sRoleManager.addOnRoleHoldersChangedListenerAsUser( 465 sContext.getMainExecutor(), future, user)); 466 Pair<String, UserHandle> result; 467 try { 468 runnable.run(); 469 result = future.get(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); 470 } finally { 471 runWithShellPermissionIdentity(() -> 472 sRoleManager.removeOnRoleHoldersChangedListenerAsUser(future, user)); 473 } 474 475 assertThat(result.first).isEqualTo(ROLE_NAME); 476 assertThat(result.second).isEqualTo(user); 477 } 478 479 @Test 480 public void addAndRemoveOnRoleHoldersChangedListenerAndAddRoleHolderThenIsNotNotified() 481 throws Exception { 482 ListenerFuture future = new ListenerFuture(); 483 UserHandle user = Process.myUserHandle(); 484 runWithShellPermissionIdentity(() -> { 485 sRoleManager.addOnRoleHoldersChangedListenerAsUser(sContext.getMainExecutor(), future, 486 user); 487 sRoleManager.removeOnRoleHoldersChangedListenerAsUser(future, user); 488 }); 489 addRoleHolder(ROLE_NAME, APP_PACKAGE_NAME); 490 491 try { 492 future.get(UNEXPECTED_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); 493 } catch (TimeoutException e) { 494 // Expected 495 return; 496 } 497 throw new AssertionError("OnRoleHoldersChangedListener was notified after removal"); 498 } 499 500 @Test 501 public void setRoleNamesFromControllerShouldRequireManageRolesFromControllerPermission() { 502 assertRequiresManageRolesFromControllerPermission( 503 () -> sRoleManager.setRoleNamesFromController(Collections.emptyList()), 504 "setRoleNamesFromController"); 505 } 506 507 @Test 508 public void addRoleHolderFromControllerShouldRequireManageRolesFromControllerPermission() { 509 assertRequiresManageRolesFromControllerPermission( 510 () -> sRoleManager.addRoleHolderFromController(ROLE_NAME, APP_PACKAGE_NAME), 511 "addRoleHolderFromController"); 512 } 513 514 @Test 515 public void removeRoleHolderFromControllerShouldRequireManageRolesFromControllerPermission() { 516 assertRequiresManageRolesFromControllerPermission( 517 () -> sRoleManager.removeRoleHolderFromController(ROLE_NAME, APP_PACKAGE_NAME), 518 "removeRoleHolderFromController"); 519 } 520 521 @Test 522 public void getHeldRolesFromControllerShouldRequireManageRolesFromControllerPermission() { 523 assertRequiresManageRolesFromControllerPermission( 524 () -> sRoleManager.getHeldRolesFromController(APP_PACKAGE_NAME), 525 "getHeldRolesFromController"); 526 } 527 528 private void assertRequiresManageRolesFromControllerPermission(@NonNull Runnable runnable, 529 @NonNull String methodName) { 530 try { 531 runnable.run(); 532 } catch (SecurityException e) { 533 if (e.getMessage().contains(PERMISSION_MANAGE_ROLES_FROM_CONTROLLER)) { 534 // Expected 535 return; 536 } 537 throw e; 538 } 539 fail("RoleManager." + methodName + "() should require " 540 + PERMISSION_MANAGE_ROLES_FROM_CONTROLLER); 541 } 542 543 @Test 544 public void manageRoleFromsFromControllerPermissionShouldBeDeclaredByPermissionController() 545 throws PackageManager.NameNotFoundException { 546 PermissionInfo permissionInfo = sPackageManager.getPermissionInfo( 547 PERMISSION_MANAGE_ROLES_FROM_CONTROLLER, 0); 548 549 assertThat(permissionInfo.packageName).isEqualTo( 550 sPackageManager.getPermissionControllerPackageName()); 551 assertThat(permissionInfo.getProtection()).isEqualTo(PermissionInfo.PROTECTION_SIGNATURE); 552 assertThat(permissionInfo.getProtectionFlags()).isEqualTo(0); 553 } 554 555 @Test 556 public void removeSmsRoleHolderThenDialerRoleAppOpIsNotDenied() throws Exception { 557 if (!(sRoleManager.isRoleAvailable(RoleManager.ROLE_DIALER) 558 && sRoleManager.isRoleAvailable(RoleManager.ROLE_SMS))) { 559 return; 560 } 561 562 addRoleHolder(RoleManager.ROLE_DIALER, APP_PACKAGE_NAME); 563 addRoleHolder(RoleManager.ROLE_SMS, APP_PACKAGE_NAME); 564 removeRoleHolder(RoleManager.ROLE_SMS, APP_PACKAGE_NAME); 565 566 assertThat(AppOpsUtils.getOpMode(APP_PACKAGE_NAME, AppOpsManager.OPSTR_SEND_SMS)) 567 .isEqualTo(AppOpsManager.MODE_ALLOWED); 568 } 569 570 @Test 571 public void smsRoleHasHolder() throws Exception { 572 if (!sRoleManager.isRoleAvailable(RoleManager.ROLE_SMS)) { 573 return; 574 } 575 576 assertThat(getRoleHolders(RoleManager.ROLE_SMS)).isNotEmpty(); 577 } 578 579 private List<String> getRoleHolders(@NonNull String roleName) throws Exception { 580 return callWithShellPermissionIdentity(() -> sRoleManager.getRoleHolders(roleName)); 581 } 582 583 private void assertIsRoleHolder(@NonNull String roleName, @NonNull String packageName, 584 boolean shouldBeRoleHolder) throws Exception { 585 List<String> packageNames = getRoleHolders(roleName); 586 587 if (shouldBeRoleHolder) { 588 assertThat(packageNames).contains(packageName); 589 } else { 590 assertThat(packageNames).doesNotContain(packageName); 591 } 592 } 593 594 private void addRoleHolder(@NonNull String roleName, @NonNull String packageName) 595 throws Exception { 596 CallbackFuture future = new CallbackFuture(); 597 runWithShellPermissionIdentity(() -> sRoleManager.addRoleHolderAsUser(roleName, 598 packageName, 0, Process.myUserHandle(), sContext.getMainExecutor(), future)); 599 future.get(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); 600 } 601 602 private void removeRoleHolder(@NonNull String roleName, @NonNull String packageName) 603 throws Exception { 604 CallbackFuture future = new CallbackFuture(); 605 runWithShellPermissionIdentity(() -> sRoleManager.removeRoleHolderAsUser(roleName, 606 packageName, 0, Process.myUserHandle(), sContext.getMainExecutor(), future)); 607 future.get(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); 608 } 609 610 private void clearRoleHolders(@NonNull String roleName) throws Exception { 611 CallbackFuture future = new CallbackFuture(); 612 runWithShellPermissionIdentity(() -> sRoleManager.clearRoleHoldersAsUser(roleName, 0, 613 Process.myUserHandle(), sContext.getMainExecutor(), future)); 614 future.get(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); 615 } 616 617 private static class ListenerFuture extends CompletableFuture<Pair<String, UserHandle>> 618 implements OnRoleHoldersChangedListener { 619 620 @Override 621 public void onRoleHoldersChanged(@NonNull String roleName, @NonNull UserHandle user) { 622 complete(new Pair<>(roleName, user)); 623 } 624 } 625 626 private static class CallbackFuture extends CompletableFuture<Void> 627 implements Consumer<Boolean> { 628 629 @Override 630 public void accept(Boolean successful) { 631 if (successful) { 632 complete(null); 633 } else { 634 completeExceptionally(new RuntimeException()); 635 } 636 } 637 } 638 } 639