• 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 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