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