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