• 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.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      */
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      * @see android.telephony.TelephonyManager#ACTION_EMERGENCY_ASSISTANCE
106      */
107     public static final String ROLE_EMERGENCY = "android.app.role.EMERGENCY";
108 
109     /**
110      * The name of the home role.
111      *
112      * @see Intent#CATEGORY_HOME
113      */
114     public static final String ROLE_HOME = "android.app.role.HOME";
115 
116     /**
117      * The name of the call redirection role.
118      * <p>
119      * A call redirection app provides a means to re-write the phone number for an outgoing call to
120      * place the call through a call redirection service.
121      *
122      * @see android.telecom.CallRedirectionService
123      */
124     public static final String ROLE_CALL_REDIRECTION = "android.app.role.CALL_REDIRECTION";
125 
126     /**
127      * The name of the call screening and caller id role.
128      *
129      * @see android.telecom.CallScreeningService
130      */
131     public static final String ROLE_CALL_SCREENING = "android.app.role.CALL_SCREENING";
132 
133     /**
134      * @hide
135      */
136     @IntDef(flag = true, value = { MANAGE_HOLDERS_FLAG_DONT_KILL_APP })
137     public @interface ManageHoldersFlags {}
138 
139     /**
140      * Flag parameter for {@link #addRoleHolderAsUser}, {@link #removeRoleHolderAsUser} and
141      * {@link #clearRoleHoldersAsUser} to indicate that apps should not be killed when changing
142      * their role holder status.
143      *
144      * @hide
145      */
146     @SystemApi
147     @TestApi
148     public static final int MANAGE_HOLDERS_FLAG_DONT_KILL_APP = 1;
149 
150     /**
151      * The action used to request user approval of a role for an application.
152      *
153      * @hide
154      */
155     public static final String ACTION_REQUEST_ROLE = "android.app.role.action.REQUEST_ROLE";
156 
157     /**
158      * The permission required to manage records of role holders in {@link RoleManager} directly.
159      *
160      * @hide
161      */
162     public static final String PERMISSION_MANAGE_ROLES_FROM_CONTROLLER =
163             "com.android.permissioncontroller.permission.MANAGE_ROLES_FROM_CONTROLLER";
164 
165     @NonNull
166     private final Context mContext;
167 
168     @NonNull
169     private final IRoleManager mService;
170 
171     @GuardedBy("mListenersLock")
172     @NonNull
173     private final SparseArray<ArrayMap<OnRoleHoldersChangedListener,
174             OnRoleHoldersChangedListenerDelegate>> mListeners = new SparseArray<>();
175     @NonNull
176     private final Object mListenersLock = new Object();
177 
178     /**
179      * @hide
180      */
RoleManager(@onNull Context context)181     public RoleManager(@NonNull Context context) throws ServiceManager.ServiceNotFoundException {
182         mContext = context;
183         mService = IRoleManager.Stub.asInterface(ServiceManager.getServiceOrThrow(
184                 Context.ROLE_SERVICE));
185     }
186 
187     /**
188      * Returns an {@code Intent} suitable for passing to
189      * {@link android.app.Activity#startActivityForResult(Intent, int)} which prompts the user to
190      * grant a role to this application.
191      * <p>
192      * If the role is granted, the {@code resultCode} will be
193      * {@link android.app.Activity#RESULT_OK}, otherwise it will be
194      * {@link android.app.Activity#RESULT_CANCELED}.
195      *
196      * @param roleName the name of requested role
197      *
198      * @return the {@code Intent} to prompt user to grant the role
199      */
200     @NonNull
createRequestRoleIntent(@onNull String roleName)201     public Intent createRequestRoleIntent(@NonNull String roleName) {
202         Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
203         Intent intent = new Intent(ACTION_REQUEST_ROLE);
204         intent.setPackage(mContext.getPackageManager().getPermissionControllerPackageName());
205         intent.putExtra(Intent.EXTRA_ROLE_NAME, roleName);
206         return intent;
207     }
208 
209     /**
210      * Check whether a role is available in the system.
211      *
212      * @param roleName the name of role to checking for
213      *
214      * @return whether the role is available in the system
215      */
isRoleAvailable(@onNull String roleName)216     public boolean isRoleAvailable(@NonNull String roleName) {
217         Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
218         try {
219             return mService.isRoleAvailable(roleName);
220         } catch (RemoteException e) {
221             throw e.rethrowFromSystemServer();
222         }
223     }
224 
225     /**
226      * Check whether the calling application is holding a particular role.
227      *
228      * @param roleName the name of the role to check for
229      *
230      * @return whether the calling application is holding the role
231      */
isRoleHeld(@onNull String roleName)232     public boolean isRoleHeld(@NonNull String roleName) {
233         Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
234         try {
235             return mService.isRoleHeld(roleName, mContext.getPackageName());
236         } catch (RemoteException e) {
237             throw e.rethrowFromSystemServer();
238         }
239     }
240 
241     /**
242      * Get package names of the applications holding the role.
243      * <p>
244      * <strong>Note:</strong> Using this API requires holding
245      * {@code android.permission.MANAGE_ROLE_HOLDERS}.
246      *
247      * @param roleName the name of the role to get the role holder for
248      *
249      * @return a list of package names of the role holders, or an empty list if none.
250      *
251      * @see #getRoleHoldersAsUser(String, UserHandle)
252      *
253      * @hide
254      */
255     @NonNull
256     @RequiresPermission(Manifest.permission.MANAGE_ROLE_HOLDERS)
257     @SystemApi
258     @TestApi
getRoleHolders(@onNull String roleName)259     public List<String> getRoleHolders(@NonNull String roleName) {
260         return getRoleHoldersAsUser(roleName, Process.myUserHandle());
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} and if the user id is not the current user
268      * {@code android.permission.INTERACT_ACROSS_USERS_FULL}.
269      *
270      * @param roleName the name of the role to get the role holder for
271      * @param user the user to get the role holder for
272      *
273      * @return a list of package names of the role holders, or an empty list if none.
274      *
275      * @see #addRoleHolderAsUser(String, String, int, UserHandle, Executor, Consumer)
276      * @see #removeRoleHolderAsUser(String, String, int, UserHandle, Executor, Consumer)
277      * @see #clearRoleHoldersAsUser(String, int, UserHandle, Executor, Consumer)
278      *
279      * @hide
280      */
281     @NonNull
282     @RequiresPermission(Manifest.permission.MANAGE_ROLE_HOLDERS)
283     @SystemApi
284     @TestApi
getRoleHoldersAsUser(@onNull String roleName, @NonNull UserHandle user)285     public List<String> getRoleHoldersAsUser(@NonNull String roleName, @NonNull UserHandle user) {
286         Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
287         Preconditions.checkNotNull(user, "user cannot be null");
288         try {
289             return mService.getRoleHoldersAsUser(roleName, user.getIdentifier());
290         } catch (RemoteException e) {
291             throw e.rethrowFromSystemServer();
292         }
293     }
294 
295     /**
296      * Add a specific application to the holders of a role. If the role is exclusive, the previous
297      * holder will be replaced.
298      * <p>
299      * <strong>Note:</strong> Using this API requires holding
300      * {@code android.permission.MANAGE_ROLE_HOLDERS} and if the user id is not the current user
301      * {@code android.permission.INTERACT_ACROSS_USERS_FULL}.
302      *
303      * @param roleName the name of the role to add the role holder for
304      * @param packageName the package name of the application to add to the role holders
305      * @param flags optional behavior flags
306      * @param user the user to add the role holder for
307      * @param executor the {@code Executor} to run the callback on.
308      * @param callback the callback for whether this call is successful
309      *
310      * @see #getRoleHoldersAsUser(String, UserHandle)
311      * @see #removeRoleHolderAsUser(String, String, int, UserHandle, Executor, Consumer)
312      * @see #clearRoleHoldersAsUser(String, int, UserHandle, Executor, Consumer)
313      *
314      * @hide
315      */
316     @RequiresPermission(Manifest.permission.MANAGE_ROLE_HOLDERS)
317     @SystemApi
318     @TestApi
addRoleHolderAsUser(@onNull String roleName, @NonNull String packageName, @ManageHoldersFlags int flags, @NonNull UserHandle user, @CallbackExecutor @NonNull Executor executor, @NonNull Consumer<Boolean> callback)319     public void addRoleHolderAsUser(@NonNull String roleName, @NonNull String packageName,
320             @ManageHoldersFlags int flags, @NonNull UserHandle user,
321             @CallbackExecutor @NonNull Executor executor, @NonNull Consumer<Boolean> callback) {
322         Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
323         Preconditions.checkStringNotEmpty(packageName, "packageName cannot be null or empty");
324         Preconditions.checkNotNull(user, "user cannot be null");
325         Preconditions.checkNotNull(executor, "executor cannot be null");
326         Preconditions.checkNotNull(callback, "callback cannot be null");
327         try {
328             mService.addRoleHolderAsUser(roleName, packageName, flags, user.getIdentifier(),
329                     createRemoteCallback(executor, callback));
330         } catch (RemoteException e) {
331             throw e.rethrowFromSystemServer();
332         }
333     }
334 
335     /**
336      * Remove a specific application from the holders of a role.
337      * <p>
338      * <strong>Note:</strong> Using this API requires holding
339      * {@code android.permission.MANAGE_ROLE_HOLDERS} and if the user id is not the current user
340      * {@code android.permission.INTERACT_ACROSS_USERS_FULL}.
341      *
342      * @param roleName the name of the role to remove the role holder for
343      * @param packageName the package name of the application to remove from the role holders
344      * @param flags optional behavior flags
345      * @param user the user to remove the role holder for
346      * @param executor the {@code Executor} to run the callback on.
347      * @param callback the callback for whether this call is successful
348      *
349      * @see #getRoleHoldersAsUser(String, UserHandle)
350      * @see #addRoleHolderAsUser(String, String, int, UserHandle, Executor, Consumer)
351      * @see #clearRoleHoldersAsUser(String, int, UserHandle, Executor, Consumer)
352      *
353      * @hide
354      */
355     @RequiresPermission(Manifest.permission.MANAGE_ROLE_HOLDERS)
356     @SystemApi
357     @TestApi
removeRoleHolderAsUser(@onNull String roleName, @NonNull String packageName, @ManageHoldersFlags int flags, @NonNull UserHandle user, @CallbackExecutor @NonNull Executor executor, @NonNull Consumer<Boolean> callback)358     public void removeRoleHolderAsUser(@NonNull String roleName, @NonNull String packageName,
359             @ManageHoldersFlags int flags, @NonNull UserHandle user,
360             @CallbackExecutor @NonNull Executor executor, @NonNull Consumer<Boolean> callback) {
361         Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
362         Preconditions.checkStringNotEmpty(packageName, "packageName cannot be null or empty");
363         Preconditions.checkNotNull(user, "user cannot be null");
364         Preconditions.checkNotNull(executor, "executor cannot be null");
365         Preconditions.checkNotNull(callback, "callback cannot be null");
366         try {
367             mService.removeRoleHolderAsUser(roleName, packageName, flags, user.getIdentifier(),
368                     createRemoteCallback(executor, callback));
369         } catch (RemoteException e) {
370             throw e.rethrowFromSystemServer();
371         }
372     }
373 
374     /**
375      * Remove all holders of a role.
376      * <p>
377      * <strong>Note:</strong> Using this API requires holding
378      * {@code android.permission.MANAGE_ROLE_HOLDERS} and if the user id is not the current user
379      * {@code android.permission.INTERACT_ACROSS_USERS_FULL}.
380      *
381      * @param roleName the name of the role to remove role holders for
382      * @param flags optional behavior flags
383      * @param user the user to remove role holders for
384      * @param executor the {@code Executor} to run the callback on.
385      * @param callback the callback for whether this call is successful
386      *
387      * @see #getRoleHoldersAsUser(String, UserHandle)
388      * @see #addRoleHolderAsUser(String, String, int, UserHandle, Executor, Consumer)
389      * @see #removeRoleHolderAsUser(String, String, int, UserHandle, Executor, Consumer)
390      *
391      * @hide
392      */
393     @RequiresPermission(Manifest.permission.MANAGE_ROLE_HOLDERS)
394     @SystemApi
395     @TestApi
clearRoleHoldersAsUser(@onNull String roleName, @ManageHoldersFlags int flags, @NonNull UserHandle user, @CallbackExecutor @NonNull Executor executor, @NonNull Consumer<Boolean> callback)396     public void clearRoleHoldersAsUser(@NonNull String roleName, @ManageHoldersFlags int flags,
397             @NonNull UserHandle user, @CallbackExecutor @NonNull Executor executor,
398             @NonNull Consumer<Boolean> callback) {
399         Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
400         Preconditions.checkNotNull(user, "user cannot be null");
401         Preconditions.checkNotNull(executor, "executor cannot be null");
402         Preconditions.checkNotNull(callback, "callback cannot be null");
403         try {
404             mService.clearRoleHoldersAsUser(roleName, flags, user.getIdentifier(),
405                     createRemoteCallback(executor, callback));
406         } catch (RemoteException e) {
407             throw e.rethrowFromSystemServer();
408         }
409     }
410 
411     @NonNull
createRemoteCallback(@onNull Executor executor, @NonNull Consumer<Boolean> callback)412     private static RemoteCallback createRemoteCallback(@NonNull Executor executor,
413             @NonNull Consumer<Boolean> callback) {
414         return new RemoteCallback(result -> executor.execute(() -> {
415             boolean successful = result != null;
416             long token = Binder.clearCallingIdentity();
417             try {
418                 callback.accept(successful);
419             } finally {
420                 Binder.restoreCallingIdentity(token);
421             }
422         }));
423     }
424 
425     /**
426      * Add a listener to observe role holder changes
427      * <p>
428      * <strong>Note:</strong> Using this API requires holding
429      * {@code android.permission.OBSERVE_ROLE_HOLDERS} and if the user id is not the current user
430      * {@code android.permission.INTERACT_ACROSS_USERS_FULL}.
431      *
432      * @param executor the {@code Executor} to call the listener on.
433      * @param listener the listener to be added
434      * @param user the user to add the listener for
435      *
436      * @see #removeOnRoleHoldersChangedListenerAsUser(OnRoleHoldersChangedListener, UserHandle)
437      *
438      * @hide
439      */
440     @RequiresPermission(Manifest.permission.OBSERVE_ROLE_HOLDERS)
441     @SystemApi
442     @TestApi
addOnRoleHoldersChangedListenerAsUser(@allbackExecutor @onNull Executor executor, @NonNull OnRoleHoldersChangedListener listener, @NonNull UserHandle user)443     public void addOnRoleHoldersChangedListenerAsUser(@CallbackExecutor @NonNull Executor executor,
444             @NonNull OnRoleHoldersChangedListener listener, @NonNull UserHandle user) {
445         Preconditions.checkNotNull(executor, "executor cannot be null");
446         Preconditions.checkNotNull(listener, "listener cannot be null");
447         Preconditions.checkNotNull(user, "user cannot be null");
448         int userId = user.getIdentifier();
449         synchronized (mListenersLock) {
450             ArrayMap<OnRoleHoldersChangedListener, OnRoleHoldersChangedListenerDelegate> listeners =
451                     mListeners.get(userId);
452             if (listeners == null) {
453                 listeners = new ArrayMap<>();
454                 mListeners.put(userId, listeners);
455             } else {
456                 if (listeners.containsKey(listener)) {
457                     return;
458                 }
459             }
460             OnRoleHoldersChangedListenerDelegate listenerDelegate =
461                     new OnRoleHoldersChangedListenerDelegate(executor, listener);
462             try {
463                 mService.addOnRoleHoldersChangedListenerAsUser(listenerDelegate, userId);
464             } catch (RemoteException e) {
465                 throw e.rethrowFromSystemServer();
466             }
467             listeners.put(listener, listenerDelegate);
468         }
469     }
470 
471     /**
472      * Remove a listener observing role holder changes
473      * <p>
474      * <strong>Note:</strong> Using this API requires holding
475      * {@code android.permission.OBSERVE_ROLE_HOLDERS} and if the user id is not the current user
476      * {@code android.permission.INTERACT_ACROSS_USERS_FULL}.
477      *
478      * @param listener the listener to be removed
479      * @param user the user to remove the listener for
480      *
481      * @see #addOnRoleHoldersChangedListenerAsUser(Executor, OnRoleHoldersChangedListener,
482      *                                             UserHandle)
483      *
484      * @hide
485      */
486     @RequiresPermission(Manifest.permission.OBSERVE_ROLE_HOLDERS)
487     @SystemApi
488     @TestApi
removeOnRoleHoldersChangedListenerAsUser( @onNull OnRoleHoldersChangedListener listener, @NonNull UserHandle user)489     public void removeOnRoleHoldersChangedListenerAsUser(
490             @NonNull OnRoleHoldersChangedListener listener, @NonNull UserHandle user) {
491         Preconditions.checkNotNull(listener, "listener cannot be null");
492         Preconditions.checkNotNull(user, "user cannot be null");
493         int userId = user.getIdentifier();
494         synchronized (mListenersLock) {
495             ArrayMap<OnRoleHoldersChangedListener, OnRoleHoldersChangedListenerDelegate> listeners =
496                     mListeners.get(userId);
497             if (listeners == null) {
498                 return;
499             }
500             OnRoleHoldersChangedListenerDelegate listenerDelegate = listeners.get(listener);
501             if (listenerDelegate == null) {
502                 return;
503             }
504             try {
505                 mService.removeOnRoleHoldersChangedListenerAsUser(listenerDelegate,
506                         user.getIdentifier());
507             } catch (RemoteException e) {
508                 throw e.rethrowFromSystemServer();
509             }
510             listeners.remove(listener);
511             if (listeners.isEmpty()) {
512                 mListeners.remove(userId);
513             }
514         }
515     }
516 
517     /**
518      * Set the names of all the available roles. Should only be called from
519      * {@link android.app.role.RoleControllerService}.
520      * <p>
521      * <strong>Note:</strong> Using this API requires holding
522      * {@link #PERMISSION_MANAGE_ROLES_FROM_CONTROLLER}.
523      *
524      * @param roleNames the names of all the available roles
525      *
526      * @hide
527      */
528     @RequiresPermission(PERMISSION_MANAGE_ROLES_FROM_CONTROLLER)
529     @SystemApi
530     @TestApi
setRoleNamesFromController(@onNull List<String> roleNames)531     public void setRoleNamesFromController(@NonNull List<String> roleNames) {
532         Preconditions.checkNotNull(roleNames, "roleNames cannot be null");
533         try {
534             mService.setRoleNamesFromController(roleNames);
535         } catch (RemoteException e) {
536             throw e.rethrowFromSystemServer();
537         }
538     }
539 
540     /**
541      * Add a specific application to the holders of a role, only modifying records inside
542      * {@link RoleManager}. Should only be called from
543      * {@link android.app.role.RoleControllerService}.
544      * <p>
545      * <strong>Note:</strong> Using this API requires holding
546      * {@link #PERMISSION_MANAGE_ROLES_FROM_CONTROLLER}.
547      *
548      * @param roleName the name of the role to add the role holder for
549      * @param packageName the package name of the application to add to the role holders
550      *
551      * @return whether the operation was successful, and will also be {@code true} if a matching
552      *         role holder is already found.
553      *
554      * @see #getRoleHolders(String)
555      * @see #removeRoleHolderFromController(String, String)
556      *
557      * @hide
558      */
559     @RequiresPermission(PERMISSION_MANAGE_ROLES_FROM_CONTROLLER)
560     @SystemApi
561     @TestApi
addRoleHolderFromController(@onNull String roleName, @NonNull String packageName)562     public boolean addRoleHolderFromController(@NonNull String roleName,
563             @NonNull String packageName) {
564         Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
565         Preconditions.checkStringNotEmpty(packageName, "packageName cannot be null or empty");
566         try {
567             return mService.addRoleHolderFromController(roleName, packageName);
568         } catch (RemoteException e) {
569             throw e.rethrowFromSystemServer();
570         }
571     }
572 
573     /**
574      * Remove a specific application from the holders of a role, only modifying records inside
575      * {@link RoleManager}. Should only be called from
576      * {@link android.app.role.RoleControllerService}.
577      * <p>
578      * <strong>Note:</strong> Using this API requires holding
579      * {@link #PERMISSION_MANAGE_ROLES_FROM_CONTROLLER}.
580      *
581      * @param roleName the name of the role to remove the role holder for
582      * @param packageName the package name of the application to remove from the role holders
583      *
584      * @return whether the operation was successful, and will also be {@code true} if no matching
585      *         role holder was found to remove.
586      *
587      * @see #getRoleHolders(String)
588      * @see #addRoleHolderFromController(String, String)
589      *
590      * @hide
591      */
592     @RequiresPermission(PERMISSION_MANAGE_ROLES_FROM_CONTROLLER)
593     @SystemApi
594     @TestApi
removeRoleHolderFromController(@onNull String roleName, @NonNull String packageName)595     public boolean removeRoleHolderFromController(@NonNull String roleName,
596             @NonNull String packageName) {
597         Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
598         Preconditions.checkStringNotEmpty(packageName, "packageName cannot be null or empty");
599         try {
600             return mService.removeRoleHolderFromController(roleName, packageName);
601         } catch (RemoteException e) {
602             throw e.rethrowFromSystemServer();
603         }
604     }
605 
606     /**
607      * Returns the list of all roles that the given package is currently holding
608      *
609      * @param packageName the package name
610      * @return the list of role names
611      *
612      * @hide
613      */
614     @NonNull
615     @RequiresPermission(PERMISSION_MANAGE_ROLES_FROM_CONTROLLER)
616     @SystemApi
617     @TestApi
getHeldRolesFromController(@onNull String packageName)618     public List<String> getHeldRolesFromController(@NonNull String packageName) {
619         Preconditions.checkStringNotEmpty(packageName, "packageName cannot be null or empty");
620         try {
621             return mService.getHeldRolesFromController(packageName);
622         } catch (RemoteException e) {
623             throw e.rethrowFromSystemServer();
624         }
625     }
626 
627     /**
628      * Allows getting the role holder for {@link #ROLE_SMS} without
629      * {@link Manifest.permission#OBSERVE_ROLE_HOLDERS}, as required by
630      * {@link android.provider.Telephony.Sms#getDefaultSmsPackage(Context)}
631      *
632      * @hide
633      */
634     @Nullable
getDefaultSmsPackage(@serIdInt int userId)635     public String getDefaultSmsPackage(@UserIdInt int userId) {
636         try {
637             return mService.getDefaultSmsPackage(userId);
638         } catch (RemoteException e) {
639             throw e.rethrowFromSystemServer();
640         }
641     }
642 
643     private static class OnRoleHoldersChangedListenerDelegate
644             extends IOnRoleHoldersChangedListener.Stub {
645 
646         @NonNull
647         private final Executor mExecutor;
648         @NonNull
649         private final OnRoleHoldersChangedListener mListener;
650 
OnRoleHoldersChangedListenerDelegate(@onNull Executor executor, @NonNull OnRoleHoldersChangedListener listener)651         OnRoleHoldersChangedListenerDelegate(@NonNull Executor executor,
652                 @NonNull OnRoleHoldersChangedListener listener) {
653             mExecutor = executor;
654             mListener = listener;
655         }
656 
657         @Override
onRoleHoldersChanged(@onNull String roleName, @UserIdInt int userId)658         public void onRoleHoldersChanged(@NonNull String roleName, @UserIdInt int userId) {
659             long token = Binder.clearCallingIdentity();
660             try {
661                 mExecutor.execute(PooledLambda.obtainRunnable(
662                         OnRoleHoldersChangedListener::onRoleHoldersChanged, mListener, roleName,
663                         UserHandle.of(userId)));
664             } finally {
665                 Binder.restoreCallingIdentity(token);
666             }
667         }
668     }
669 }
670