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; 18 19 import android.Manifest; 20 import android.annotation.CallbackExecutor; 21 import android.annotation.IntDef; 22 import android.annotation.NonNull; 23 import android.annotation.Nullable; 24 import android.annotation.RequiresPermission; 25 import android.annotation.SystemApi; 26 import android.annotation.SystemService; 27 import android.annotation.TestApi; 28 import android.annotation.UserIdInt; 29 import android.content.Context; 30 import android.content.Intent; 31 import android.os.Binder; 32 import android.os.Process; 33 import android.os.RemoteCallback; 34 import android.os.RemoteException; 35 import android.os.ServiceManager; 36 import android.os.UserHandle; 37 import android.util.ArrayMap; 38 import android.util.SparseArray; 39 40 import com.android.internal.annotations.GuardedBy; 41 import com.android.internal.util.Preconditions; 42 import com.android.internal.util.function.pooled.PooledLambda; 43 44 import java.util.List; 45 import java.util.concurrent.Executor; 46 import java.util.function.Consumer; 47 48 /** 49 * This class provides information about and manages roles. 50 * <p> 51 * A role is a unique name within the system associated with certain privileges. The list of 52 * available roles might change with a system app update, so apps should not make assumption about 53 * the availability of roles. Instead, they should always query if the role is available using 54 * {@link #isRoleAvailable(String)} before trying to do anything with it. Some predefined role names 55 * are available as constants in this class, and a list of possibly available roles can be found in 56 * the <a href="{@docRoot}reference/androidx/core/role/package-summary.html">AndroidX Role 57 * library</a>. 58 * <p> 59 * There can be multiple applications qualifying for a role, but only a subset of them can become 60 * role holders. To qualify for a role, an application must meet certain requirements, including 61 * defining certain components in its manifest. These requirements can be found in the AndroidX 62 * Libraries. Then the application will need user consent to become a role holder, which can be 63 * requested using {@link android.app.Activity#startActivityForResult(Intent, int)} with the 64 * {@code Intent} obtained from {@link #createRequestRoleIntent(String)}. 65 * <p> 66 * Upon becoming a role holder, the application may be granted certain privileges that are role 67 * specific. When the application loses its role, these privileges will also be revoked. 68 */ 69 @SystemService(Context.ROLE_SERVICE) 70 public final class RoleManager { 71 72 private static final String LOG_TAG = RoleManager.class.getSimpleName(); 73 74 /** 75 * The name of the assistant app role. 76 * 77 * @see android.service.voice.VoiceInteractionService 78 */ 79 public static final String ROLE_ASSISTANT = "android.app.role.ASSISTANT"; 80 81 /** 82 * The name of the browser role. 83 * 84 * @see Intent#CATEGORY_APP_BROWSER 85 */ 86 public static final String ROLE_BROWSER = "android.app.role.BROWSER"; 87 88 /** 89 * The name of the dialer role. 90 * 91 * @see Intent#ACTION_DIAL 92 */ 93 public static final String ROLE_DIALER = "android.app.role.DIALER"; 94 95 /** 96 * The name of the SMS role. 97 * 98 * @see Intent#CATEGORY_APP_MESSAGING 99 */ 100 public static final String ROLE_SMS = "android.app.role.SMS"; 101 102 /** 103 * The name of the emergency role 104 * 105 * @see android.telephony.TelephonyManager#ACTION_EMERGENCY_ASSISTANCE 106 */ 107 public static final String ROLE_EMERGENCY = "android.app.role.EMERGENCY"; 108 109 /** 110 * The name of the home role. 111 * 112 * @see Intent#CATEGORY_HOME 113 */ 114 public static final String ROLE_HOME = "android.app.role.HOME"; 115 116 /** 117 * The name of the call redirection role. 118 * <p> 119 * A call redirection app provides a means to re-write the phone number for an outgoing call to 120 * place the call through a call redirection service. 121 * 122 * @see android.telecom.CallRedirectionService 123 */ 124 public static final String ROLE_CALL_REDIRECTION = "android.app.role.CALL_REDIRECTION"; 125 126 /** 127 * The name of the call screening and caller id role. 128 * 129 * @see android.telecom.CallScreeningService 130 */ 131 public static final String ROLE_CALL_SCREENING = "android.app.role.CALL_SCREENING"; 132 133 /** 134 * @hide 135 */ 136 @IntDef(flag = true, value = { MANAGE_HOLDERS_FLAG_DONT_KILL_APP }) 137 public @interface ManageHoldersFlags {} 138 139 /** 140 * Flag parameter for {@link #addRoleHolderAsUser}, {@link #removeRoleHolderAsUser} and 141 * {@link #clearRoleHoldersAsUser} to indicate that apps should not be killed when changing 142 * their role holder status. 143 * 144 * @hide 145 */ 146 @SystemApi 147 @TestApi 148 public static final int MANAGE_HOLDERS_FLAG_DONT_KILL_APP = 1; 149 150 /** 151 * The action used to request user approval of a role for an application. 152 * 153 * @hide 154 */ 155 public static final String ACTION_REQUEST_ROLE = "android.app.role.action.REQUEST_ROLE"; 156 157 /** 158 * The permission required to manage records of role holders in {@link RoleManager} directly. 159 * 160 * @hide 161 */ 162 public static final String PERMISSION_MANAGE_ROLES_FROM_CONTROLLER = 163 "com.android.permissioncontroller.permission.MANAGE_ROLES_FROM_CONTROLLER"; 164 165 @NonNull 166 private final Context mContext; 167 168 @NonNull 169 private final IRoleManager mService; 170 171 @GuardedBy("mListenersLock") 172 @NonNull 173 private final SparseArray<ArrayMap<OnRoleHoldersChangedListener, 174 OnRoleHoldersChangedListenerDelegate>> mListeners = new SparseArray<>(); 175 @NonNull 176 private final Object mListenersLock = new Object(); 177 178 /** 179 * @hide 180 */ RoleManager(@onNull Context context)181 public RoleManager(@NonNull Context context) throws ServiceManager.ServiceNotFoundException { 182 mContext = context; 183 mService = IRoleManager.Stub.asInterface(ServiceManager.getServiceOrThrow( 184 Context.ROLE_SERVICE)); 185 } 186 187 /** 188 * Returns an {@code Intent} suitable for passing to 189 * {@link android.app.Activity#startActivityForResult(Intent, int)} which prompts the user to 190 * grant a role to this application. 191 * <p> 192 * If the role is granted, the {@code resultCode} will be 193 * {@link android.app.Activity#RESULT_OK}, otherwise it will be 194 * {@link android.app.Activity#RESULT_CANCELED}. 195 * 196 * @param roleName the name of requested role 197 * 198 * @return the {@code Intent} to prompt user to grant the role 199 */ 200 @NonNull createRequestRoleIntent(@onNull String roleName)201 public Intent createRequestRoleIntent(@NonNull String roleName) { 202 Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty"); 203 Intent intent = new Intent(ACTION_REQUEST_ROLE); 204 intent.setPackage(mContext.getPackageManager().getPermissionControllerPackageName()); 205 intent.putExtra(Intent.EXTRA_ROLE_NAME, roleName); 206 return intent; 207 } 208 209 /** 210 * Check whether a role is available in the system. 211 * 212 * @param roleName the name of role to checking for 213 * 214 * @return whether the role is available in the system 215 */ isRoleAvailable(@onNull String roleName)216 public boolean isRoleAvailable(@NonNull String roleName) { 217 Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty"); 218 try { 219 return mService.isRoleAvailable(roleName); 220 } catch (RemoteException e) { 221 throw e.rethrowFromSystemServer(); 222 } 223 } 224 225 /** 226 * Check whether the calling application is holding a particular role. 227 * 228 * @param roleName the name of the role to check for 229 * 230 * @return whether the calling application is holding the role 231 */ isRoleHeld(@onNull String roleName)232 public boolean isRoleHeld(@NonNull String roleName) { 233 Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty"); 234 try { 235 return mService.isRoleHeld(roleName, mContext.getPackageName()); 236 } catch (RemoteException e) { 237 throw e.rethrowFromSystemServer(); 238 } 239 } 240 241 /** 242 * Get package names of the applications holding the role. 243 * <p> 244 * <strong>Note:</strong> Using this API requires holding 245 * {@code android.permission.MANAGE_ROLE_HOLDERS}. 246 * 247 * @param roleName the name of the role to get the role holder for 248 * 249 * @return a list of package names of the role holders, or an empty list if none. 250 * 251 * @see #getRoleHoldersAsUser(String, UserHandle) 252 * 253 * @hide 254 */ 255 @NonNull 256 @RequiresPermission(Manifest.permission.MANAGE_ROLE_HOLDERS) 257 @SystemApi 258 @TestApi getRoleHolders(@onNull String roleName)259 public List<String> getRoleHolders(@NonNull String roleName) { 260 return getRoleHoldersAsUser(roleName, Process.myUserHandle()); 261 } 262 263 /** 264 * Get package names of the applications holding the role. 265 * <p> 266 * <strong>Note:</strong> Using this API requires holding 267 * {@code android.permission.MANAGE_ROLE_HOLDERS} and if the user id is not the current user 268 * {@code android.permission.INTERACT_ACROSS_USERS_FULL}. 269 * 270 * @param roleName the name of the role to get the role holder for 271 * @param user the user to get the role holder for 272 * 273 * @return a list of package names of the role holders, or an empty list if none. 274 * 275 * @see #addRoleHolderAsUser(String, String, int, UserHandle, Executor, Consumer) 276 * @see #removeRoleHolderAsUser(String, String, int, UserHandle, Executor, Consumer) 277 * @see #clearRoleHoldersAsUser(String, int, UserHandle, Executor, Consumer) 278 * 279 * @hide 280 */ 281 @NonNull 282 @RequiresPermission(Manifest.permission.MANAGE_ROLE_HOLDERS) 283 @SystemApi 284 @TestApi getRoleHoldersAsUser(@onNull String roleName, @NonNull UserHandle user)285 public List<String> getRoleHoldersAsUser(@NonNull String roleName, @NonNull UserHandle user) { 286 Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty"); 287 Preconditions.checkNotNull(user, "user cannot be null"); 288 try { 289 return mService.getRoleHoldersAsUser(roleName, user.getIdentifier()); 290 } catch (RemoteException e) { 291 throw e.rethrowFromSystemServer(); 292 } 293 } 294 295 /** 296 * Add a specific application to the holders of a role. If the role is exclusive, the previous 297 * holder will be replaced. 298 * <p> 299 * <strong>Note:</strong> Using this API requires holding 300 * {@code android.permission.MANAGE_ROLE_HOLDERS} and if the user id is not the current user 301 * {@code android.permission.INTERACT_ACROSS_USERS_FULL}. 302 * 303 * @param roleName the name of the role to add the role holder for 304 * @param packageName the package name of the application to add to the role holders 305 * @param flags optional behavior flags 306 * @param user the user to add the role holder for 307 * @param executor the {@code Executor} to run the callback on. 308 * @param callback the callback for whether this call is successful 309 * 310 * @see #getRoleHoldersAsUser(String, UserHandle) 311 * @see #removeRoleHolderAsUser(String, String, int, UserHandle, Executor, Consumer) 312 * @see #clearRoleHoldersAsUser(String, int, UserHandle, Executor, Consumer) 313 * 314 * @hide 315 */ 316 @RequiresPermission(Manifest.permission.MANAGE_ROLE_HOLDERS) 317 @SystemApi 318 @TestApi addRoleHolderAsUser(@onNull String roleName, @NonNull String packageName, @ManageHoldersFlags int flags, @NonNull UserHandle user, @CallbackExecutor @NonNull Executor executor, @NonNull Consumer<Boolean> callback)319 public void addRoleHolderAsUser(@NonNull String roleName, @NonNull String packageName, 320 @ManageHoldersFlags int flags, @NonNull UserHandle user, 321 @CallbackExecutor @NonNull Executor executor, @NonNull Consumer<Boolean> callback) { 322 Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty"); 323 Preconditions.checkStringNotEmpty(packageName, "packageName cannot be null or empty"); 324 Preconditions.checkNotNull(user, "user cannot be null"); 325 Preconditions.checkNotNull(executor, "executor cannot be null"); 326 Preconditions.checkNotNull(callback, "callback cannot be null"); 327 try { 328 mService.addRoleHolderAsUser(roleName, packageName, flags, user.getIdentifier(), 329 createRemoteCallback(executor, callback)); 330 } catch (RemoteException e) { 331 throw e.rethrowFromSystemServer(); 332 } 333 } 334 335 /** 336 * Remove a specific application from the holders of a role. 337 * <p> 338 * <strong>Note:</strong> Using this API requires holding 339 * {@code android.permission.MANAGE_ROLE_HOLDERS} and if the user id is not the current user 340 * {@code android.permission.INTERACT_ACROSS_USERS_FULL}. 341 * 342 * @param roleName the name of the role to remove the role holder for 343 * @param packageName the package name of the application to remove from the role holders 344 * @param flags optional behavior flags 345 * @param user the user to remove the role holder for 346 * @param executor the {@code Executor} to run the callback on. 347 * @param callback the callback for whether this call is successful 348 * 349 * @see #getRoleHoldersAsUser(String, UserHandle) 350 * @see #addRoleHolderAsUser(String, String, int, UserHandle, Executor, Consumer) 351 * @see #clearRoleHoldersAsUser(String, int, UserHandle, Executor, Consumer) 352 * 353 * @hide 354 */ 355 @RequiresPermission(Manifest.permission.MANAGE_ROLE_HOLDERS) 356 @SystemApi 357 @TestApi removeRoleHolderAsUser(@onNull String roleName, @NonNull String packageName, @ManageHoldersFlags int flags, @NonNull UserHandle user, @CallbackExecutor @NonNull Executor executor, @NonNull Consumer<Boolean> callback)358 public void removeRoleHolderAsUser(@NonNull String roleName, @NonNull String packageName, 359 @ManageHoldersFlags int flags, @NonNull UserHandle user, 360 @CallbackExecutor @NonNull Executor executor, @NonNull Consumer<Boolean> callback) { 361 Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty"); 362 Preconditions.checkStringNotEmpty(packageName, "packageName cannot be null or empty"); 363 Preconditions.checkNotNull(user, "user cannot be null"); 364 Preconditions.checkNotNull(executor, "executor cannot be null"); 365 Preconditions.checkNotNull(callback, "callback cannot be null"); 366 try { 367 mService.removeRoleHolderAsUser(roleName, packageName, flags, user.getIdentifier(), 368 createRemoteCallback(executor, callback)); 369 } catch (RemoteException e) { 370 throw e.rethrowFromSystemServer(); 371 } 372 } 373 374 /** 375 * Remove all holders of a role. 376 * <p> 377 * <strong>Note:</strong> Using this API requires holding 378 * {@code android.permission.MANAGE_ROLE_HOLDERS} and if the user id is not the current user 379 * {@code android.permission.INTERACT_ACROSS_USERS_FULL}. 380 * 381 * @param roleName the name of the role to remove role holders for 382 * @param flags optional behavior flags 383 * @param user the user to remove role holders for 384 * @param executor the {@code Executor} to run the callback on. 385 * @param callback the callback for whether this call is successful 386 * 387 * @see #getRoleHoldersAsUser(String, UserHandle) 388 * @see #addRoleHolderAsUser(String, String, int, UserHandle, Executor, Consumer) 389 * @see #removeRoleHolderAsUser(String, String, int, UserHandle, Executor, Consumer) 390 * 391 * @hide 392 */ 393 @RequiresPermission(Manifest.permission.MANAGE_ROLE_HOLDERS) 394 @SystemApi 395 @TestApi clearRoleHoldersAsUser(@onNull String roleName, @ManageHoldersFlags int flags, @NonNull UserHandle user, @CallbackExecutor @NonNull Executor executor, @NonNull Consumer<Boolean> callback)396 public void clearRoleHoldersAsUser(@NonNull String roleName, @ManageHoldersFlags int flags, 397 @NonNull UserHandle user, @CallbackExecutor @NonNull Executor executor, 398 @NonNull Consumer<Boolean> callback) { 399 Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty"); 400 Preconditions.checkNotNull(user, "user cannot be null"); 401 Preconditions.checkNotNull(executor, "executor cannot be null"); 402 Preconditions.checkNotNull(callback, "callback cannot be null"); 403 try { 404 mService.clearRoleHoldersAsUser(roleName, flags, user.getIdentifier(), 405 createRemoteCallback(executor, callback)); 406 } catch (RemoteException e) { 407 throw e.rethrowFromSystemServer(); 408 } 409 } 410 411 @NonNull createRemoteCallback(@onNull Executor executor, @NonNull Consumer<Boolean> callback)412 private static RemoteCallback createRemoteCallback(@NonNull Executor executor, 413 @NonNull Consumer<Boolean> callback) { 414 return new RemoteCallback(result -> executor.execute(() -> { 415 boolean successful = result != null; 416 long token = Binder.clearCallingIdentity(); 417 try { 418 callback.accept(successful); 419 } finally { 420 Binder.restoreCallingIdentity(token); 421 } 422 })); 423 } 424 425 /** 426 * Add a listener to observe role holder changes 427 * <p> 428 * <strong>Note:</strong> Using this API requires holding 429 * {@code android.permission.OBSERVE_ROLE_HOLDERS} and if the user id is not the current user 430 * {@code android.permission.INTERACT_ACROSS_USERS_FULL}. 431 * 432 * @param executor the {@code Executor} to call the listener on. 433 * @param listener the listener to be added 434 * @param user the user to add the listener for 435 * 436 * @see #removeOnRoleHoldersChangedListenerAsUser(OnRoleHoldersChangedListener, UserHandle) 437 * 438 * @hide 439 */ 440 @RequiresPermission(Manifest.permission.OBSERVE_ROLE_HOLDERS) 441 @SystemApi 442 @TestApi addOnRoleHoldersChangedListenerAsUser(@allbackExecutor @onNull Executor executor, @NonNull OnRoleHoldersChangedListener listener, @NonNull UserHandle user)443 public void addOnRoleHoldersChangedListenerAsUser(@CallbackExecutor @NonNull Executor executor, 444 @NonNull OnRoleHoldersChangedListener listener, @NonNull UserHandle user) { 445 Preconditions.checkNotNull(executor, "executor cannot be null"); 446 Preconditions.checkNotNull(listener, "listener cannot be null"); 447 Preconditions.checkNotNull(user, "user cannot be null"); 448 int userId = user.getIdentifier(); 449 synchronized (mListenersLock) { 450 ArrayMap<OnRoleHoldersChangedListener, OnRoleHoldersChangedListenerDelegate> listeners = 451 mListeners.get(userId); 452 if (listeners == null) { 453 listeners = new ArrayMap<>(); 454 mListeners.put(userId, listeners); 455 } else { 456 if (listeners.containsKey(listener)) { 457 return; 458 } 459 } 460 OnRoleHoldersChangedListenerDelegate listenerDelegate = 461 new OnRoleHoldersChangedListenerDelegate(executor, listener); 462 try { 463 mService.addOnRoleHoldersChangedListenerAsUser(listenerDelegate, userId); 464 } catch (RemoteException e) { 465 throw e.rethrowFromSystemServer(); 466 } 467 listeners.put(listener, listenerDelegate); 468 } 469 } 470 471 /** 472 * Remove a listener observing role holder changes 473 * <p> 474 * <strong>Note:</strong> Using this API requires holding 475 * {@code android.permission.OBSERVE_ROLE_HOLDERS} and if the user id is not the current user 476 * {@code android.permission.INTERACT_ACROSS_USERS_FULL}. 477 * 478 * @param listener the listener to be removed 479 * @param user the user to remove the listener for 480 * 481 * @see #addOnRoleHoldersChangedListenerAsUser(Executor, OnRoleHoldersChangedListener, 482 * UserHandle) 483 * 484 * @hide 485 */ 486 @RequiresPermission(Manifest.permission.OBSERVE_ROLE_HOLDERS) 487 @SystemApi 488 @TestApi removeOnRoleHoldersChangedListenerAsUser( @onNull OnRoleHoldersChangedListener listener, @NonNull UserHandle user)489 public void removeOnRoleHoldersChangedListenerAsUser( 490 @NonNull OnRoleHoldersChangedListener listener, @NonNull UserHandle user) { 491 Preconditions.checkNotNull(listener, "listener cannot be null"); 492 Preconditions.checkNotNull(user, "user cannot be null"); 493 int userId = user.getIdentifier(); 494 synchronized (mListenersLock) { 495 ArrayMap<OnRoleHoldersChangedListener, OnRoleHoldersChangedListenerDelegate> listeners = 496 mListeners.get(userId); 497 if (listeners == null) { 498 return; 499 } 500 OnRoleHoldersChangedListenerDelegate listenerDelegate = listeners.get(listener); 501 if (listenerDelegate == null) { 502 return; 503 } 504 try { 505 mService.removeOnRoleHoldersChangedListenerAsUser(listenerDelegate, 506 user.getIdentifier()); 507 } catch (RemoteException e) { 508 throw e.rethrowFromSystemServer(); 509 } 510 listeners.remove(listener); 511 if (listeners.isEmpty()) { 512 mListeners.remove(userId); 513 } 514 } 515 } 516 517 /** 518 * Set the names of all the available roles. Should only be called from 519 * {@link android.app.role.RoleControllerService}. 520 * <p> 521 * <strong>Note:</strong> Using this API requires holding 522 * {@link #PERMISSION_MANAGE_ROLES_FROM_CONTROLLER}. 523 * 524 * @param roleNames the names of all the available roles 525 * 526 * @hide 527 */ 528 @RequiresPermission(PERMISSION_MANAGE_ROLES_FROM_CONTROLLER) 529 @SystemApi 530 @TestApi setRoleNamesFromController(@onNull List<String> roleNames)531 public void setRoleNamesFromController(@NonNull List<String> roleNames) { 532 Preconditions.checkNotNull(roleNames, "roleNames cannot be null"); 533 try { 534 mService.setRoleNamesFromController(roleNames); 535 } catch (RemoteException e) { 536 throw e.rethrowFromSystemServer(); 537 } 538 } 539 540 /** 541 * Add a specific application to the holders of a role, only modifying records inside 542 * {@link RoleManager}. Should only be called from 543 * {@link android.app.role.RoleControllerService}. 544 * <p> 545 * <strong>Note:</strong> Using this API requires holding 546 * {@link #PERMISSION_MANAGE_ROLES_FROM_CONTROLLER}. 547 * 548 * @param roleName the name of the role to add the role holder for 549 * @param packageName the package name of the application to add to the role holders 550 * 551 * @return whether the operation was successful, and will also be {@code true} if a matching 552 * role holder is already found. 553 * 554 * @see #getRoleHolders(String) 555 * @see #removeRoleHolderFromController(String, String) 556 * 557 * @hide 558 */ 559 @RequiresPermission(PERMISSION_MANAGE_ROLES_FROM_CONTROLLER) 560 @SystemApi 561 @TestApi addRoleHolderFromController(@onNull String roleName, @NonNull String packageName)562 public boolean addRoleHolderFromController(@NonNull String roleName, 563 @NonNull String packageName) { 564 Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty"); 565 Preconditions.checkStringNotEmpty(packageName, "packageName cannot be null or empty"); 566 try { 567 return mService.addRoleHolderFromController(roleName, packageName); 568 } catch (RemoteException e) { 569 throw e.rethrowFromSystemServer(); 570 } 571 } 572 573 /** 574 * Remove a specific application from the holders of a role, only modifying records inside 575 * {@link RoleManager}. Should only be called from 576 * {@link android.app.role.RoleControllerService}. 577 * <p> 578 * <strong>Note:</strong> Using this API requires holding 579 * {@link #PERMISSION_MANAGE_ROLES_FROM_CONTROLLER}. 580 * 581 * @param roleName the name of the role to remove the role holder for 582 * @param packageName the package name of the application to remove from the role holders 583 * 584 * @return whether the operation was successful, and will also be {@code true} if no matching 585 * role holder was found to remove. 586 * 587 * @see #getRoleHolders(String) 588 * @see #addRoleHolderFromController(String, String) 589 * 590 * @hide 591 */ 592 @RequiresPermission(PERMISSION_MANAGE_ROLES_FROM_CONTROLLER) 593 @SystemApi 594 @TestApi removeRoleHolderFromController(@onNull String roleName, @NonNull String packageName)595 public boolean removeRoleHolderFromController(@NonNull String roleName, 596 @NonNull String packageName) { 597 Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty"); 598 Preconditions.checkStringNotEmpty(packageName, "packageName cannot be null or empty"); 599 try { 600 return mService.removeRoleHolderFromController(roleName, packageName); 601 } catch (RemoteException e) { 602 throw e.rethrowFromSystemServer(); 603 } 604 } 605 606 /** 607 * Returns the list of all roles that the given package is currently holding 608 * 609 * @param packageName the package name 610 * @return the list of role names 611 * 612 * @hide 613 */ 614 @NonNull 615 @RequiresPermission(PERMISSION_MANAGE_ROLES_FROM_CONTROLLER) 616 @SystemApi 617 @TestApi getHeldRolesFromController(@onNull String packageName)618 public List<String> getHeldRolesFromController(@NonNull String packageName) { 619 Preconditions.checkStringNotEmpty(packageName, "packageName cannot be null or empty"); 620 try { 621 return mService.getHeldRolesFromController(packageName); 622 } catch (RemoteException e) { 623 throw e.rethrowFromSystemServer(); 624 } 625 } 626 627 /** 628 * Allows getting the role holder for {@link #ROLE_SMS} without 629 * {@link Manifest.permission#OBSERVE_ROLE_HOLDERS}, as required by 630 * {@link android.provider.Telephony.Sms#getDefaultSmsPackage(Context)} 631 * 632 * @hide 633 */ 634 @Nullable getDefaultSmsPackage(@serIdInt int userId)635 public String getDefaultSmsPackage(@UserIdInt int userId) { 636 try { 637 return mService.getDefaultSmsPackage(userId); 638 } catch (RemoteException e) { 639 throw e.rethrowFromSystemServer(); 640 } 641 } 642 643 private static class OnRoleHoldersChangedListenerDelegate 644 extends IOnRoleHoldersChangedListener.Stub { 645 646 @NonNull 647 private final Executor mExecutor; 648 @NonNull 649 private final OnRoleHoldersChangedListener mListener; 650 OnRoleHoldersChangedListenerDelegate(@onNull Executor executor, @NonNull OnRoleHoldersChangedListener listener)651 OnRoleHoldersChangedListenerDelegate(@NonNull Executor executor, 652 @NonNull OnRoleHoldersChangedListener listener) { 653 mExecutor = executor; 654 mListener = listener; 655 } 656 657 @Override onRoleHoldersChanged(@onNull String roleName, @UserIdInt int userId)658 public void onRoleHoldersChanged(@NonNull String roleName, @UserIdInt int userId) { 659 long token = Binder.clearCallingIdentity(); 660 try { 661 mExecutor.execute(PooledLambda.obtainRunnable( 662 OnRoleHoldersChangedListener::onRoleHoldersChanged, mListener, roleName, 663 UserHandle.of(userId))); 664 } finally { 665 Binder.restoreCallingIdentity(token); 666 } 667 } 668 } 669 } 670