• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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