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.SystemApi;
26 import android.annotation.SystemService;
27 import android.annotation.TestApi;
28 import android.annotation.UserIdInt;
29 import android.content.Context;
30 import android.content.Intent;
31 import android.os.Binder;
32 import android.os.Process;
33 import android.os.RemoteCallback;
34 import android.os.RemoteException;
35 import android.os.ServiceManager;
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.internal.util.function.pooled.PooledLambda;
43 
44 import java.util.List;
45 import java.util.concurrent.Executor;
46 import java.util.function.Consumer;
47 
48 /**
49  * This class provides information about and manages roles.
50  * <p>
51  * A role is a unique name within the system associated with certain privileges. The list of
52  * available roles might change with a system app update, so apps should not make assumption about
53  * the availability of roles. Instead, they should always query if the role is available using
54  * {@link #isRoleAvailable(String)} before trying to do anything with it. Some predefined role names
55  * are available as constants in this class, and a list of possibly available roles can be found in
56  * the <a href="{@docRoot}reference/androidx/core/role/package-summary.html">AndroidX Role
57  * library</a>.
58  * <p>
59  * There can be multiple applications qualifying for a role, but only a subset of them can become
60  * role holders. To qualify for a role, an application must meet certain requirements, including
61  * defining certain components in its manifest. These requirements can be found in the AndroidX
62  * Libraries. Then the application will need user consent to become a role holder, which can be
63  * requested using {@link android.app.Activity#startActivityForResult(Intent, int)} with the
64  * {@code Intent} obtained from {@link #createRequestRoleIntent(String)}.
65  * <p>
66  * Upon becoming a role holder, the application may be granted certain privileges that are role
67  * specific. When the application loses its role, these privileges will also be revoked.
68  */
69 @SystemService(Context.ROLE_SERVICE)
70 public final class RoleManager {
71 
72     private static final String LOG_TAG = RoleManager.class.getSimpleName();
73 
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      * @hide
134      */
135     @IntDef(flag = true, value = { MANAGE_HOLDERS_FLAG_DONT_KILL_APP })
136     public @interface ManageHoldersFlags {}
137 
138     /**
139      * Flag parameter for {@link #addRoleHolderAsUser}, {@link #removeRoleHolderAsUser} and
140      * {@link #clearRoleHoldersAsUser} to indicate that apps should not be killed when changing
141      * their role holder status.
142      *
143      * @hide
144      */
145     @SystemApi
146     @TestApi
147     public static final int MANAGE_HOLDERS_FLAG_DONT_KILL_APP = 1;
148 
149     /**
150      * The action used to request user approval of a role for an application.
151      *
152      * @hide
153      */
154     public static final String ACTION_REQUEST_ROLE = "android.app.role.action.REQUEST_ROLE";
155 
156     /**
157      * The permission required to manage records of role holders in {@link RoleManager} directly.
158      *
159      * @hide
160      */
161     public static final String PERMISSION_MANAGE_ROLES_FROM_CONTROLLER =
162             "com.android.permissioncontroller.permission.MANAGE_ROLES_FROM_CONTROLLER";
163 
164     @NonNull
165     private final Context mContext;
166 
167     @NonNull
168     private final IRoleManager mService;
169 
170     @GuardedBy("mListenersLock")
171     @NonNull
172     private final SparseArray<ArrayMap<OnRoleHoldersChangedListener,
173             OnRoleHoldersChangedListenerDelegate>> mListeners = new SparseArray<>();
174     @NonNull
175     private final Object mListenersLock = new Object();
176 
177     /**
178      * @hide
179      */
RoleManager(@onNull Context context)180     public RoleManager(@NonNull Context context) throws ServiceManager.ServiceNotFoundException {
181         mContext = context;
182         mService = IRoleManager.Stub.asInterface(ServiceManager.getServiceOrThrow(
183                 Context.ROLE_SERVICE));
184     }
185 
186     /**
187      * Returns an {@code Intent} suitable for passing to
188      * {@link android.app.Activity#startActivityForResult(Intent, int)} which prompts the user to
189      * grant a role to this application.
190      * <p>
191      * If the role is granted, the {@code resultCode} will be
192      * {@link android.app.Activity#RESULT_OK}, otherwise it will be
193      * {@link android.app.Activity#RESULT_CANCELED}.
194      *
195      * @param roleName the name of requested role
196      *
197      * @return the {@code Intent} to prompt user to grant the role
198      */
199     @NonNull
createRequestRoleIntent(@onNull String roleName)200     public Intent createRequestRoleIntent(@NonNull String roleName) {
201         Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
202         Intent intent = new Intent(ACTION_REQUEST_ROLE);
203         intent.setPackage(mContext.getPackageManager().getPermissionControllerPackageName());
204         intent.putExtra(Intent.EXTRA_ROLE_NAME, roleName);
205         return intent;
206     }
207 
208     /**
209      * Check whether a role is available in the system.
210      *
211      * @param roleName the name of role to checking for
212      *
213      * @return whether the role is available in the system
214      */
isRoleAvailable(@onNull String roleName)215     public boolean isRoleAvailable(@NonNull String roleName) {
216         Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
217         try {
218             return mService.isRoleAvailable(roleName);
219         } catch (RemoteException e) {
220             throw e.rethrowFromSystemServer();
221         }
222     }
223 
224     /**
225      * Check whether the calling application is holding a particular role.
226      *
227      * @param roleName the name of the role to check for
228      *
229      * @return whether the calling application is holding the role
230      */
isRoleHeld(@onNull String roleName)231     public boolean isRoleHeld(@NonNull String roleName) {
232         Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
233         try {
234             return mService.isRoleHeld(roleName, mContext.getPackageName());
235         } catch (RemoteException e) {
236             throw e.rethrowFromSystemServer();
237         }
238     }
239 
240     /**
241      * Get package names of the applications holding the role.
242      * <p>
243      * <strong>Note:</strong> Using this API requires holding
244      * {@code android.permission.MANAGE_ROLE_HOLDERS}.
245      *
246      * @param roleName the name of the role to get the role holder for
247      *
248      * @return a list of package names of the role holders, or an empty list if none.
249      *
250      * @see #getRoleHoldersAsUser(String, UserHandle)
251      *
252      * @hide
253      */
254     @NonNull
255     @RequiresPermission(Manifest.permission.MANAGE_ROLE_HOLDERS)
256     @SystemApi
257     @TestApi
getRoleHolders(@onNull String roleName)258     public List<String> getRoleHolders(@NonNull String roleName) {
259         return getRoleHoldersAsUser(roleName, Process.myUserHandle());
260     }
261 
262     /**
263      * Get package names of the applications holding the role.
264      * <p>
265      * <strong>Note:</strong> Using this API requires holding
266      * {@code android.permission.MANAGE_ROLE_HOLDERS} and if the user id is not the current user
267      * {@code android.permission.INTERACT_ACROSS_USERS_FULL}.
268      *
269      * @param roleName the name of the role to get the role holder for
270      * @param user the user to get the role holder for
271      *
272      * @return a list of package names of the role holders, or an empty list if none.
273      *
274      * @see #addRoleHolderAsUser(String, String, int, UserHandle, Executor, Consumer)
275      * @see #removeRoleHolderAsUser(String, String, int, UserHandle, Executor, Consumer)
276      * @see #clearRoleHoldersAsUser(String, int, UserHandle, Executor, Consumer)
277      *
278      * @hide
279      */
280     @NonNull
281     @RequiresPermission(Manifest.permission.MANAGE_ROLE_HOLDERS)
282     @SystemApi
283     @TestApi
getRoleHoldersAsUser(@onNull String roleName, @NonNull UserHandle user)284     public List<String> getRoleHoldersAsUser(@NonNull String roleName, @NonNull UserHandle user) {
285         Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
286         Preconditions.checkNotNull(user, "user cannot be null");
287         try {
288             return mService.getRoleHoldersAsUser(roleName, user.getIdentifier());
289         } catch (RemoteException e) {
290             throw e.rethrowFromSystemServer();
291         }
292     }
293 
294     /**
295      * Add a specific application to the holders of a role. If the role is exclusive, the previous
296      * holder will be replaced.
297      * <p>
298      * <strong>Note:</strong> Using this API requires holding
299      * {@code android.permission.MANAGE_ROLE_HOLDERS} and if the user id is not the current user
300      * {@code android.permission.INTERACT_ACROSS_USERS_FULL}.
301      *
302      * @param roleName the name of the role to add the role holder for
303      * @param packageName the package name of the application to add to the role holders
304      * @param flags optional behavior flags
305      * @param user the user to add the role holder for
306      * @param executor the {@code Executor} to run the callback on.
307      * @param callback the callback for whether this call is successful
308      *
309      * @see #getRoleHoldersAsUser(String, UserHandle)
310      * @see #removeRoleHolderAsUser(String, String, int, UserHandle, Executor, Consumer)
311      * @see #clearRoleHoldersAsUser(String, int, UserHandle, Executor, Consumer)
312      *
313      * @hide
314      */
315     @RequiresPermission(Manifest.permission.MANAGE_ROLE_HOLDERS)
316     @SystemApi
317     @TestApi
addRoleHolderAsUser(@onNull String roleName, @NonNull String packageName, @ManageHoldersFlags int flags, @NonNull UserHandle user, @CallbackExecutor @NonNull Executor executor, @NonNull Consumer<Boolean> callback)318     public void addRoleHolderAsUser(@NonNull String roleName, @NonNull String packageName,
319             @ManageHoldersFlags int flags, @NonNull UserHandle user,
320             @CallbackExecutor @NonNull Executor executor, @NonNull Consumer<Boolean> callback) {
321         Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
322         Preconditions.checkStringNotEmpty(packageName, "packageName cannot be null or empty");
323         Preconditions.checkNotNull(user, "user cannot be null");
324         Preconditions.checkNotNull(executor, "executor cannot be null");
325         Preconditions.checkNotNull(callback, "callback cannot be null");
326         try {
327             mService.addRoleHolderAsUser(roleName, packageName, flags, user.getIdentifier(),
328                     createRemoteCallback(executor, callback));
329         } catch (RemoteException e) {
330             throw e.rethrowFromSystemServer();
331         }
332     }
333 
334     /**
335      * Remove a specific application from the holders of a role.
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 remove the role holder for
342      * @param packageName the package name of the application to remove from the role holders
343      * @param flags optional behavior flags
344      * @param user the user to remove 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 #addRoleHolderAsUser(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
356     @TestApi
removeRoleHolderAsUser(@onNull String roleName, @NonNull String packageName, @ManageHoldersFlags int flags, @NonNull UserHandle user, @CallbackExecutor @NonNull Executor executor, @NonNull Consumer<Boolean> callback)357     public void removeRoleHolderAsUser(@NonNull String roleName, @NonNull String packageName,
358             @ManageHoldersFlags int flags, @NonNull UserHandle user,
359             @CallbackExecutor @NonNull Executor executor, @NonNull Consumer<Boolean> callback) {
360         Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
361         Preconditions.checkStringNotEmpty(packageName, "packageName cannot be null or empty");
362         Preconditions.checkNotNull(user, "user cannot be null");
363         Preconditions.checkNotNull(executor, "executor cannot be null");
364         Preconditions.checkNotNull(callback, "callback cannot be null");
365         try {
366             mService.removeRoleHolderAsUser(roleName, packageName, flags, user.getIdentifier(),
367                     createRemoteCallback(executor, callback));
368         } catch (RemoteException e) {
369             throw e.rethrowFromSystemServer();
370         }
371     }
372 
373     /**
374      * Remove all holders of a role.
375      * <p>
376      * <strong>Note:</strong> Using this API requires holding
377      * {@code android.permission.MANAGE_ROLE_HOLDERS} and if the user id is not the current user
378      * {@code android.permission.INTERACT_ACROSS_USERS_FULL}.
379      *
380      * @param roleName the name of the role to remove role holders for
381      * @param flags optional behavior flags
382      * @param user the user to remove role holders 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 #removeRoleHolderAsUser(String, String, int, UserHandle, Executor, Consumer)
389      *
390      * @hide
391      */
392     @RequiresPermission(Manifest.permission.MANAGE_ROLE_HOLDERS)
393     @SystemApi
394     @TestApi
clearRoleHoldersAsUser(@onNull String roleName, @ManageHoldersFlags int flags, @NonNull UserHandle user, @CallbackExecutor @NonNull Executor executor, @NonNull Consumer<Boolean> callback)395     public void clearRoleHoldersAsUser(@NonNull String roleName, @ManageHoldersFlags int flags,
396             @NonNull UserHandle user, @CallbackExecutor @NonNull Executor executor,
397             @NonNull Consumer<Boolean> callback) {
398         Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
399         Preconditions.checkNotNull(user, "user cannot be null");
400         Preconditions.checkNotNull(executor, "executor cannot be null");
401         Preconditions.checkNotNull(callback, "callback cannot be null");
402         try {
403             mService.clearRoleHoldersAsUser(roleName, flags, user.getIdentifier(),
404                     createRemoteCallback(executor, callback));
405         } catch (RemoteException e) {
406             throw e.rethrowFromSystemServer();
407         }
408     }
409 
410     @NonNull
createRemoteCallback(@onNull Executor executor, @NonNull Consumer<Boolean> callback)411     private static RemoteCallback createRemoteCallback(@NonNull Executor executor,
412             @NonNull Consumer<Boolean> callback) {
413         return new RemoteCallback(result -> executor.execute(() -> {
414             boolean successful = result != null;
415             long token = Binder.clearCallingIdentity();
416             try {
417                 callback.accept(successful);
418             } finally {
419                 Binder.restoreCallingIdentity(token);
420             }
421         }));
422     }
423 
424     /**
425      * Add a listener to observe role holder changes
426      * <p>
427      * <strong>Note:</strong> Using this API requires holding
428      * {@code android.permission.OBSERVE_ROLE_HOLDERS} and if the user id is not the current user
429      * {@code android.permission.INTERACT_ACROSS_USERS_FULL}.
430      *
431      * @param executor the {@code Executor} to call the listener on.
432      * @param listener the listener to be added
433      * @param user the user to add the listener for
434      *
435      * @see #removeOnRoleHoldersChangedListenerAsUser(OnRoleHoldersChangedListener, UserHandle)
436      *
437      * @hide
438      */
439     @RequiresPermission(Manifest.permission.OBSERVE_ROLE_HOLDERS)
440     @SystemApi
441     @TestApi
addOnRoleHoldersChangedListenerAsUser(@allbackExecutor @onNull Executor executor, @NonNull OnRoleHoldersChangedListener listener, @NonNull UserHandle user)442     public void addOnRoleHoldersChangedListenerAsUser(@CallbackExecutor @NonNull Executor executor,
443             @NonNull OnRoleHoldersChangedListener listener, @NonNull UserHandle user) {
444         Preconditions.checkNotNull(executor, "executor cannot be null");
445         Preconditions.checkNotNull(listener, "listener cannot be null");
446         Preconditions.checkNotNull(user, "user cannot be null");
447         int userId = user.getIdentifier();
448         synchronized (mListenersLock) {
449             ArrayMap<OnRoleHoldersChangedListener, OnRoleHoldersChangedListenerDelegate> listeners =
450                     mListeners.get(userId);
451             if (listeners == null) {
452                 listeners = new ArrayMap<>();
453                 mListeners.put(userId, listeners);
454             } else {
455                 if (listeners.containsKey(listener)) {
456                     return;
457                 }
458             }
459             OnRoleHoldersChangedListenerDelegate listenerDelegate =
460                     new OnRoleHoldersChangedListenerDelegate(executor, listener);
461             try {
462                 mService.addOnRoleHoldersChangedListenerAsUser(listenerDelegate, userId);
463             } catch (RemoteException e) {
464                 throw e.rethrowFromSystemServer();
465             }
466             listeners.put(listener, listenerDelegate);
467         }
468     }
469 
470     /**
471      * Remove a listener observing role holder changes
472      * <p>
473      * <strong>Note:</strong> Using this API requires holding
474      * {@code android.permission.OBSERVE_ROLE_HOLDERS} and if the user id is not the current user
475      * {@code android.permission.INTERACT_ACROSS_USERS_FULL}.
476      *
477      * @param listener the listener to be removed
478      * @param user the user to remove the listener for
479      *
480      * @see #addOnRoleHoldersChangedListenerAsUser(Executor, OnRoleHoldersChangedListener,
481      *                                             UserHandle)
482      *
483      * @hide
484      */
485     @RequiresPermission(Manifest.permission.OBSERVE_ROLE_HOLDERS)
486     @SystemApi
487     @TestApi
removeOnRoleHoldersChangedListenerAsUser( @onNull OnRoleHoldersChangedListener listener, @NonNull UserHandle user)488     public void removeOnRoleHoldersChangedListenerAsUser(
489             @NonNull OnRoleHoldersChangedListener listener, @NonNull UserHandle user) {
490         Preconditions.checkNotNull(listener, "listener cannot be null");
491         Preconditions.checkNotNull(user, "user cannot be null");
492         int userId = user.getIdentifier();
493         synchronized (mListenersLock) {
494             ArrayMap<OnRoleHoldersChangedListener, OnRoleHoldersChangedListenerDelegate> listeners =
495                     mListeners.get(userId);
496             if (listeners == null) {
497                 return;
498             }
499             OnRoleHoldersChangedListenerDelegate listenerDelegate = listeners.get(listener);
500             if (listenerDelegate == null) {
501                 return;
502             }
503             try {
504                 mService.removeOnRoleHoldersChangedListenerAsUser(listenerDelegate,
505                         user.getIdentifier());
506             } catch (RemoteException e) {
507                 throw e.rethrowFromSystemServer();
508             }
509             listeners.remove(listener);
510             if (listeners.isEmpty()) {
511                 mListeners.remove(userId);
512             }
513         }
514     }
515 
516     /**
517      * Set the names of all the available roles. Should only be called from
518      * {@link android.app.role.RoleControllerService}.
519      * <p>
520      * <strong>Note:</strong> Using this API requires holding
521      * {@link #PERMISSION_MANAGE_ROLES_FROM_CONTROLLER}.
522      *
523      * @param roleNames the names of all the available roles
524      *
525      * @hide
526      */
527     @RequiresPermission(PERMISSION_MANAGE_ROLES_FROM_CONTROLLER)
528     @SystemApi
529     @TestApi
setRoleNamesFromController(@onNull List<String> roleNames)530     public void setRoleNamesFromController(@NonNull List<String> roleNames) {
531         Preconditions.checkNotNull(roleNames, "roleNames cannot be null");
532         try {
533             mService.setRoleNamesFromController(roleNames);
534         } catch (RemoteException e) {
535             throw e.rethrowFromSystemServer();
536         }
537     }
538 
539     /**
540      * Add a specific application to the holders of a role, only modifying records inside
541      * {@link RoleManager}. Should only be called from
542      * {@link android.app.role.RoleControllerService}.
543      * <p>
544      * <strong>Note:</strong> Using this API requires holding
545      * {@link #PERMISSION_MANAGE_ROLES_FROM_CONTROLLER}.
546      *
547      * @param roleName the name of the role to add the role holder for
548      * @param packageName the package name of the application to add to the role holders
549      *
550      * @return whether the operation was successful, and will also be {@code true} if a matching
551      *         role holder is already found.
552      *
553      * @see #getRoleHolders(String)
554      * @see #removeRoleHolderFromController(String, String)
555      *
556      * @hide
557      */
558     @RequiresPermission(PERMISSION_MANAGE_ROLES_FROM_CONTROLLER)
559     @SystemApi
560     @TestApi
addRoleHolderFromController(@onNull String roleName, @NonNull String packageName)561     public boolean addRoleHolderFromController(@NonNull String roleName,
562             @NonNull String packageName) {
563         Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
564         Preconditions.checkStringNotEmpty(packageName, "packageName cannot be null or empty");
565         try {
566             return mService.addRoleHolderFromController(roleName, packageName);
567         } catch (RemoteException e) {
568             throw e.rethrowFromSystemServer();
569         }
570     }
571 
572     /**
573      * Remove a specific application from the holders of a role, only modifying records inside
574      * {@link RoleManager}. Should only be called from
575      * {@link android.app.role.RoleControllerService}.
576      * <p>
577      * <strong>Note:</strong> Using this API requires holding
578      * {@link #PERMISSION_MANAGE_ROLES_FROM_CONTROLLER}.
579      *
580      * @param roleName the name of the role to remove the role holder for
581      * @param packageName the package name of the application to remove from the role holders
582      *
583      * @return whether the operation was successful, and will also be {@code true} if no matching
584      *         role holder was found to remove.
585      *
586      * @see #getRoleHolders(String)
587      * @see #addRoleHolderFromController(String, String)
588      *
589      * @hide
590      */
591     @RequiresPermission(PERMISSION_MANAGE_ROLES_FROM_CONTROLLER)
592     @SystemApi
593     @TestApi
removeRoleHolderFromController(@onNull String roleName, @NonNull String packageName)594     public boolean removeRoleHolderFromController(@NonNull String roleName,
595             @NonNull String packageName) {
596         Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
597         Preconditions.checkStringNotEmpty(packageName, "packageName cannot be null or empty");
598         try {
599             return mService.removeRoleHolderFromController(roleName, packageName);
600         } catch (RemoteException e) {
601             throw e.rethrowFromSystemServer();
602         }
603     }
604 
605     /**
606      * Returns the list of all roles that the given package is currently holding
607      *
608      * @param packageName the package name
609      * @return the list of role names
610      *
611      * @hide
612      */
613     @NonNull
614     @RequiresPermission(PERMISSION_MANAGE_ROLES_FROM_CONTROLLER)
615     @SystemApi
616     @TestApi
getHeldRolesFromController(@onNull String packageName)617     public List<String> getHeldRolesFromController(@NonNull String packageName) {
618         Preconditions.checkStringNotEmpty(packageName, "packageName cannot be null or empty");
619         try {
620             return mService.getHeldRolesFromController(packageName);
621         } catch (RemoteException e) {
622             throw e.rethrowFromSystemServer();
623         }
624     }
625 
626     /**
627      * Allows getting the role holder for {@link #ROLE_SMS} without
628      * {@link Manifest.permission#OBSERVE_ROLE_HOLDERS}, as required by
629      * {@link android.provider.Telephony.Sms#getDefaultSmsPackage(Context)}
630      *
631      * @param userId The user ID to get the default SMS package for.
632      * @return the package name of the default SMS app, or {@code null} if not configured.
633      * @hide
634      */
635     @Nullable
636     @SystemApi
getDefaultSmsPackage(@serIdInt int userId)637     public String getDefaultSmsPackage(@UserIdInt int userId) {
638         try {
639             return mService.getDefaultSmsPackage(userId);
640         } catch (RemoteException e) {
641             throw e.rethrowFromSystemServer();
642         }
643     }
644 
645     private static class OnRoleHoldersChangedListenerDelegate
646             extends IOnRoleHoldersChangedListener.Stub {
647 
648         @NonNull
649         private final Executor mExecutor;
650         @NonNull
651         private final OnRoleHoldersChangedListener mListener;
652 
OnRoleHoldersChangedListenerDelegate(@onNull Executor executor, @NonNull OnRoleHoldersChangedListener listener)653         OnRoleHoldersChangedListenerDelegate(@NonNull Executor executor,
654                 @NonNull OnRoleHoldersChangedListener listener) {
655             mExecutor = executor;
656             mListener = listener;
657         }
658 
659         @Override
onRoleHoldersChanged(@onNull String roleName, @UserIdInt int userId)660         public void onRoleHoldersChanged(@NonNull String roleName, @UserIdInt int userId) {
661             long token = Binder.clearCallingIdentity();
662             try {
663                 mExecutor.execute(PooledLambda.obtainRunnable(
664                         OnRoleHoldersChangedListener::onRoleHoldersChanged, mListener, roleName,
665                         UserHandle.of(userId)));
666             } finally {
667                 Binder.restoreCallingIdentity(token);
668             }
669         }
670     }
671 }
672