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