1 /* 2 * Copyright (C) 2017 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 package android.content.pm; 17 18 import static android.app.admin.DevicePolicyResources.Strings.Core.SWITCH_TO_PERSONAL_LABEL; 19 import static android.app.admin.DevicePolicyResources.Strings.Core.SWITCH_TO_WORK_LABEL; 20 21 import android.annotation.NonNull; 22 import android.annotation.Nullable; 23 import android.annotation.RequiresPermission; 24 import android.annotation.SystemApi; 25 import android.annotation.TestApi; 26 import android.app.Activity; 27 import android.app.AppOpsManager.Mode; 28 import android.app.admin.DevicePolicyManager; 29 import android.content.ComponentName; 30 import android.content.Context; 31 import android.content.Intent; 32 import android.content.res.Resources; 33 import android.graphics.drawable.Drawable; 34 import android.net.Uri; 35 import android.os.Bundle; 36 import android.os.RemoteException; 37 import android.os.UserHandle; 38 import android.os.UserManager; 39 import android.provider.Settings; 40 41 import com.android.internal.R; 42 import com.android.internal.util.UserIcons; 43 44 import java.util.Collection; 45 import java.util.List; 46 import java.util.Set; 47 import java.util.stream.Collectors; 48 49 /** 50 * Class for handling cross profile operations. Apps can use this class to interact with its 51 * instance in any profile that is in {@link #getTargetUserProfiles()}. For example, app can 52 * use this class to start its main activity in managed profile. 53 */ 54 public class CrossProfileApps { 55 56 /** 57 * Broadcast signalling that the receiving app's permission to interact across profiles has 58 * changed. This includes the user, admin, or OEM changing their consent such that the 59 * permission for the app to interact across profiles has changed. 60 * 61 * <p>This broadcast is not sent when other circumstances result in a change to being able to 62 * interact across profiles in practice, such as the profile being turned off or removed, apps 63 * being uninstalled, etc. The methods {@link #canInteractAcrossProfiles()} and {@link 64 * #canRequestInteractAcrossProfiles()} can be used by apps prior to attempting to interact 65 * across profiles or attempting to request user consent to interact across profiles. 66 * 67 * <p>Apps that have set the {@code android:crossProfile} manifest attribute to {@code true} 68 * can receive this broadcast in manifest broadcast receivers. Otherwise, it can only be 69 * received by dynamically-registered broadcast receivers. 70 */ 71 public static final String ACTION_CAN_INTERACT_ACROSS_PROFILES_CHANGED = 72 "android.content.pm.action.CAN_INTERACT_ACROSS_PROFILES_CHANGED"; 73 74 private final Context mContext; 75 private final ICrossProfileApps mService; 76 private final UserManager mUserManager; 77 private final Resources mResources; 78 79 /** @hide */ CrossProfileApps(Context context, ICrossProfileApps service)80 public CrossProfileApps(Context context, ICrossProfileApps service) { 81 mContext = context; 82 mService = service; 83 mUserManager = context.getSystemService(UserManager.class); 84 mResources = context.getResources(); 85 } 86 87 /** 88 * Starts the specified main activity of the caller package in the specified profile. 89 * 90 * @param component The ComponentName of the activity to launch, it must be exported and has 91 * action {@link android.content.Intent#ACTION_MAIN}, category 92 * {@link android.content.Intent#CATEGORY_LAUNCHER}. Otherwise, SecurityException will 93 * be thrown. 94 * @param targetUser The UserHandle of the profile, must be one of the users returned by 95 * {@link #getTargetUserProfiles()}, otherwise a {@link SecurityException} will 96 * be thrown. 97 */ startMainActivity(@onNull ComponentName component, @NonNull UserHandle targetUser)98 public void startMainActivity(@NonNull ComponentName component, 99 @NonNull UserHandle targetUser) { 100 try { 101 mService.startActivityAsUser( 102 mContext.getIApplicationThread(), 103 mContext.getPackageName(), 104 mContext.getAttributionTag(), 105 component, 106 targetUser.getIdentifier(), 107 true, 108 null, 109 null); 110 } catch (RemoteException ex) { 111 throw ex.rethrowFromSystemServer(); 112 } 113 } 114 115 /** 116 * Starts the specified main activity of the caller package in the specified profile, launching 117 * in the specified activity. 118 * 119 * @param component The ComponentName of the activity to launch, it must be exported and has 120 * action {@link android.content.Intent#ACTION_MAIN}, category 121 * {@link android.content.Intent#CATEGORY_LAUNCHER}. Otherwise, SecurityException will 122 * be thrown. 123 * @param targetUser The UserHandle of the profile, must be one of the users returned by 124 * {@link #getTargetUserProfiles()}, otherwise a {@link SecurityException} will 125 * be thrown. 126 * @param callingActivity The activity to start the new activity from for the purposes of 127 * deciding which task the new activity should belong to. If {@code null}, the activity 128 * will always be started in a new task. 129 * @param options The activity options or {@code null}. See {@link android.app.ActivityOptions}. 130 */ startMainActivity(@onNull ComponentName component, @NonNull UserHandle targetUser, @Nullable Activity callingActivity, @Nullable Bundle options)131 public void startMainActivity(@NonNull ComponentName component, 132 @NonNull UserHandle targetUser, 133 @Nullable Activity callingActivity, 134 @Nullable Bundle options) { 135 try { 136 mService.startActivityAsUser( 137 mContext.getIApplicationThread(), 138 mContext.getPackageName(), 139 mContext.getAttributionTag(), 140 component, 141 targetUser.getIdentifier(), 142 true, 143 callingActivity != null ? callingActivity.getActivityToken() : null, 144 options); 145 } catch (RemoteException ex) { 146 throw ex.rethrowFromSystemServer(); 147 } 148 } 149 150 /** 151 * Starts the specified activity of the caller package in the specified profile. 152 * 153 * <p>The caller must have the {@link android.Manifest.permission#INTERACT_ACROSS_PROFILES}, 154 * {@code android.Manifest.permission#INTERACT_ACROSS_USERS}, or {@code 155 * android.Manifest.permission#INTERACT_ACROSS_USERS_FULL} permission. Both the caller and 156 * target user profiles must be in the same profile group. The target user must be a valid user 157 * returned from {@link #getTargetUserProfiles()}. 158 * 159 * @param intent The intent to launch. A component in the caller package must be specified. 160 * @param targetUser The {@link UserHandle} of the profile; must be one of the users returned by 161 * {@link #getTargetUserProfiles()} if different to the calling user, otherwise a 162 * {@link SecurityException} will be thrown. 163 * @param callingActivity The activity to start the new activity from for the purposes of 164 * passing back any result and deciding which task the new activity should belong to. If 165 * {@code null}, the activity will always be started in a new task and no result will be 166 * returned. 167 */ 168 @RequiresPermission(anyOf = { 169 android.Manifest.permission.INTERACT_ACROSS_PROFILES, 170 android.Manifest.permission.INTERACT_ACROSS_USERS}) startActivity( @onNull Intent intent, @NonNull UserHandle targetUser, @Nullable Activity callingActivity)171 public void startActivity( 172 @NonNull Intent intent, 173 @NonNull UserHandle targetUser, 174 @Nullable Activity callingActivity) { 175 startActivity(intent, targetUser, callingActivity, /* options= */ null); 176 } 177 178 /** 179 * Starts the specified activity of the caller package in the specified profile. 180 * 181 * <p>The caller must have the {@link android.Manifest.permission#INTERACT_ACROSS_PROFILES}, 182 * {@code android.Manifest.permission#INTERACT_ACROSS_USERS}, or {@code 183 * android.Manifest.permission#INTERACT_ACROSS_USERS_FULL} permission. Both the caller and 184 * target user profiles must be in the same profile group. The target user must be a valid user 185 * returned from {@link #getTargetUserProfiles()}. 186 * 187 * @param intent The intent to launch. A component in the caller package must be specified. 188 * @param targetUser The {@link UserHandle} of the profile; must be one of the users returned by 189 * {@link #getTargetUserProfiles()} if different to the calling user, otherwise a 190 * {@link SecurityException} will be thrown. 191 * @param callingActivity The activity to start the new activity from for the purposes of 192 * passing back any result and deciding which task the new activity should belong to. If 193 * {@code null}, the activity will always be started in a new task and no result will be 194 * returned. 195 * @param options The activity options or {@code null}. See {@link android.app.ActivityOptions}. 196 */ 197 @RequiresPermission(anyOf = { 198 android.Manifest.permission.INTERACT_ACROSS_PROFILES, 199 android.Manifest.permission.INTERACT_ACROSS_USERS}) startActivity( @onNull Intent intent, @NonNull UserHandle targetUser, @Nullable Activity callingActivity, @Nullable Bundle options)200 public void startActivity( 201 @NonNull Intent intent, 202 @NonNull UserHandle targetUser, 203 @Nullable Activity callingActivity, 204 @Nullable Bundle options) { 205 try { 206 mService.startActivityAsUserByIntent( 207 mContext.getIApplicationThread(), 208 mContext.getPackageName(), 209 mContext.getAttributionTag(), 210 intent, 211 targetUser.getIdentifier(), 212 callingActivity != null ? callingActivity.getActivityToken() : null, 213 options); 214 } catch (RemoteException ex) { 215 throw ex.rethrowFromSystemServer(); 216 } 217 } 218 219 /** 220 * Starts the specified activity of the caller package in the specified profile. Unlike 221 * {@link #startMainActivity}, this can start any activity of the caller package, not just 222 * the main activity. 223 * The caller must have the {@link android.Manifest.permission#INTERACT_ACROSS_PROFILES} 224 * or {@link android.Manifest.permission#START_CROSS_PROFILE_ACTIVITIES} 225 * permission and both the caller and target user profiles must be in the same profile group. 226 * 227 * @param component The ComponentName of the activity to launch. It must be exported. 228 * @param targetUser The UserHandle of the profile, must be one of the users returned by 229 * {@link #getTargetUserProfiles()}, otherwise a {@link SecurityException} will 230 * be thrown. 231 * @param callingActivity The activity to start the new activity from for the purposes of 232 * deciding which task the new activity should belong to. If {@code null}, the activity 233 * will always be started in a new task. 234 * @param options The activity options or {@code null}. See {@link android.app.ActivityOptions}. 235 * @hide 236 */ 237 @SystemApi 238 @RequiresPermission(anyOf = { 239 android.Manifest.permission.INTERACT_ACROSS_PROFILES, 240 android.Manifest.permission.START_CROSS_PROFILE_ACTIVITIES}) startActivity( @onNull ComponentName component, @NonNull UserHandle targetUser, @Nullable Activity callingActivity, @Nullable Bundle options)241 public void startActivity( 242 @NonNull ComponentName component, 243 @NonNull UserHandle targetUser, 244 @Nullable Activity callingActivity, 245 @Nullable Bundle options) { 246 try { 247 mService.startActivityAsUser( 248 mContext.getIApplicationThread(), 249 mContext.getPackageName(), 250 mContext.getAttributionTag(), 251 component, 252 targetUser.getIdentifier(), 253 false, 254 callingActivity != null ? callingActivity.getActivityToken() : null, 255 options); 256 } catch (RemoteException ex) { 257 throw ex.rethrowFromSystemServer(); 258 } 259 } 260 261 /** 262 * Starts the specified activity of the caller package in the specified profile. Unlike 263 * {@link #startMainActivity}, this can start any activity of the caller package, not just 264 * the main activity. 265 * The caller must have the {@link android.Manifest.permission#INTERACT_ACROSS_PROFILES} 266 * or {@link android.Manifest.permission#START_CROSS_PROFILE_ACTIVITIES} 267 * permission and both the caller and target user profiles must be in the same profile group. 268 * 269 * @param component The ComponentName of the activity to launch. It must be exported. 270 * @param targetUser The UserHandle of the profile, must be one of the users returned by 271 * {@link #getTargetUserProfiles()}, otherwise a {@link SecurityException} will 272 * be thrown. 273 * @hide 274 */ 275 @SystemApi 276 @RequiresPermission(anyOf = { 277 android.Manifest.permission.INTERACT_ACROSS_PROFILES, 278 android.Manifest.permission.START_CROSS_PROFILE_ACTIVITIES}) startActivity(@onNull ComponentName component, @NonNull UserHandle targetUser)279 public void startActivity(@NonNull ComponentName component, @NonNull UserHandle targetUser) { 280 try { 281 mService.startActivityAsUser(mContext.getIApplicationThread(), 282 mContext.getPackageName(), mContext.getAttributionTag(), component, 283 targetUser.getIdentifier(), false, null, null); 284 } catch (RemoteException ex) { 285 throw ex.rethrowFromSystemServer(); 286 } 287 } 288 289 /** 290 * Return a list of user profiles that that the caller can use when calling other APIs in this 291 * class. 292 * <p> 293 * A user profile would be considered as a valid target user profile, provided that: 294 * <ul> 295 * <li>It gets caller app installed</li> 296 * <li>It is not equal to the calling user</li> 297 * <li>It is in the same profile group of calling user profile</li> 298 * <li>It is enabled</li> 299 * </ul> 300 * 301 * @see UserManager#getUserProfiles() 302 */ getTargetUserProfiles()303 public @NonNull List<UserHandle> getTargetUserProfiles() { 304 try { 305 return mService.getTargetUserProfiles(mContext.getPackageName()); 306 } catch (RemoteException ex) { 307 throw ex.rethrowFromSystemServer(); 308 } 309 } 310 311 /** 312 * Return a label that calling app can show to user for the semantic of profile switching -- 313 * launching its own activity in specified user profile. For example, it may return 314 * "Switch to work" if the given user handle is the managed profile one. 315 * 316 * @param userHandle The UserHandle of the target profile, must be one of the users returned by 317 * {@link #getTargetUserProfiles()}, otherwise a {@link SecurityException} will 318 * be thrown. 319 * @return a label that calling app can show user for the semantic of launching its own 320 * activity in the specified user profile. 321 * 322 * @see #startMainActivity(ComponentName, UserHandle) 323 */ getProfileSwitchingLabel(@onNull UserHandle userHandle)324 public @NonNull CharSequence getProfileSwitchingLabel(@NonNull UserHandle userHandle) { 325 verifyCanAccessUser(userHandle); 326 327 final boolean isManagedProfile = mUserManager.isManagedProfile(userHandle.getIdentifier()); 328 final DevicePolicyManager dpm = mContext.getSystemService(DevicePolicyManager.class); 329 return dpm.getResources().getString( 330 getUpdatableProfileSwitchingLabelId(isManagedProfile), 331 () -> getDefaultProfileSwitchingLabel(isManagedProfile)); 332 } 333 getUpdatableProfileSwitchingLabelId(boolean isManagedProfile)334 private String getUpdatableProfileSwitchingLabelId(boolean isManagedProfile) { 335 return isManagedProfile ? SWITCH_TO_WORK_LABEL : SWITCH_TO_PERSONAL_LABEL; 336 } 337 getDefaultProfileSwitchingLabel(boolean isManagedProfile)338 private String getDefaultProfileSwitchingLabel(boolean isManagedProfile) { 339 final int stringRes = isManagedProfile 340 ? R.string.managed_profile_label : R.string.user_owner_label; 341 return mResources.getString(stringRes); 342 } 343 344 345 /** 346 * Return a drawable that calling app can show to user for the semantic of profile switching -- 347 * launching its own activity in specified user profile. For example, it may return a briefcase 348 * icon if the given user handle is the managed profile one. 349 * 350 * @param userHandle The UserHandle of the target profile, must be one of the users returned by 351 * {@link #getTargetUserProfiles()}, otherwise a {@link SecurityException} will 352 * be thrown. 353 * @return an icon that calling app can show user for the semantic of launching its own 354 * activity in specified user profile. 355 * 356 * @see #startMainActivity(ComponentName, UserHandle) 357 */ getProfileSwitchingIconDrawable(@onNull UserHandle userHandle)358 public @NonNull Drawable getProfileSwitchingIconDrawable(@NonNull UserHandle userHandle) { 359 verifyCanAccessUser(userHandle); 360 361 final boolean isManagedProfile = 362 mUserManager.isManagedProfile(userHandle.getIdentifier()); 363 if (isManagedProfile) { 364 return mContext.getPackageManager().getUserBadgeForDensityNoBackground( 365 userHandle, /* density= */ 0); 366 } else { 367 return UserIcons.getDefaultUserIcon( 368 mResources, UserHandle.USER_SYSTEM, true /* light */); 369 } 370 } 371 372 /** 373 * Returns whether the calling package can request to navigate the user to 374 * the relevant settings page to request user consent to interact across profiles. 375 * 376 * <p>If {@code true}, the navigation intent can be obtained via {@link 377 * #createRequestInteractAcrossProfilesIntent()}. The package can then listen to {@link 378 * #ACTION_CAN_INTERACT_ACROSS_PROFILES_CHANGED} broadcasts. 379 * 380 * <p>Specifically, returns whether the following are all true: 381 * <ul> 382 * <li>{@code UserManager#getEnabledProfileIds(int)} returns at least one other profile for the 383 * calling user.</li> 384 * <li>The calling app has requested 385 * {@code android.Manifest.permission.INTERACT_ACROSS_PROFILES} in its manifest.</li> 386 * <li>The calling app is not a profile owner within the profile group of the calling user.</li> 387 * </ul> 388 * 389 * <p>Note that in order for the user to be able to grant the consent, the requesting package 390 * must be allowlisted by the admin or the OEM and installed in the other profile. If this is 391 * not the case the user will be shown a message explaining why they can't grant the consent. 392 * 393 * <p>Note that user consent could already be granted if given a return value of {@code true}. 394 * The package's current ability to interact across profiles can be checked with {@link 395 * #canInteractAcrossProfiles()}. 396 * 397 * @return true if the calling package can request to interact across profiles. 398 */ canRequestInteractAcrossProfiles()399 public boolean canRequestInteractAcrossProfiles() { 400 try { 401 return mService.canRequestInteractAcrossProfiles(mContext.getPackageName()); 402 } catch (RemoteException ex) { 403 throw ex.rethrowFromSystemServer(); 404 } 405 } 406 407 /** 408 * Returns whether the calling package can interact across profiles. 409 410 * <p>Specifically, returns whether the following are all true: 411 * <ul> 412 * <li>{@link #getTargetUserProfiles()} returns a non-empty list for the calling user.</li> 413 * <li>The user has previously consented to cross-profile communication for the calling 414 * package.</li> 415 * <li>The calling package has either been allowlisted by default by the OEM or has been 416 * explicitly allowlisted by the admin via 417 * {@link android.app.admin.DevicePolicyManager#setCrossProfilePackages(ComponentName, Set)}. 418 * </li> 419 * </ul> 420 * 421 * <p>If {@code false}, the package's current ability to request user consent to interact across 422 * profiles can be checked with {@link #canRequestInteractAcrossProfiles()}. If {@code true}, 423 * user consent can be obtained via {@link #createRequestInteractAcrossProfilesIntent()}. The 424 * package can then listen to {@link #ACTION_CAN_INTERACT_ACROSS_PROFILES_CHANGED} broadcasts. 425 * 426 * @return true if the calling package can interact across profiles. 427 * @throws SecurityException if {@code mContext.getPackageName()} does not belong to the 428 * calling UID. 429 */ canInteractAcrossProfiles()430 public boolean canInteractAcrossProfiles() { 431 try { 432 return mService.canInteractAcrossProfiles(mContext.getPackageName()); 433 } catch (RemoteException ex) { 434 throw ex.rethrowFromSystemServer(); 435 } 436 } 437 438 /** 439 * Returns an {@link Intent} to open the settings page that allows the user to decide whether 440 * the calling app can interact across profiles. 441 * 442 * <p>The method {@link #canRequestInteractAcrossProfiles()} must be returning {@code true}. 443 * 444 * <p>Note that the user may already have given consent and the app may already be able to 445 * interact across profiles, even if {@link #canRequestInteractAcrossProfiles()} is {@code 446 * true}. The current ability to interact across profiles is given by {@link 447 * #canInteractAcrossProfiles()}. 448 * 449 * @return an {@link Intent} to open the settings page that allows the user to decide whether 450 * the app can interact across profiles 451 * 452 * @throws SecurityException if {@code mContext.getPackageName()} does not belong to the 453 * calling UID, or {@link #canRequestInteractAcrossProfiles()} is {@code false}. 454 */ createRequestInteractAcrossProfilesIntent()455 public @NonNull Intent createRequestInteractAcrossProfilesIntent() { 456 if (!canRequestInteractAcrossProfiles()) { 457 throw new SecurityException( 458 "The calling package can not request to interact across profiles."); 459 } 460 final Intent settingsIntent = new Intent(); 461 settingsIntent.setAction(Settings.ACTION_MANAGE_CROSS_PROFILE_ACCESS); 462 final Uri packageUri = Uri.parse("package:" + mContext.getPackageName()); 463 settingsIntent.setData(packageUri); 464 return settingsIntent; 465 } 466 467 /** 468 * Sets the app-op for {@link android.Manifest.permission#INTERACT_ACROSS_PROFILES} that is 469 * configurable by users in Settings. This configures it for the profile group of the calling 470 * package. 471 * 472 * <p>Before calling, check {@link #canConfigureInteractAcrossProfiles(String)} and do not call 473 * if it is {@code false}. If presenting a user interface, do not allow the user to configure 474 * the app-op in that case. 475 * 476 * <p>The underlying app-op {@link android.app.AppOpsManager#OP_INTERACT_ACROSS_PROFILES} should 477 * never be set directly. This method ensures that the app-op is kept in sync for the app across 478 * each user in the profile group and that those apps are sent a broadcast when their ability to 479 * interact across profiles changes. 480 * 481 * <p>This method should be used directly whenever a user's action results in a change in an 482 * app's ability to interact across profiles, as defined by the return value of {@link 483 * #canInteractAcrossProfiles()}. This includes user consent changes in Settings or during 484 * provisioning. 485 * 486 * <p>If other changes could have affected the app's ability to interact across profiles, as 487 * defined by the return value of {@link #canInteractAcrossProfiles()}, such as changes to the 488 * admin or OEM consent whitelists, then {@link #resetInteractAcrossProfilesAppOps(Collection, 489 * Set)} should be used. 490 * 491 * <p>If the caller does not have the {@link android.Manifest.permission 492 * #CONFIGURE_INTERACT_ACROSS_PROFILES} permission, then they must have the permissions that 493 * would have been required to call {@link android.app.AppOpsManager#setMode(int, int, String, 494 * int)}, which includes {@link android.Manifest.permission#MANAGE_APP_OPS_MODES}. 495 * 496 * <p>Also requires either {@link android.Manifest.permission#INTERACT_ACROSS_USERS} or {@link 497 * android.Manifest.permission#INTERACT_ACROSS_USERS_FULL}. 498 * 499 * @hide 500 */ 501 @RequiresPermission( 502 allOf={android.Manifest.permission.CONFIGURE_INTERACT_ACROSS_PROFILES, 503 android.Manifest.permission.INTERACT_ACROSS_USERS}) setInteractAcrossProfilesAppOp(@onNull String packageName, @Mode int newMode)504 public void setInteractAcrossProfilesAppOp(@NonNull String packageName, @Mode int newMode) { 505 try { 506 mService.setInteractAcrossProfilesAppOp(packageName, newMode); 507 } catch (RemoteException ex) { 508 throw ex.rethrowFromSystemServer(); 509 } 510 } 511 512 /** 513 * Returns whether the given package can have its ability to interact across profiles configured 514 * by the user. This means that every other condition to interact across profiles has been set. 515 * 516 * <p>This differs from {@link #canRequestInteractAcrossProfiles()} since it will not return 517 * {@code false} simply when the target profile is disabled. 518 * 519 * @hide 520 */ 521 @TestApi canConfigureInteractAcrossProfiles(@onNull String packageName)522 public boolean canConfigureInteractAcrossProfiles(@NonNull String packageName) { 523 try { 524 return mService.canConfigureInteractAcrossProfiles(packageName); 525 } catch (RemoteException ex) { 526 throw ex.rethrowFromSystemServer(); 527 } 528 } 529 530 /** 531 * Returns {@code true} if the given package has requested 532 * {@link android.Manifest.permission#INTERACT_ACROSS_PROFILES} and the user has at least one 533 * other profile in the same profile group. 534 * 535 * <p>This differs from {@link #canConfigureInteractAcrossProfiles(String)} since it will 536 * not return {@code false} if the app is not allowlisted or not installed in the other profile. 537 * 538 * <p>Note that platform-signed apps that are automatically granted the permission and are not 539 * allowlisted by the OEM will not be included in this list. 540 * 541 * @hide 542 */ canUserAttemptToConfigureInteractAcrossProfiles(String packageName)543 public boolean canUserAttemptToConfigureInteractAcrossProfiles(String packageName) { 544 try { 545 return mService.canUserAttemptToConfigureInteractAcrossProfiles(packageName); 546 } catch (RemoteException ex) { 547 throw ex.rethrowFromSystemServer(); 548 } 549 } 550 /** 551 * For each of the packages defined in {@code previousCrossProfilePackages} but not included in 552 * {@code newCrossProfilePackages}, resets the app-op for {@link android.Manifest.permission 553 * #INTERACT_ACROSS_PROFILES} back to its default value if it can no longer be configured by 554 * users in Settings, as defined by {@link #canConfigureInteractAcrossProfiles(String)}. 555 * 556 * <p>This method should be used whenever an app's ability to interact across profiles could 557 * have changed as a result of non-user actions, such as changes to admin or OEM consent 558 * whitelists. 559 * 560 * <p>If the caller does not have the {@link android.Manifest.permission 561 * #CONFIGURE_INTERACT_ACROSS_PROFILES} permission, then they must have the permissions that 562 * would have been required to call {@link android.app.AppOpsManager#setMode(int, int, String, 563 * int)}, which includes {@link android.Manifest.permission#MANAGE_APP_OPS_MODES}. 564 * 565 * <p>Also requires either {@link android.Manifest.permission#INTERACT_ACROSS_USERS} or {@link 566 * android.Manifest.permission#INTERACT_ACROSS_USERS_FULL}. 567 * 568 * @hide 569 */ 570 @RequiresPermission( 571 allOf={android.Manifest.permission.CONFIGURE_INTERACT_ACROSS_PROFILES, 572 android.Manifest.permission.INTERACT_ACROSS_USERS}) resetInteractAcrossProfilesAppOps( @onNull Collection<String> previousCrossProfilePackages, @NonNull Set<String> newCrossProfilePackages)573 public void resetInteractAcrossProfilesAppOps( 574 @NonNull Collection<String> previousCrossProfilePackages, 575 @NonNull Set<String> newCrossProfilePackages) { 576 if (previousCrossProfilePackages.isEmpty()) { 577 return; 578 } 579 final List<String> unsetCrossProfilePackages = 580 previousCrossProfilePackages.stream() 581 .filter(packageName -> !newCrossProfilePackages.contains(packageName)) 582 .collect(Collectors.toList()); 583 if (unsetCrossProfilePackages.isEmpty()) { 584 return; 585 } 586 try { 587 mService.resetInteractAcrossProfilesAppOps(unsetCrossProfilePackages); 588 } catch (RemoteException ex) { 589 throw ex.rethrowFromSystemServer(); 590 } 591 } 592 593 /** 594 * Clears the app-op for {@link android.Manifest.permission#INTERACT_ACROSS_PROFILES} back to 595 * its default value for every package on the device. 596 * 597 * <p>This method can be used to ensure that app-op state is not left around on existing users 598 * for previously-configured profiles. 599 * 600 * <p>If the caller does not have the {@link android.Manifest.permission 601 * #CONFIGURE_INTERACT_ACROSS_PROFILES} permission, then they must have the permissions that 602 * would have been required to call {@link android.app.AppOpsManager#setMode(int, int, String, 603 * int)}, which includes {@link android.Manifest.permission#MANAGE_APP_OPS_MODES}. 604 * 605 * <p>Also requires either {@link android.Manifest.permission#INTERACT_ACROSS_USERS} or {@link 606 * android.Manifest.permission#INTERACT_ACROSS_USERS_FULL}. 607 * 608 * @hide 609 */ 610 @RequiresPermission( 611 allOf={android.Manifest.permission.CONFIGURE_INTERACT_ACROSS_PROFILES, 612 android.Manifest.permission.INTERACT_ACROSS_USERS}) clearInteractAcrossProfilesAppOps()613 public void clearInteractAcrossProfilesAppOps() { 614 try { 615 mService.clearInteractAcrossProfilesAppOps(); 616 } catch (RemoteException ex) { 617 throw ex.rethrowFromSystemServer(); 618 } 619 } 620 verifyCanAccessUser(UserHandle userHandle)621 private void verifyCanAccessUser(UserHandle userHandle) { 622 if (!getTargetUserProfiles().contains(userHandle)) { 623 throw new SecurityException("Not allowed to access " + userHandle); 624 } 625 } 626 } 627