blob: d1f8ed20cf0fefaa0afd827c33890cd9edb476a8 [file] [log] [blame]
Hai Zhangb7776682018-09-25 15:10:57 -07001/*
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
17package android.app.role;
18
19import android.Manifest;
20import android.annotation.CallbackExecutor;
Hai Zhang71d70362019-02-04 16:17:38 -080021import android.annotation.IntDef;
Hai Zhangb7776682018-09-25 15:10:57 -070022import android.annotation.NonNull;
Eugene Susla4ab95112018-12-17 14:45:11 -080023import android.annotation.Nullable;
Hai Zhangb7776682018-09-25 15:10:57 -070024import android.annotation.RequiresPermission;
25import android.annotation.SystemApi;
26import android.annotation.SystemService;
Hai Zhang6329be42018-11-19 11:05:34 -080027import android.annotation.TestApi;
Hai Zhang31d06ba2018-12-06 18:14:42 -080028import android.annotation.UserIdInt;
Hai Zhangb7776682018-09-25 15:10:57 -070029import android.content.Context;
30import android.content.Intent;
31import android.os.Binder;
Hai Zhangb295ac42018-11-16 16:08:18 -080032import android.os.Process;
Hai Zhangf5e8ccd2019-03-06 20:12:24 -080033import android.os.RemoteCallback;
Hai Zhangb7776682018-09-25 15:10:57 -070034import android.os.RemoteException;
35import android.os.ServiceManager;
36import android.os.UserHandle;
Hai Zhang31d06ba2018-12-06 18:14:42 -080037import android.util.ArrayMap;
38import android.util.SparseArray;
Hai Zhangb7776682018-09-25 15:10:57 -070039
Hai Zhang31d06ba2018-12-06 18:14:42 -080040import com.android.internal.annotations.GuardedBy;
Hai Zhangb7776682018-09-25 15:10:57 -070041import com.android.internal.util.Preconditions;
Hai Zhang31d06ba2018-12-06 18:14:42 -080042import com.android.internal.util.function.pooled.PooledLambda;
Hai Zhangb7776682018-09-25 15:10:57 -070043
44import java.util.List;
Hai Zhangb7776682018-09-25 15:10:57 -070045import java.util.concurrent.Executor;
Hai Zhangf5e8ccd2019-03-06 20:12:24 -080046import java.util.function.Consumer;
Hai Zhangb7776682018-09-25 15:10:57 -070047
48/**
49 * This class provides information about and manages roles.
50 * <p>
51 * A role is a unique name within the system associated with certain privileges. The list of
52 * available roles might change with a system app update, so apps should not make assumption about
53 * the availability of roles. Instead, they should always query if the role is available using
54 * {@link #isRoleAvailable(String)} before trying to do anything with it. Some predefined role names
55 * are available as constants in this class, and a list of possibly available roles can be found in
56 * the AndroidX Libraries.
57 * <p>
58 * There can be multiple applications qualifying for a role, but only a subset of them can become
59 * role holders. To qualify for a role, an application must meet certain requirements, including
60 * defining certain components in its manifest. These requirements can be found in the AndroidX
61 * Libraries. Then the application will need user consent to become a role holder, which can be
Hai Zhang87ed09a2018-10-22 10:43:31 -070062 * requested using {@link android.app.Activity#startActivityForResult(Intent, int)} with the
63 * {@code Intent} obtained from {@link #createRequestRoleIntent(String)}.
Hai Zhangb7776682018-09-25 15:10:57 -070064 * <p>
65 * Upon becoming a role holder, the application may be granted certain privileges that are role
66 * specific. When the application loses its role, these privileges will also be revoked.
67 */
68@SystemService(Context.ROLE_SERVICE)
69public final class RoleManager {
70
71 private static final String LOG_TAG = RoleManager.class.getSimpleName();
72
73 /**
Hai Zhang9ba31962019-02-08 12:27:45 -080074 * The name of the assistant app role.
75 *
Hai Zhang051cdc82019-02-22 19:58:02 -080076 * @see android.service.voice.VoiceInteractionService
Hai Zhang9ba31962019-02-08 12:27:45 -080077 */
Hai Zhang9ba31962019-02-08 12:27:45 -080078 public static final String ROLE_ASSISTANT = "android.app.role.ASSISTANT";
79
80 /**
81 * The name of the browser role.
82 *
83 * @see Intent#CATEGORY_APP_BROWSER
84 */
85 public static final String ROLE_BROWSER = "android.app.role.BROWSER";
86
87 /**
Hai Zhangb7776682018-09-25 15:10:57 -070088 * The name of the dialer role.
Hai Zhang85b762c2019-01-10 17:48:56 -080089 *
90 * @see Intent#ACTION_DIAL
Hai Zhangb7776682018-09-25 15:10:57 -070091 */
92 public static final String ROLE_DIALER = "android.app.role.DIALER";
93
94 /**
95 * The name of the SMS role.
Jeff Sharkey82338602018-11-18 17:53:02 -070096 *
97 * @see Intent#CATEGORY_APP_MESSAGING
Hai Zhangb7776682018-09-25 15:10:57 -070098 */
99 public static final String ROLE_SMS = "android.app.role.SMS";
100
101 /**
Hai Zhang9ba31962019-02-08 12:27:45 -0800102 * The name of the emergency role
Jeff Sharkey82338602018-11-18 17:53:02 -0700103 *
Hai Zhang9ba31962019-02-08 12:27:45 -0800104 * @see android.telephony.TelephonyManager#ACTION_EMERGENCY_ASSISTANCE
Jeff Sharkey82338602018-11-18 17:53:02 -0700105 */
Hai Zhang9ba31962019-02-08 12:27:45 -0800106 public static final String ROLE_EMERGENCY = "android.app.role.EMERGENCY";
Jeff Sharkey82338602018-11-18 17:53:02 -0700107
108 /**
Hai Zhang85b762c2019-01-10 17:48:56 -0800109 * 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 /**
Hai Zhang9ba31962019-02-08 12:27:45 -0800116 * The name of the music player role.
Hai Zhang85b762c2019-01-10 17:48:56 -0800117 *
Hai Zhang9ba31962019-02-08 12:27:45 -0800118 * @see Intent#CATEGORY_APP_MUSIC
Hai Zhang85b762c2019-01-10 17:48:56 -0800119 */
Hai Zhang9ba31962019-02-08 12:27:45 -0800120 public static final String ROLE_MUSIC = "android.app.role.MUSIC";
121
122 /**
123 * The name of the gallery role.
124 *
125 * @see Intent#CATEGORY_APP_GALLERY
126 */
127 public static final String ROLE_GALLERY = "android.app.role.GALLERY";
Hai Zhang85b762c2019-01-10 17:48:56 -0800128
129 /**
130 * The name of the car mode dialer app role.
131 * <p>
132 * Similar to the {@link #ROLE_DIALER dialer} role, this role determines which app is
133 * responsible for showing the user interface for ongoing calls on the device. It is only used
134 * when the device is in car mode.
135 *
136 * @see #ROLE_DIALER
137 * @see android.app.UiModeManager#ACTION_ENTER_CAR_MODE
138 * @see android.telecom.InCallService
139 *
140 * TODO: STOPSHIP: Make name of required roles public API
141 * @hide
142 */
Hai Zhangd142e8182019-02-06 16:32:23 -0800143 public static final String ROLE_CAR_MODE_DIALER = "android.app.role.CAR_MODE_DIALER";
Hai Zhang85b762c2019-01-10 17:48:56 -0800144
145 /**
Hai Zhangd142e8182019-02-06 16:32:23 -0800146 * The name of the call redirection role.
Hai Zhang85b762c2019-01-10 17:48:56 -0800147 * <p>
Hai Zhangd142e8182019-02-06 16:32:23 -0800148 * A call redirection app provides a means to re-write the phone number for an outgoing call to
149 * place the call through a call redirection service.
Hai Zhang85b762c2019-01-10 17:48:56 -0800150 *
151 * @see android.telecom.CallRedirectionService
Hai Zhang85b762c2019-01-10 17:48:56 -0800152 */
Hai Zhangd142e8182019-02-06 16:32:23 -0800153 public static final String ROLE_CALL_REDIRECTION = "android.app.role.CALL_REDIRECTION";
Hai Zhang85b762c2019-01-10 17:48:56 -0800154
155 /**
156 * The name of the call screening and caller id role.
157 *
158 * @see android.telecom.CallScreeningService
Hai Zhang85b762c2019-01-10 17:48:56 -0800159 */
Hai Zhangd142e8182019-02-06 16:32:23 -0800160 public static final String ROLE_CALL_SCREENING = "android.app.role.CALL_SCREENING";
Hai Zhang85b762c2019-01-10 17:48:56 -0800161
162 /**
163 * The name of the call companion app role.
164 * <p>
165 * A call companion app provides no user interface for calls, but will be bound to by Telecom
166 * when there are active calls on the device. Companion apps for wearable devices are an
167 * acceptable use-case.
168 * <p>
169 * Multiple apps may hold this role at the same time.
170 *
171 * @see android.telecom.InCallService
172 *
173 * TODO: STOPSHIP: Make name of required roles public API
174 * @hide
175 */
Hai Zhangd142e8182019-02-06 16:32:23 -0800176 public static final String ROLE_CALL_COMPANION = "android.app.role.CALL_COMPANION";
Hai Zhang85b762c2019-01-10 17:48:56 -0800177
178 /**
Hai Zhang71d70362019-02-04 16:17:38 -0800179 * @hide
180 */
181 @IntDef(flag = true, value = { MANAGE_HOLDERS_FLAG_DONT_KILL_APP })
182 public @interface ManageHoldersFlags {}
183
184 /**
185 * Flag parameter for {@link #addRoleHolderAsUser}, {@link #removeRoleHolderAsUser} and
186 * {@link #clearRoleHoldersAsUser} to indicate that apps should not be killed when changing
187 * their role holder status.
188 *
189 * @hide
190 */
191 @SystemApi
Leland Miller2293da22019-02-28 15:45:51 -0800192 @TestApi
Hai Zhang71d70362019-02-04 16:17:38 -0800193 public static final int MANAGE_HOLDERS_FLAG_DONT_KILL_APP = 1;
194
195 /**
Hai Zhangb7776682018-09-25 15:10:57 -0700196 * The action used to request user approval of a role for an application.
197 *
198 * @hide
199 */
200 public static final String ACTION_REQUEST_ROLE = "android.app.role.action.REQUEST_ROLE";
201
202 /**
Hai Zhang87ed09a2018-10-22 10:43:31 -0700203 * The permission required to manage records of role holders in {@link RoleManager} directly.
204 *
205 * @hide
206 */
Hai Zhang8e60a8f2018-11-20 11:21:09 -0800207 public static final String PERMISSION_MANAGE_ROLES_FROM_CONTROLLER =
208 "com.android.permissioncontroller.permission.MANAGE_ROLES_FROM_CONTROLLER";
Hai Zhang87ed09a2018-10-22 10:43:31 -0700209
Hai Zhangb7776682018-09-25 15:10:57 -0700210 @NonNull
211 private final Context mContext;
212
213 @NonNull
214 private final IRoleManager mService;
215
Hai Zhang31d06ba2018-12-06 18:14:42 -0800216 @GuardedBy("mListenersLock")
217 @NonNull
218 private final SparseArray<ArrayMap<OnRoleHoldersChangedListener,
219 OnRoleHoldersChangedListenerDelegate>> mListeners = new SparseArray<>();
220 @NonNull
221 private final Object mListenersLock = new Object();
222
Hai Zhangb7776682018-09-25 15:10:57 -0700223 /**
224 * @hide
225 */
226 public RoleManager(@NonNull Context context) throws ServiceManager.ServiceNotFoundException {
227 mContext = context;
228 mService = IRoleManager.Stub.asInterface(ServiceManager.getServiceOrThrow(
229 Context.ROLE_SERVICE));
230 }
231
232 /**
Hai Zhang87ed09a2018-10-22 10:43:31 -0700233 * Returns an {@code Intent} suitable for passing to
234 * {@link android.app.Activity#startActivityForResult(Intent, int)} which prompts the user to
235 * grant a role to this application.
Hai Zhangb7776682018-09-25 15:10:57 -0700236 * <p>
Hai Zhang87ed09a2018-10-22 10:43:31 -0700237 * If the role is granted, the {@code resultCode} will be
238 * {@link android.app.Activity#RESULT_OK}, otherwise it will be
239 * {@link android.app.Activity#RESULT_CANCELED}.
Hai Zhangb7776682018-09-25 15:10:57 -0700240 *
241 * @param roleName the name of requested role
242 *
243 * @return the {@code Intent} to prompt user to grant the role
Hai Zhangb7776682018-09-25 15:10:57 -0700244 */
245 @NonNull
246 public Intent createRequestRoleIntent(@NonNull String roleName) {
247 Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
248 Intent intent = new Intent(ACTION_REQUEST_ROLE);
249 intent.setPackage(mContext.getPackageManager().getPermissionControllerPackageName());
Hai Zhang3a212892019-01-11 15:21:17 -0800250 intent.putExtra(Intent.EXTRA_ROLE_NAME, roleName);
Hai Zhangb7776682018-09-25 15:10:57 -0700251 return intent;
252 }
253
254 /**
255 * Check whether a role is available in the system.
256 *
257 * @param roleName the name of role to checking for
258 *
259 * @return whether the role is available in the system
Hai Zhangb7776682018-09-25 15:10:57 -0700260 */
261 public boolean isRoleAvailable(@NonNull String roleName) {
262 Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
263 try {
264 return mService.isRoleAvailable(roleName);
265 } catch (RemoteException e) {
266 throw e.rethrowFromSystemServer();
267 }
268 }
269
270 /**
271 * Check whether the calling application is holding a particular role.
272 *
273 * @param roleName the name of the role to check for
274 *
275 * @return whether the calling application is holding the role
Hai Zhangb7776682018-09-25 15:10:57 -0700276 */
277 public boolean isRoleHeld(@NonNull String roleName) {
278 Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
279 try {
280 return mService.isRoleHeld(roleName, mContext.getPackageName());
281 } catch (RemoteException e) {
282 throw e.rethrowFromSystemServer();
283 }
284 }
285
286 /**
287 * Get package names of the applications holding the role.
288 * <p>
Hai Zhang87ed09a2018-10-22 10:43:31 -0700289 * <strong>Note:</strong> Using this API requires holding
290 * {@code android.permission.MANAGE_ROLE_HOLDERS}.
291 *
292 * @param roleName the name of the role to get the role holder for
293 *
294 * @return a list of package names of the role holders, or an empty list if none.
295 *
Hai Zhang87ed09a2018-10-22 10:43:31 -0700296 * @see #getRoleHoldersAsUser(String, UserHandle)
297 *
298 * @hide
299 */
300 @NonNull
301 @RequiresPermission(Manifest.permission.MANAGE_ROLE_HOLDERS)
302 @SystemApi
Hai Zhang6329be42018-11-19 11:05:34 -0800303 @TestApi
Hai Zhang87ed09a2018-10-22 10:43:31 -0700304 public List<String> getRoleHolders(@NonNull String roleName) {
Hai Zhangb295ac42018-11-16 16:08:18 -0800305 return getRoleHoldersAsUser(roleName, Process.myUserHandle());
Hai Zhang87ed09a2018-10-22 10:43:31 -0700306 }
307
308 /**
309 * Get package names of the applications holding the role.
310 * <p>
311 * <strong>Note:</strong> Using this API requires holding
Hai Zhangb7776682018-09-25 15:10:57 -0700312 * {@code android.permission.MANAGE_ROLE_HOLDERS} and if the user id is not the current user
313 * {@code android.permission.INTERACT_ACROSS_USERS_FULL}.
314 *
315 * @param roleName the name of the role to get the role holder for
316 * @param user the user to get the role holder for
317 *
Hai Zhang87ed09a2018-10-22 10:43:31 -0700318 * @return a list of package names of the role holders, or an empty list if none.
Hai Zhangb7776682018-09-25 15:10:57 -0700319 *
Hai Zhangf5e8ccd2019-03-06 20:12:24 -0800320 * @see #addRoleHolderAsUser(String, String, int, UserHandle, Executor, Consumer)
321 * @see #removeRoleHolderAsUser(String, String, int, UserHandle, Executor, Consumer)
322 * @see #clearRoleHoldersAsUser(String, int, UserHandle, Executor, Consumer)
Hai Zhangb7776682018-09-25 15:10:57 -0700323 *
324 * @hide
325 */
326 @NonNull
327 @RequiresPermission(Manifest.permission.MANAGE_ROLE_HOLDERS)
328 @SystemApi
Hai Zhang6329be42018-11-19 11:05:34 -0800329 @TestApi
Hai Zhang87ed09a2018-10-22 10:43:31 -0700330 public List<String> getRoleHoldersAsUser(@NonNull String roleName, @NonNull UserHandle user) {
Hai Zhangb7776682018-09-25 15:10:57 -0700331 Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
332 Preconditions.checkNotNull(user, "user cannot be null");
Hai Zhangb7776682018-09-25 15:10:57 -0700333 try {
Hai Zhang87ed09a2018-10-22 10:43:31 -0700334 return mService.getRoleHoldersAsUser(roleName, user.getIdentifier());
Hai Zhangb7776682018-09-25 15:10:57 -0700335 } catch (RemoteException e) {
336 throw e.rethrowFromSystemServer();
337 }
Hai Zhangb7776682018-09-25 15:10:57 -0700338 }
339
340 /**
341 * Add a specific application to the holders of a role. If the role is exclusive, the previous
342 * holder will be replaced.
343 * <p>
Hai Zhang87ed09a2018-10-22 10:43:31 -0700344 * <strong>Note:</strong> Using this API requires holding
Hai Zhangb7776682018-09-25 15:10:57 -0700345 * {@code android.permission.MANAGE_ROLE_HOLDERS} and if the user id is not the current user
346 * {@code android.permission.INTERACT_ACROSS_USERS_FULL}.
347 *
348 * @param roleName the name of the role to add the role holder for
349 * @param packageName the package name of the application to add to the role holders
Hai Zhang71d70362019-02-04 16:17:38 -0800350 * @param flags optional behavior flags
Hai Zhangb7776682018-09-25 15:10:57 -0700351 * @param user the user to add the role holder for
352 * @param executor the {@code Executor} to run the callback on.
353 * @param callback the callback for whether this call is successful
354 *
Hai Zhangb7776682018-09-25 15:10:57 -0700355 * @see #getRoleHoldersAsUser(String, UserHandle)
Hai Zhangf5e8ccd2019-03-06 20:12:24 -0800356 * @see #removeRoleHolderAsUser(String, String, int, UserHandle, Executor, Consumer)
357 * @see #clearRoleHoldersAsUser(String, int, UserHandle, Executor, Consumer)
Hai Zhangb7776682018-09-25 15:10:57 -0700358 *
359 * @hide
360 */
361 @RequiresPermission(Manifest.permission.MANAGE_ROLE_HOLDERS)
362 @SystemApi
Hai Zhang6329be42018-11-19 11:05:34 -0800363 @TestApi
Hai Zhangb7776682018-09-25 15:10:57 -0700364 public void addRoleHolderAsUser(@NonNull String roleName, @NonNull String packageName,
Hai Zhang71d70362019-02-04 16:17:38 -0800365 @ManageHoldersFlags int flags, @NonNull UserHandle user,
Hai Zhangf5e8ccd2019-03-06 20:12:24 -0800366 @CallbackExecutor @NonNull Executor executor, @NonNull Consumer<Boolean> callback) {
Hai Zhangb7776682018-09-25 15:10:57 -0700367 Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
368 Preconditions.checkStringNotEmpty(packageName, "packageName cannot be null or empty");
369 Preconditions.checkNotNull(user, "user cannot be null");
370 Preconditions.checkNotNull(executor, "executor cannot be null");
371 Preconditions.checkNotNull(callback, "callback cannot be null");
372 try {
Hai Zhang71d70362019-02-04 16:17:38 -0800373 mService.addRoleHolderAsUser(roleName, packageName, flags, user.getIdentifier(),
Hai Zhangf5e8ccd2019-03-06 20:12:24 -0800374 createRemoteCallback(executor, callback));
Hai Zhangb7776682018-09-25 15:10:57 -0700375 } catch (RemoteException e) {
376 throw e.rethrowFromSystemServer();
377 }
378 }
379
380 /**
381 * Remove a specific application from the holders of a role.
382 * <p>
Hai Zhang87ed09a2018-10-22 10:43:31 -0700383 * <strong>Note:</strong> Using this API requires holding
Hai Zhangb7776682018-09-25 15:10:57 -0700384 * {@code android.permission.MANAGE_ROLE_HOLDERS} and if the user id is not the current user
385 * {@code android.permission.INTERACT_ACROSS_USERS_FULL}.
386 *
387 * @param roleName the name of the role to remove the role holder for
388 * @param packageName the package name of the application to remove from the role holders
Hai Zhang71d70362019-02-04 16:17:38 -0800389 * @param flags optional behavior flags
Hai Zhangb7776682018-09-25 15:10:57 -0700390 * @param user the user to remove the role holder for
391 * @param executor the {@code Executor} to run the callback on.
392 * @param callback the callback for whether this call is successful
393 *
Hai Zhangb7776682018-09-25 15:10:57 -0700394 * @see #getRoleHoldersAsUser(String, UserHandle)
Hai Zhangf5e8ccd2019-03-06 20:12:24 -0800395 * @see #addRoleHolderAsUser(String, String, int, UserHandle, Executor, Consumer)
396 * @see #clearRoleHoldersAsUser(String, int, UserHandle, Executor, Consumer)
Hai Zhangb7776682018-09-25 15:10:57 -0700397 *
398 * @hide
399 */
400 @RequiresPermission(Manifest.permission.MANAGE_ROLE_HOLDERS)
401 @SystemApi
Hai Zhang6329be42018-11-19 11:05:34 -0800402 @TestApi
Hai Zhangb7776682018-09-25 15:10:57 -0700403 public void removeRoleHolderAsUser(@NonNull String roleName, @NonNull String packageName,
Hai Zhang71d70362019-02-04 16:17:38 -0800404 @ManageHoldersFlags int flags, @NonNull UserHandle user,
Hai Zhangf5e8ccd2019-03-06 20:12:24 -0800405 @CallbackExecutor @NonNull Executor executor, @NonNull Consumer<Boolean> callback) {
Hai Zhangb7776682018-09-25 15:10:57 -0700406 Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
407 Preconditions.checkStringNotEmpty(packageName, "packageName cannot be null or empty");
408 Preconditions.checkNotNull(user, "user cannot be null");
409 Preconditions.checkNotNull(executor, "executor cannot be null");
410 Preconditions.checkNotNull(callback, "callback cannot be null");
411 try {
Hai Zhang71d70362019-02-04 16:17:38 -0800412 mService.removeRoleHolderAsUser(roleName, packageName, flags, user.getIdentifier(),
Hai Zhangf5e8ccd2019-03-06 20:12:24 -0800413 createRemoteCallback(executor, callback));
Hai Zhangb7776682018-09-25 15:10:57 -0700414 } catch (RemoteException e) {
415 throw e.rethrowFromSystemServer();
416 }
417 }
418
419 /**
420 * Remove all holders of a role.
421 * <p>
Hai Zhang87ed09a2018-10-22 10:43:31 -0700422 * <strong>Note:</strong> Using this API requires holding
Hai Zhangb7776682018-09-25 15:10:57 -0700423 * {@code android.permission.MANAGE_ROLE_HOLDERS} and if the user id is not the current user
424 * {@code android.permission.INTERACT_ACROSS_USERS_FULL}.
425 *
426 * @param roleName the name of the role to remove role holders for
Hai Zhang71d70362019-02-04 16:17:38 -0800427 * @param flags optional behavior flags
Hai Zhangb7776682018-09-25 15:10:57 -0700428 * @param user the user to remove role holders for
429 * @param executor the {@code Executor} to run the callback on.
430 * @param callback the callback for whether this call is successful
431 *
Hai Zhangb7776682018-09-25 15:10:57 -0700432 * @see #getRoleHoldersAsUser(String, UserHandle)
Hai Zhangf5e8ccd2019-03-06 20:12:24 -0800433 * @see #addRoleHolderAsUser(String, String, int, UserHandle, Executor, Consumer)
434 * @see #removeRoleHolderAsUser(String, String, int, UserHandle, Executor, Consumer)
Hai Zhangb7776682018-09-25 15:10:57 -0700435 *
436 * @hide
437 */
438 @RequiresPermission(Manifest.permission.MANAGE_ROLE_HOLDERS)
439 @SystemApi
Hai Zhang6329be42018-11-19 11:05:34 -0800440 @TestApi
Hai Zhang71d70362019-02-04 16:17:38 -0800441 public void clearRoleHoldersAsUser(@NonNull String roleName, @ManageHoldersFlags int flags,
442 @NonNull UserHandle user, @CallbackExecutor @NonNull Executor executor,
Hai Zhangf5e8ccd2019-03-06 20:12:24 -0800443 @NonNull Consumer<Boolean> callback) {
Hai Zhangb7776682018-09-25 15:10:57 -0700444 Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
445 Preconditions.checkNotNull(user, "user cannot be null");
446 Preconditions.checkNotNull(executor, "executor cannot be null");
447 Preconditions.checkNotNull(callback, "callback cannot be null");
448 try {
Hai Zhang71d70362019-02-04 16:17:38 -0800449 mService.clearRoleHoldersAsUser(roleName, flags, user.getIdentifier(),
Hai Zhangf5e8ccd2019-03-06 20:12:24 -0800450 createRemoteCallback(executor, callback));
Hai Zhangb7776682018-09-25 15:10:57 -0700451 } catch (RemoteException e) {
452 throw e.rethrowFromSystemServer();
453 }
454 }
455
Hai Zhangf5e8ccd2019-03-06 20:12:24 -0800456 @NonNull
457 private static RemoteCallback createRemoteCallback(@NonNull Executor executor,
458 @NonNull Consumer<Boolean> callback) {
459 return new RemoteCallback(result -> executor.execute(() -> {
460 boolean successful = result != null;
461 long token = Binder.clearCallingIdentity();
462 try {
463 callback.accept(successful);
464 } finally {
465 Binder.restoreCallingIdentity(token);
466 }
467 }));
468 }
469
Hai Zhang87ed09a2018-10-22 10:43:31 -0700470 /**
Hai Zhang31d06ba2018-12-06 18:14:42 -0800471 * Add a listener to observe role holder changes
472 * <p>
473 * <strong>Note:</strong> Using this API requires holding
474 * {@code android.permission.OBSERVE_ROLE_HOLDERS} and if the user id is not the current user
475 * {@code android.permission.INTERACT_ACROSS_USERS_FULL}.
476 *
477 * @param executor the {@code Executor} to call the listener on.
478 * @param listener the listener to be added
479 * @param user the user to add the listener for
480 *
481 * @see #removeOnRoleHoldersChangedListenerAsUser(OnRoleHoldersChangedListener, UserHandle)
482 *
483 * @hide
484 */
485 @RequiresPermission(Manifest.permission.OBSERVE_ROLE_HOLDERS)
486 @SystemApi
Hai Zhang22435862019-02-26 16:57:47 -0800487 @TestApi
Hai Zhang31d06ba2018-12-06 18:14:42 -0800488 public void addOnRoleHoldersChangedListenerAsUser(@CallbackExecutor @NonNull Executor executor,
489 @NonNull OnRoleHoldersChangedListener listener, @NonNull UserHandle user) {
490 Preconditions.checkNotNull(executor, "executor cannot be null");
491 Preconditions.checkNotNull(listener, "listener cannot be null");
492 Preconditions.checkNotNull(user, "user cannot be null");
493 int userId = user.getIdentifier();
494 synchronized (mListenersLock) {
495 ArrayMap<OnRoleHoldersChangedListener, OnRoleHoldersChangedListenerDelegate> listeners =
496 mListeners.get(userId);
497 if (listeners == null) {
498 listeners = new ArrayMap<>();
499 mListeners.put(userId, listeners);
500 } else {
501 if (listeners.containsKey(listener)) {
502 return;
503 }
504 }
505 OnRoleHoldersChangedListenerDelegate listenerDelegate =
506 new OnRoleHoldersChangedListenerDelegate(executor, listener);
507 try {
508 mService.addOnRoleHoldersChangedListenerAsUser(listenerDelegate, userId);
509 } catch (RemoteException e) {
510 throw e.rethrowFromSystemServer();
511 }
512 listeners.put(listener, listenerDelegate);
513 }
514 }
515
516 /**
517 * Remove a listener observing role holder changes
518 * <p>
519 * <strong>Note:</strong> Using this API requires holding
520 * {@code android.permission.OBSERVE_ROLE_HOLDERS} and if the user id is not the current user
521 * {@code android.permission.INTERACT_ACROSS_USERS_FULL}.
522 *
523 * @param listener the listener to be removed
524 * @param user the user to remove the listener for
525 *
526 * @see #addOnRoleHoldersChangedListenerAsUser(Executor, OnRoleHoldersChangedListener,
527 * UserHandle)
528 *
529 * @hide
530 */
531 @RequiresPermission(Manifest.permission.OBSERVE_ROLE_HOLDERS)
532 @SystemApi
Hai Zhang22435862019-02-26 16:57:47 -0800533 @TestApi
Hai Zhang31d06ba2018-12-06 18:14:42 -0800534 public void removeOnRoleHoldersChangedListenerAsUser(
535 @NonNull OnRoleHoldersChangedListener listener, @NonNull UserHandle user) {
536 Preconditions.checkNotNull(listener, "listener cannot be null");
537 Preconditions.checkNotNull(user, "user cannot be null");
538 int userId = user.getIdentifier();
539 synchronized (mListenersLock) {
540 ArrayMap<OnRoleHoldersChangedListener, OnRoleHoldersChangedListenerDelegate> listeners =
541 mListeners.get(userId);
542 if (listeners == null) {
543 return;
544 }
545 OnRoleHoldersChangedListenerDelegate listenerDelegate = listeners.get(listener);
546 if (listenerDelegate == null) {
547 return;
548 }
549 try {
550 mService.removeOnRoleHoldersChangedListenerAsUser(listenerDelegate,
551 user.getIdentifier());
552 } catch (RemoteException e) {
553 throw e.rethrowFromSystemServer();
554 }
555 listeners.remove(listener);
556 if (listeners.isEmpty()) {
557 mListeners.remove(userId);
558 }
559 }
560 }
561
562 /**
Hai Zhang8e60a8f2018-11-20 11:21:09 -0800563 * Set the names of all the available roles. Should only be called from
Hai Zhanga4959e52019-03-06 12:21:07 -0800564 * {@link android.app.role.RoleControllerService}.
Hai Zhang8e60a8f2018-11-20 11:21:09 -0800565 * <p>
566 * <strong>Note:</strong> Using this API requires holding
567 * {@link #PERMISSION_MANAGE_ROLES_FROM_CONTROLLER}.
568 *
569 * @param roleNames the names of all the available roles
570 *
Hai Zhang8e60a8f2018-11-20 11:21:09 -0800571 * @hide
572 */
573 @RequiresPermission(PERMISSION_MANAGE_ROLES_FROM_CONTROLLER)
574 @SystemApi
Hai Zhang22435862019-02-26 16:57:47 -0800575 @TestApi
Hai Zhang8e60a8f2018-11-20 11:21:09 -0800576 public void setRoleNamesFromController(@NonNull List<String> roleNames) {
577 Preconditions.checkNotNull(roleNames, "roleNames cannot be null");
578 try {
579 mService.setRoleNamesFromController(roleNames);
580 } catch (RemoteException e) {
581 throw e.rethrowFromSystemServer();
582 }
583 }
584
585 /**
Hai Zhang87ed09a2018-10-22 10:43:31 -0700586 * Add a specific application to the holders of a role, only modifying records inside
587 * {@link RoleManager}. Should only be called from
Hai Zhanga4959e52019-03-06 12:21:07 -0800588 * {@link android.app.role.RoleControllerService}.
Hai Zhang87ed09a2018-10-22 10:43:31 -0700589 * <p>
590 * <strong>Note:</strong> Using this API requires holding
Hai Zhang8e60a8f2018-11-20 11:21:09 -0800591 * {@link #PERMISSION_MANAGE_ROLES_FROM_CONTROLLER}.
Hai Zhang87ed09a2018-10-22 10:43:31 -0700592 *
593 * @param roleName the name of the role to add the role holder for
594 * @param packageName the package name of the application to add to the role holders
595 *
596 * @return whether the operation was successful, and will also be {@code true} if a matching
597 * role holder is already found.
598 *
Hai Zhang87ed09a2018-10-22 10:43:31 -0700599 * @see #getRoleHolders(String)
600 * @see #removeRoleHolderFromController(String, String)
601 *
602 * @hide
603 */
Hai Zhang8e60a8f2018-11-20 11:21:09 -0800604 @RequiresPermission(PERMISSION_MANAGE_ROLES_FROM_CONTROLLER)
Hai Zhang87ed09a2018-10-22 10:43:31 -0700605 @SystemApi
Hai Zhang22435862019-02-26 16:57:47 -0800606 @TestApi
Hai Zhang87ed09a2018-10-22 10:43:31 -0700607 public boolean addRoleHolderFromController(@NonNull String roleName,
608 @NonNull String packageName) {
609 Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
610 Preconditions.checkStringNotEmpty(packageName, "packageName cannot be null or empty");
611 try {
612 return mService.addRoleHolderFromController(roleName, packageName);
613 } catch (RemoteException e) {
614 throw e.rethrowFromSystemServer();
615 }
616 }
617
618 /**
619 * Remove a specific application from the holders of a role, only modifying records inside
620 * {@link RoleManager}. Should only be called from
Hai Zhanga4959e52019-03-06 12:21:07 -0800621 * {@link android.app.role.RoleControllerService}.
Hai Zhang87ed09a2018-10-22 10:43:31 -0700622 * <p>
623 * <strong>Note:</strong> Using this API requires holding
Hai Zhang8e60a8f2018-11-20 11:21:09 -0800624 * {@link #PERMISSION_MANAGE_ROLES_FROM_CONTROLLER}.
Hai Zhang87ed09a2018-10-22 10:43:31 -0700625 *
626 * @param roleName the name of the role to remove the role holder for
627 * @param packageName the package name of the application to remove from the role holders
628 *
629 * @return whether the operation was successful, and will also be {@code true} if no matching
630 * role holder was found to remove.
631 *
Hai Zhang87ed09a2018-10-22 10:43:31 -0700632 * @see #getRoleHolders(String)
633 * @see #addRoleHolderFromController(String, String)
634 *
635 * @hide
636 */
Hai Zhang8e60a8f2018-11-20 11:21:09 -0800637 @RequiresPermission(PERMISSION_MANAGE_ROLES_FROM_CONTROLLER)
Hai Zhang87ed09a2018-10-22 10:43:31 -0700638 @SystemApi
Hai Zhang22435862019-02-26 16:57:47 -0800639 @TestApi
Hai Zhang87ed09a2018-10-22 10:43:31 -0700640 public boolean removeRoleHolderFromController(@NonNull String roleName,
641 @NonNull String packageName) {
642 Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
643 Preconditions.checkStringNotEmpty(packageName, "packageName cannot be null or empty");
644 try {
645 return mService.removeRoleHolderFromController(roleName, packageName);
646 } catch (RemoteException e) {
647 throw e.rethrowFromSystemServer();
648 }
649 }
650
Eugene Suslaa2a80322018-12-12 17:09:38 -0800651 /**
652 * Returns the list of all roles that the given package is currently holding
653 *
654 * @param packageName the package name
655 * @return the list of role names
656 *
657 * @hide
658 */
Hai Zhang22435862019-02-26 16:57:47 -0800659 @NonNull
Eugene Suslaa2a80322018-12-12 17:09:38 -0800660 @RequiresPermission(PERMISSION_MANAGE_ROLES_FROM_CONTROLLER)
661 @SystemApi
Hai Zhang22435862019-02-26 16:57:47 -0800662 @TestApi
Eugene Suslaa2a80322018-12-12 17:09:38 -0800663 public List<String> getHeldRolesFromController(@NonNull String packageName) {
664 Preconditions.checkStringNotEmpty(packageName, "packageName cannot be null or empty");
665 try {
666 return mService.getHeldRolesFromController(packageName);
667 } catch (RemoteException e) {
668 throw e.rethrowFromSystemServer();
669 }
670 }
671
Eugene Susla4ab95112018-12-17 14:45:11 -0800672 /**
673 * Allows getting the role holder for {@link #ROLE_SMS} without
674 * {@link Manifest.permission#OBSERVE_ROLE_HOLDERS}, as required by
675 * {@link android.provider.Telephony.Sms#getDefaultSmsPackage(Context)}
676 *
677 * @hide
678 */
679 @Nullable
680 public String getDefaultSmsPackage(@UserIdInt int userId) {
681 try {
682 return mService.getDefaultSmsPackage(userId);
683 } catch (RemoteException e) {
684 throw e.rethrowFromSystemServer();
685 }
686 }
687
Hai Zhang31d06ba2018-12-06 18:14:42 -0800688 private static class OnRoleHoldersChangedListenerDelegate
689 extends IOnRoleHoldersChangedListener.Stub {
690
691 @NonNull
692 private final Executor mExecutor;
693 @NonNull
694 private final OnRoleHoldersChangedListener mListener;
695
696 OnRoleHoldersChangedListenerDelegate(@NonNull Executor executor,
697 @NonNull OnRoleHoldersChangedListener listener) {
698 mExecutor = executor;
699 mListener = listener;
700 }
701
702 @Override
703 public void onRoleHoldersChanged(@NonNull String roleName, @UserIdInt int userId) {
704 long token = Binder.clearCallingIdentity();
705 try {
706 mExecutor.execute(PooledLambda.obtainRunnable(
707 OnRoleHoldersChangedListener::onRoleHoldersChanged, mListener, roleName,
708 UserHandle.of(userId)));
709 } finally {
710 Binder.restoreCallingIdentity(token);
711 }
712 }
713 }
Hai Zhangb7776682018-09-25 15:10:57 -0700714}