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