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