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.SuppressLint; 26 import android.annotation.SystemApi; 27 import android.annotation.SystemService; 28 import android.annotation.UserIdInt; 29 import android.content.Context; 30 import android.content.Intent; 31 import android.os.Binder; 32 import android.os.Build; 33 import android.os.Process; 34 import android.os.RemoteCallback; 35 import android.os.RemoteException; 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.modules.annotation.MinSdk; 43 44 import java.util.List; 45 import java.util.Objects; 46 import java.util.concurrent.Executor; 47 import java.util.function.Consumer; 48 49 /** 50 * This class provides information about and manages roles. 51 * <p> 52 * A role is a unique name within the system associated with certain privileges. The list of 53 * available roles might change with a system app update, so apps should not make assumption about 54 * the availability of roles. Instead, they should always query if the role is available using 55 * {@link #isRoleAvailable(String)} before trying to do anything with it. Some predefined role names 56 * are available as constants in this class, and a list of possibly available roles can be found in 57 * the <a href="{@docRoot}reference/androidx/core/role/package-summary.html">AndroidX Role 58 * library</a>. 59 * <p> 60 * There can be multiple applications qualifying for a role, but only a subset of them can become 61 * role holders. To qualify for a role, an application must meet certain requirements, including 62 * defining certain components in its manifest. These requirements can be found in the AndroidX 63 * Libraries. Then the application will need user consent to become a role holder, which can be 64 * requested using {@link android.app.Activity#startActivityForResult(Intent, int)} with the 65 * {@code Intent} obtained from {@link #createRequestRoleIntent(String)}. 66 * <p> 67 * Upon becoming a role holder, the application may be granted certain privileges that are role 68 * specific. When the application loses its role, these privileges will also be revoked. 69 */ 70 @SystemService(Context.ROLE_SERVICE) 71 public final class RoleManager { 72 /** 73 * The name of the assistant app role. 74 * 75 * @see android.service.voice.VoiceInteractionService 76 */ 77 public static final String ROLE_ASSISTANT = "android.app.role.ASSISTANT"; 78 79 /** 80 * The name of the browser role. 81 * 82 * @see Intent#CATEGORY_APP_BROWSER 83 */ 84 public static final String ROLE_BROWSER = "android.app.role.BROWSER"; 85 86 /** 87 * The name of the dialer role. 88 * 89 * @see Intent#ACTION_DIAL 90 * @see android.telecom.InCallService 91 */ 92 public static final String ROLE_DIALER = "android.app.role.DIALER"; 93 94 /** 95 * The name of the SMS role. 96 * 97 * @see Intent#CATEGORY_APP_MESSAGING 98 */ 99 public static final String ROLE_SMS = "android.app.role.SMS"; 100 101 /** 102 * The name of the emergency role 103 */ 104 public static final String ROLE_EMERGENCY = "android.app.role.EMERGENCY"; 105 106 /** 107 * The name of the home role. 108 * 109 * @see Intent#CATEGORY_HOME 110 */ 111 public static final String ROLE_HOME = "android.app.role.HOME"; 112 113 /** 114 * The name of the call redirection role. 115 * <p> 116 * A call redirection app provides a means to re-write the phone number for an outgoing call to 117 * place the call through a call redirection service. 118 * 119 * @see android.telecom.CallRedirectionService 120 */ 121 public static final String ROLE_CALL_REDIRECTION = "android.app.role.CALL_REDIRECTION"; 122 123 /** 124 * The name of the call screening and caller id role. 125 * 126 * @see android.telecom.CallScreeningService 127 */ 128 public static final String ROLE_CALL_SCREENING = "android.app.role.CALL_SCREENING"; 129 130 /** 131 * The name of the system wellbeing role. 132 * 133 * @hide 134 */ 135 @SystemApi 136 public static final String ROLE_SYSTEM_WELLBEING = "android.app.role.SYSTEM_WELLBEING"; 137 138 /** 139 * The name of the system activity recognizer role. 140 * 141 * @hide 142 */ 143 @SystemApi 144 public static final String ROLE_SYSTEM_ACTIVITY_RECOGNIZER = 145 "android.app.role.SYSTEM_ACTIVITY_RECOGNIZER"; 146 147 /** 148 * @hide 149 */ 150 @IntDef(flag = true, value = { MANAGE_HOLDERS_FLAG_DONT_KILL_APP }) 151 public @interface ManageHoldersFlags {} 152 153 /** 154 * Flag parameter for {@link #addRoleHolderAsUser}, {@link #removeRoleHolderAsUser} and 155 * {@link #clearRoleHoldersAsUser} to indicate that apps should not be killed when changing 156 * their role holder status. 157 * 158 * @hide 159 */ 160 @SystemApi 161 public static final int MANAGE_HOLDERS_FLAG_DONT_KILL_APP = 1; 162 163 /** 164 * The action used to request user approval of a role for an application. 165 * 166 * @hide 167 */ 168 public static final String ACTION_REQUEST_ROLE = "android.app.role.action.REQUEST_ROLE"; 169 170 /** 171 * The permission required to manage records of role holders in {@link RoleManager} directly. 172 * 173 * @hide 174 */ 175 public static final String PERMISSION_MANAGE_ROLES_FROM_CONTROLLER = 176 "com.android.permissioncontroller.permission.MANAGE_ROLES_FROM_CONTROLLER"; 177 178 @NonNull 179 private final Context mContext; 180 181 @NonNull 182 private final IRoleManager mService; 183 184 @GuardedBy("mListenersLock") 185 @NonNull 186 private final SparseArray<ArrayMap<OnRoleHoldersChangedListener, 187 OnRoleHoldersChangedListenerDelegate>> mListeners = new SparseArray<>(); 188 @NonNull 189 private final Object mListenersLock = new Object(); 190 191 @GuardedBy("mRoleControllerManagerLock") 192 @Nullable 193 private RoleControllerManager mRoleControllerManager; 194 private final Object mRoleControllerManagerLock = new Object(); 195 196 /** 197 * Create a new instance of this class. 198 * 199 * @param context the {@link Context} 200 * @param service the {@link IRoleManager} service 201 * 202 * @hide 203 */ RoleManager(@onNull Context context, @NonNull IRoleManager service)204 public RoleManager(@NonNull Context context, @NonNull IRoleManager service) { 205 mContext = context; 206 mService = service; 207 } 208 209 /** 210 * Returns an {@code Intent} suitable for passing to 211 * {@link android.app.Activity#startActivityForResult(Intent, int)} which prompts the user to 212 * grant a role to this application. 213 * <p> 214 * If the role is granted, the {@code resultCode} will be 215 * {@link android.app.Activity#RESULT_OK}, otherwise it will be 216 * {@link android.app.Activity#RESULT_CANCELED}. 217 * 218 * @param roleName the name of requested role 219 * 220 * @return the {@code Intent} to prompt user to grant the role 221 */ 222 @NonNull createRequestRoleIntent(@onNull String roleName)223 public Intent createRequestRoleIntent(@NonNull String roleName) { 224 Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty"); 225 Intent intent = new Intent(ACTION_REQUEST_ROLE); 226 intent.setPackage(mContext.getPackageManager().getPermissionControllerPackageName()); 227 intent.putExtra(Intent.EXTRA_ROLE_NAME, roleName); 228 return intent; 229 } 230 231 /** 232 * Check whether a role is available in the system. 233 * 234 * @param roleName the name of role to checking for 235 * 236 * @return whether the role is available in the system 237 */ isRoleAvailable(@onNull String roleName)238 public boolean isRoleAvailable(@NonNull String roleName) { 239 Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty"); 240 try { 241 return mService.isRoleAvailable(roleName); 242 } catch (RemoteException e) { 243 throw e.rethrowFromSystemServer(); 244 } 245 } 246 247 /** 248 * Check whether the calling application is holding a particular role. 249 * 250 * @param roleName the name of the role to check for 251 * 252 * @return whether the calling application is holding the role 253 */ isRoleHeld(@onNull String roleName)254 public boolean isRoleHeld(@NonNull String roleName) { 255 Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty"); 256 try { 257 return mService.isRoleHeld(roleName, mContext.getPackageName()); 258 } catch (RemoteException e) { 259 throw e.rethrowFromSystemServer(); 260 } 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}. 268 * 269 * @param roleName the name of the role to get the role holder for 270 * 271 * @return a list of package names of the role holders, or an empty list if none. 272 * 273 * @see #getRoleHoldersAsUser(String, UserHandle) 274 * 275 * @hide 276 */ 277 @NonNull 278 @RequiresPermission(Manifest.permission.MANAGE_ROLE_HOLDERS) 279 @SystemApi getRoleHolders(@onNull String roleName)280 public List<String> getRoleHolders(@NonNull String roleName) { 281 return getRoleHoldersAsUser(roleName, Process.myUserHandle()); 282 } 283 284 /** 285 * Get package names of the applications holding the role. 286 * <p> 287 * <strong>Note:</strong> Using this API requires holding 288 * {@code android.permission.MANAGE_ROLE_HOLDERS} and if the user id is not the current user 289 * {@code android.permission.INTERACT_ACROSS_USERS_FULL}. 290 * 291 * @param roleName the name of the role to get the role holder for 292 * @param user the user to get the role holder for 293 * 294 * @return a list of package names of the role holders, or an empty list if none. 295 * 296 * @see #addRoleHolderAsUser(String, String, int, UserHandle, Executor, Consumer) 297 * @see #removeRoleHolderAsUser(String, String, int, UserHandle, Executor, Consumer) 298 * @see #clearRoleHoldersAsUser(String, int, UserHandle, Executor, Consumer) 299 * 300 * @hide 301 */ 302 @NonNull 303 @RequiresPermission(Manifest.permission.MANAGE_ROLE_HOLDERS) 304 @SystemApi getRoleHoldersAsUser(@onNull String roleName, @NonNull UserHandle user)305 public List<String> getRoleHoldersAsUser(@NonNull String roleName, @NonNull UserHandle user) { 306 Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty"); 307 Objects.requireNonNull(user, "user cannot be null"); 308 try { 309 return mService.getRoleHoldersAsUser(roleName, user.getIdentifier()); 310 } catch (RemoteException e) { 311 throw e.rethrowFromSystemServer(); 312 } 313 } 314 315 /** 316 * Add a specific application to the holders of a role. If the role is exclusive, the previous 317 * holder will be replaced. 318 * <p> 319 * <strong>Note:</strong> Using this API requires holding 320 * {@code android.permission.MANAGE_ROLE_HOLDERS} and if the user id is not the current user 321 * {@code android.permission.INTERACT_ACROSS_USERS_FULL}. 322 * 323 * @param roleName the name of the role to add the role holder for 324 * @param packageName the package name of the application to add to the role holders 325 * @param flags optional behavior flags 326 * @param user the user to add the role holder for 327 * @param executor the {@code Executor} to run the callback on. 328 * @param callback the callback for whether this call is successful 329 * 330 * @see #getRoleHoldersAsUser(String, UserHandle) 331 * @see #removeRoleHolderAsUser(String, String, int, UserHandle, Executor, Consumer) 332 * @see #clearRoleHoldersAsUser(String, int, UserHandle, Executor, Consumer) 333 * 334 * @hide 335 */ 336 @RequiresPermission(Manifest.permission.MANAGE_ROLE_HOLDERS) 337 @SystemApi addRoleHolderAsUser(@onNull String roleName, @NonNull String packageName, @ManageHoldersFlags int flags, @NonNull UserHandle user, @CallbackExecutor @NonNull Executor executor, @NonNull Consumer<Boolean> callback)338 public void addRoleHolderAsUser(@NonNull String roleName, @NonNull String packageName, 339 @ManageHoldersFlags int flags, @NonNull UserHandle user, 340 @CallbackExecutor @NonNull Executor executor, @NonNull Consumer<Boolean> callback) { 341 Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty"); 342 Preconditions.checkStringNotEmpty(packageName, "packageName cannot be null or empty"); 343 Objects.requireNonNull(user, "user cannot be null"); 344 Objects.requireNonNull(executor, "executor cannot be null"); 345 Objects.requireNonNull(callback, "callback cannot be null"); 346 try { 347 mService.addRoleHolderAsUser(roleName, packageName, flags, user.getIdentifier(), 348 createRemoteCallback(executor, callback)); 349 } catch (RemoteException e) { 350 throw e.rethrowFromSystemServer(); 351 } 352 } 353 354 /** 355 * Remove a specific application from the holders of a role. 356 * <p> 357 * <strong>Note:</strong> Using this API requires holding 358 * {@code android.permission.MANAGE_ROLE_HOLDERS} and if the user id is not the current user 359 * {@code android.permission.INTERACT_ACROSS_USERS_FULL}. 360 * 361 * @param roleName the name of the role to remove the role holder for 362 * @param packageName the package name of the application to remove from the role holders 363 * @param flags optional behavior flags 364 * @param user the user to remove the role holder for 365 * @param executor the {@code Executor} to run the callback on. 366 * @param callback the callback for whether this call is successful 367 * 368 * @see #getRoleHoldersAsUser(String, UserHandle) 369 * @see #addRoleHolderAsUser(String, String, int, UserHandle, Executor, Consumer) 370 * @see #clearRoleHoldersAsUser(String, int, UserHandle, Executor, Consumer) 371 * 372 * @hide 373 */ 374 @RequiresPermission(Manifest.permission.MANAGE_ROLE_HOLDERS) 375 @SystemApi removeRoleHolderAsUser(@onNull String roleName, @NonNull String packageName, @ManageHoldersFlags int flags, @NonNull UserHandle user, @CallbackExecutor @NonNull Executor executor, @NonNull Consumer<Boolean> callback)376 public void removeRoleHolderAsUser(@NonNull String roleName, @NonNull String packageName, 377 @ManageHoldersFlags int flags, @NonNull UserHandle user, 378 @CallbackExecutor @NonNull Executor executor, @NonNull Consumer<Boolean> callback) { 379 Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty"); 380 Preconditions.checkStringNotEmpty(packageName, "packageName cannot be null or empty"); 381 Objects.requireNonNull(user, "user cannot be null"); 382 Objects.requireNonNull(executor, "executor cannot be null"); 383 Objects.requireNonNull(callback, "callback cannot be null"); 384 try { 385 mService.removeRoleHolderAsUser(roleName, packageName, flags, user.getIdentifier(), 386 createRemoteCallback(executor, callback)); 387 } catch (RemoteException e) { 388 throw e.rethrowFromSystemServer(); 389 } 390 } 391 392 /** 393 * Remove all holders of a role. 394 * <p> 395 * <strong>Note:</strong> Using this API requires holding 396 * {@code android.permission.MANAGE_ROLE_HOLDERS} and if the user id is not the current user 397 * {@code android.permission.INTERACT_ACROSS_USERS_FULL}. 398 * 399 * @param roleName the name of the role to remove role holders for 400 * @param flags optional behavior flags 401 * @param user the user to remove role holders for 402 * @param executor the {@code Executor} to run the callback on. 403 * @param callback the callback for whether this call is successful 404 * 405 * @see #getRoleHoldersAsUser(String, UserHandle) 406 * @see #addRoleHolderAsUser(String, String, int, UserHandle, Executor, Consumer) 407 * @see #removeRoleHolderAsUser(String, String, int, UserHandle, Executor, Consumer) 408 * 409 * @hide 410 */ 411 @RequiresPermission(Manifest.permission.MANAGE_ROLE_HOLDERS) 412 @SystemApi clearRoleHoldersAsUser(@onNull String roleName, @ManageHoldersFlags int flags, @NonNull UserHandle user, @CallbackExecutor @NonNull Executor executor, @NonNull Consumer<Boolean> callback)413 public void clearRoleHoldersAsUser(@NonNull String roleName, @ManageHoldersFlags int flags, 414 @NonNull UserHandle user, @CallbackExecutor @NonNull Executor executor, 415 @NonNull Consumer<Boolean> callback) { 416 Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty"); 417 Objects.requireNonNull(user, "user cannot be null"); 418 Objects.requireNonNull(executor, "executor cannot be null"); 419 Objects.requireNonNull(callback, "callback cannot be null"); 420 try { 421 mService.clearRoleHoldersAsUser(roleName, flags, user.getIdentifier(), 422 createRemoteCallback(executor, callback)); 423 } catch (RemoteException e) { 424 throw e.rethrowFromSystemServer(); 425 } 426 } 427 428 @NonNull createRemoteCallback(@onNull Executor executor, @NonNull Consumer<Boolean> callback)429 private static RemoteCallback createRemoteCallback(@NonNull Executor executor, 430 @NonNull Consumer<Boolean> callback) { 431 return new RemoteCallback(result -> executor.execute(() -> { 432 boolean successful = result != null; 433 final long token = Binder.clearCallingIdentity(); 434 try { 435 callback.accept(successful); 436 } finally { 437 Binder.restoreCallingIdentity(token); 438 } 439 })); 440 } 441 442 /** 443 * Add a listener to observe role holder changes 444 * <p> 445 * <strong>Note:</strong> Using this API requires holding 446 * {@code android.permission.OBSERVE_ROLE_HOLDERS} and if the user id is not the current user 447 * {@code android.permission.INTERACT_ACROSS_USERS_FULL}. 448 * 449 * @param executor the {@code Executor} to call the listener on. 450 * @param listener the listener to be added 451 * @param user the user to add the listener for 452 * 453 * @see #removeOnRoleHoldersChangedListenerAsUser(OnRoleHoldersChangedListener, UserHandle) 454 * 455 * @hide 456 */ 457 @RequiresPermission(Manifest.permission.OBSERVE_ROLE_HOLDERS) 458 @SuppressLint("SamShouldBeLast") // TODO(b/190240500): remove this 459 @SystemApi addOnRoleHoldersChangedListenerAsUser(@allbackExecutor @onNull Executor executor, @NonNull OnRoleHoldersChangedListener listener, @NonNull UserHandle user)460 public void addOnRoleHoldersChangedListenerAsUser(@CallbackExecutor @NonNull Executor executor, 461 @NonNull OnRoleHoldersChangedListener listener, @NonNull UserHandle user) { 462 Objects.requireNonNull(executor, "executor cannot be null"); 463 Objects.requireNonNull(listener, "listener cannot be null"); 464 Objects.requireNonNull(user, "user cannot be null"); 465 int userId = user.getIdentifier(); 466 synchronized (mListenersLock) { 467 ArrayMap<OnRoleHoldersChangedListener, OnRoleHoldersChangedListenerDelegate> listeners = 468 mListeners.get(userId); 469 if (listeners == null) { 470 listeners = new ArrayMap<>(); 471 mListeners.put(userId, listeners); 472 } else { 473 if (listeners.containsKey(listener)) { 474 return; 475 } 476 } 477 OnRoleHoldersChangedListenerDelegate listenerDelegate = 478 new OnRoleHoldersChangedListenerDelegate(executor, listener); 479 try { 480 mService.addOnRoleHoldersChangedListenerAsUser(listenerDelegate, userId); 481 } catch (RemoteException e) { 482 throw e.rethrowFromSystemServer(); 483 } 484 listeners.put(listener, listenerDelegate); 485 } 486 } 487 488 /** 489 * Remove a listener observing role holder changes 490 * <p> 491 * <strong>Note:</strong> Using this API requires holding 492 * {@code android.permission.OBSERVE_ROLE_HOLDERS} and if the user id is not the current user 493 * {@code android.permission.INTERACT_ACROSS_USERS_FULL}. 494 * 495 * @param listener the listener to be removed 496 * @param user the user to remove the listener for 497 * 498 * @see #addOnRoleHoldersChangedListenerAsUser(Executor, OnRoleHoldersChangedListener, 499 * UserHandle) 500 * 501 * @hide 502 */ 503 @RequiresPermission(Manifest.permission.OBSERVE_ROLE_HOLDERS) 504 @SuppressLint("SamShouldBeLast") // TODO(b/190240500): remove this 505 @SystemApi removeOnRoleHoldersChangedListenerAsUser( @onNull OnRoleHoldersChangedListener listener, @NonNull UserHandle user)506 public void removeOnRoleHoldersChangedListenerAsUser( 507 @NonNull OnRoleHoldersChangedListener listener, @NonNull UserHandle user) { 508 Objects.requireNonNull(listener, "listener cannot be null"); 509 Objects.requireNonNull(user, "user cannot be null"); 510 int userId = user.getIdentifier(); 511 synchronized (mListenersLock) { 512 ArrayMap<OnRoleHoldersChangedListener, OnRoleHoldersChangedListenerDelegate> listeners = 513 mListeners.get(userId); 514 if (listeners == null) { 515 return; 516 } 517 OnRoleHoldersChangedListenerDelegate listenerDelegate = listeners.get(listener); 518 if (listenerDelegate == null) { 519 return; 520 } 521 try { 522 mService.removeOnRoleHoldersChangedListenerAsUser(listenerDelegate, 523 user.getIdentifier()); 524 } catch (RemoteException e) { 525 throw e.rethrowFromSystemServer(); 526 } 527 listeners.remove(listener); 528 if (listeners.isEmpty()) { 529 mListeners.remove(userId); 530 } 531 } 532 } 533 534 /** 535 * Check whether role qualifications should be bypassed. 536 * <p> 537 * Only the shell is allowed to do this, the qualification for the shell role itself cannot be 538 * bypassed, and each role needs to explicitly allow bypassing qualification in its definition. 539 * The bypass state will not be persisted across reboot. 540 * 541 * @return whether role qualification should be bypassed 542 * 543 * @hide 544 */ 545 @MinSdk(Build.VERSION_CODES.S) 546 @RequiresPermission(Manifest.permission.MANAGE_ROLE_HOLDERS) 547 @SystemApi isBypassingRoleQualification()548 public boolean isBypassingRoleQualification() { 549 try { 550 return mService.isBypassingRoleQualification(); 551 } catch (RemoteException e) { 552 throw e.rethrowFromSystemServer(); 553 } 554 } 555 556 /** 557 * Set whether role qualifications should be bypassed. 558 * <p> 559 * Only the shell is allowed to do this, the qualification for the shell role itself cannot be 560 * bypassed, and each role needs to explicitly allow bypassing qualification in its definition. 561 * The bypass state will not be persisted across reboot. 562 * 563 * @param bypassRoleQualification whether role qualification should be bypassed 564 * 565 * @hide 566 */ 567 @MinSdk(Build.VERSION_CODES.S) 568 @RequiresPermission(Manifest.permission.BYPASS_ROLE_QUALIFICATION) 569 @SystemApi setBypassingRoleQualification(boolean bypassRoleQualification)570 public void setBypassingRoleQualification(boolean bypassRoleQualification) { 571 try { 572 mService.setBypassingRoleQualification(bypassRoleQualification); 573 } catch (RemoteException e) { 574 throw e.rethrowFromSystemServer(); 575 } 576 } 577 578 /** 579 * Set the names of all the available roles. Should only be called from 580 * {@link android.app.role.RoleControllerService}. 581 * <p> 582 * <strong>Note:</strong> Using this API requires holding 583 * {@link #PERMISSION_MANAGE_ROLES_FROM_CONTROLLER}. 584 * 585 * @param roleNames the names of all the available roles 586 * 587 * @deprecated This is only usable by the role controller service, which is an internal 588 * implementation detail inside role. 589 * 590 * @hide 591 */ 592 @Deprecated 593 @RequiresPermission(PERMISSION_MANAGE_ROLES_FROM_CONTROLLER) 594 @SystemApi setRoleNamesFromController(@onNull List<String> roleNames)595 public void setRoleNamesFromController(@NonNull List<String> roleNames) { 596 Objects.requireNonNull(roleNames, "roleNames cannot be null"); 597 try { 598 mService.setRoleNamesFromController(roleNames); 599 } catch (RemoteException e) { 600 throw e.rethrowFromSystemServer(); 601 } 602 } 603 604 /** 605 * Add a specific application to the holders of a role, only modifying records inside 606 * {@link RoleManager}. Should only be called from 607 * {@link android.app.role.RoleControllerService}. 608 * <p> 609 * <strong>Note:</strong> Using this API requires holding 610 * {@link #PERMISSION_MANAGE_ROLES_FROM_CONTROLLER}. 611 * 612 * @param roleName the name of the role to add the role holder for 613 * @param packageName the package name of the application to add to the role holders 614 * 615 * @return whether the operation was successful, and will also be {@code true} if a matching 616 * role holder is already found. 617 * 618 * @see #getRoleHolders(String) 619 * @see #removeRoleHolderFromController(String, String) 620 * 621 * @deprecated This is only usable by the role controller service, which is an internal 622 * implementation detail inside role. 623 * 624 * @hide 625 */ 626 @Deprecated 627 @RequiresPermission(PERMISSION_MANAGE_ROLES_FROM_CONTROLLER) 628 @SystemApi addRoleHolderFromController(@onNull String roleName, @NonNull String packageName)629 public boolean addRoleHolderFromController(@NonNull String roleName, 630 @NonNull String packageName) { 631 Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty"); 632 Preconditions.checkStringNotEmpty(packageName, "packageName cannot be null or empty"); 633 try { 634 return mService.addRoleHolderFromController(roleName, packageName); 635 } catch (RemoteException e) { 636 throw e.rethrowFromSystemServer(); 637 } 638 } 639 640 /** 641 * Remove a specific application from the holders of a role, only modifying records inside 642 * {@link RoleManager}. Should only be called from 643 * {@link android.app.role.RoleControllerService}. 644 * <p> 645 * <strong>Note:</strong> Using this API requires holding 646 * {@link #PERMISSION_MANAGE_ROLES_FROM_CONTROLLER}. 647 * 648 * @param roleName the name of the role to remove the role holder for 649 * @param packageName the package name of the application to remove from the role holders 650 * 651 * @return whether the operation was successful, and will also be {@code true} if no matching 652 * role holder was found to remove. 653 * 654 * @see #getRoleHolders(String) 655 * @see #addRoleHolderFromController(String, String) 656 * 657 * @deprecated This is only usable by the role controller service, which is an internal 658 * implementation detail inside role. 659 * 660 * @hide 661 */ 662 @Deprecated 663 @RequiresPermission(PERMISSION_MANAGE_ROLES_FROM_CONTROLLER) 664 @SystemApi removeRoleHolderFromController(@onNull String roleName, @NonNull String packageName)665 public boolean removeRoleHolderFromController(@NonNull String roleName, 666 @NonNull String packageName) { 667 Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty"); 668 Preconditions.checkStringNotEmpty(packageName, "packageName cannot be null or empty"); 669 try { 670 return mService.removeRoleHolderFromController(roleName, packageName); 671 } catch (RemoteException e) { 672 throw e.rethrowFromSystemServer(); 673 } 674 } 675 676 /** 677 * Returns the list of all roles that the given package is currently holding 678 * 679 * @param packageName the package name 680 * @return the list of role names 681 * 682 * @deprecated This is only usable by the role controller service, which is an internal 683 * implementation detail inside role. 684 * 685 * @hide 686 */ 687 @Deprecated 688 @NonNull 689 @RequiresPermission(PERMISSION_MANAGE_ROLES_FROM_CONTROLLER) 690 @SystemApi getHeldRolesFromController(@onNull String packageName)691 public List<String> getHeldRolesFromController(@NonNull String packageName) { 692 Preconditions.checkStringNotEmpty(packageName, "packageName cannot be null or empty"); 693 try { 694 return mService.getHeldRolesFromController(packageName); 695 } catch (RemoteException e) { 696 throw e.rethrowFromSystemServer(); 697 } 698 } 699 700 /** 701 * Get the role holder of {@link #ROLE_BROWSER} without requiring 702 * {@link Manifest.permission#OBSERVE_ROLE_HOLDERS}, as in 703 * {@link android.content.pm.PackageManager#getDefaultBrowserPackageNameAsUser(int)} 704 * 705 * @param userId the user ID 706 * @return the package name of the default browser, or {@code null} if none 707 * 708 * @hide 709 */ 710 @MinSdk(Build.VERSION_CODES.S) 711 @Nullable 712 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) getBrowserRoleHolder(@serIdInt int userId)713 public String getBrowserRoleHolder(@UserIdInt int userId) { 714 try { 715 return mService.getBrowserRoleHolder(userId); 716 } catch (RemoteException e) { 717 throw e.rethrowFromSystemServer(); 718 } 719 } 720 721 /** 722 * Set the role holder of {@link #ROLE_BROWSER} requiring 723 * {@link Manifest.permission.SET_PREFERRED_APPLICATIONS} instead of 724 * {@link Manifest.permission#MANAGE_ROLE_HOLDERS}, as in 725 * {@link android.content.pm.PackageManager#setDefaultBrowserPackageNameAsUser(String, int)} 726 * 727 * @param packageName the package name of the default browser, or {@code null} if none 728 * @param userId the user ID 729 * @return whether the default browser was set successfully 730 * 731 * @hide 732 */ 733 @MinSdk(Build.VERSION_CODES.S) 734 @Nullable 735 @RequiresPermission(Manifest.permission.SET_PREFERRED_APPLICATIONS) 736 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) setBrowserRoleHolder(@ullable String packageName, @UserIdInt int userId)737 public boolean setBrowserRoleHolder(@Nullable String packageName, @UserIdInt int userId) { 738 try { 739 return mService.setBrowserRoleHolder(packageName, userId); 740 } catch (RemoteException e) { 741 throw e.rethrowFromSystemServer(); 742 } 743 } 744 745 /** 746 * Allows getting the role holder for {@link #ROLE_SMS} without requiring 747 * {@link Manifest.permission#OBSERVE_ROLE_HOLDERS}, as in 748 * {@link android.provider.Telephony.Sms#getDefaultSmsPackage(Context)}. 749 * 750 * @param userId the user ID to get the default SMS package for 751 * @return the package name of the default SMS app, or {@code null} if none 752 * 753 * @hide 754 */ 755 @MinSdk(Build.VERSION_CODES.S) 756 @Nullable 757 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) getSmsRoleHolder(@serIdInt int userId)758 public String getSmsRoleHolder(@UserIdInt int userId) { 759 try { 760 return mService.getSmsRoleHolder(userId); 761 } catch (RemoteException e) { 762 throw e.rethrowFromSystemServer(); 763 } 764 } 765 766 /** 767 * Check whether a role should be visible to user. 768 * 769 * @param roleName name of the role to check for 770 * @param executor the executor to execute callback on 771 * @param callback the callback to receive whether the role should be visible to user 772 * 773 * @hide 774 */ 775 @MinSdk(Build.VERSION_CODES.S) 776 @RequiresPermission(Manifest.permission.MANAGE_ROLE_HOLDERS) 777 @SystemApi isRoleVisible(@onNull String roleName, @NonNull @CallbackExecutor Executor executor, @NonNull Consumer<Boolean> callback)778 public void isRoleVisible(@NonNull String roleName, 779 @NonNull @CallbackExecutor Executor executor, @NonNull Consumer<Boolean> callback) { 780 getRoleControllerManager().isRoleVisible(roleName, executor, callback); 781 } 782 783 /** 784 * Check whether an application is visible for a role. 785 * 786 * While an application can be qualified for a role, it can still stay hidden from user (thus 787 * not visible). If an application is visible for a role, we may show things related to the role 788 * for it, e.g. showing an entry pointing to the role settings in its application info page. 789 * 790 * @param roleName the name of the role to check for 791 * @param packageName the package name of the application to check for 792 * @param executor the executor to execute callback on 793 * @param callback the callback to receive whether the application is visible for the role 794 * 795 * @hide 796 */ 797 @MinSdk(Build.VERSION_CODES.S) 798 @RequiresPermission(Manifest.permission.MANAGE_ROLE_HOLDERS) 799 @SystemApi isApplicationVisibleForRole(@onNull String roleName, @NonNull String packageName, @NonNull @CallbackExecutor Executor executor, @NonNull Consumer<Boolean> callback)800 public void isApplicationVisibleForRole(@NonNull String roleName, @NonNull String packageName, 801 @NonNull @CallbackExecutor Executor executor, @NonNull Consumer<Boolean> callback) { 802 getRoleControllerManager().isApplicationVisibleForRole(roleName, packageName, executor, 803 callback); 804 } 805 806 @NonNull getRoleControllerManager()807 private RoleControllerManager getRoleControllerManager() { 808 synchronized (mRoleControllerManagerLock) { 809 if (mRoleControllerManager == null) { 810 mRoleControllerManager = new RoleControllerManager(mContext); 811 } 812 return mRoleControllerManager; 813 } 814 } 815 816 private static class OnRoleHoldersChangedListenerDelegate 817 extends IOnRoleHoldersChangedListener.Stub { 818 819 @NonNull 820 private final Executor mExecutor; 821 @NonNull 822 private final OnRoleHoldersChangedListener mListener; 823 OnRoleHoldersChangedListenerDelegate(@onNull Executor executor, @NonNull OnRoleHoldersChangedListener listener)824 OnRoleHoldersChangedListenerDelegate(@NonNull Executor executor, 825 @NonNull OnRoleHoldersChangedListener listener) { 826 mExecutor = executor; 827 mListener = listener; 828 } 829 830 @Override onRoleHoldersChanged(@onNull String roleName, @UserIdInt int userId)831 public void onRoleHoldersChanged(@NonNull String roleName, @UserIdInt int userId) { 832 final long token = Binder.clearCallingIdentity(); 833 try { 834 mExecutor.execute(() -> 835 mListener.onRoleHoldersChanged(roleName, UserHandle.of(userId))); 836 } finally { 837 Binder.restoreCallingIdentity(token); 838 } 839 } 840 } 841 } 842