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