Loading api/current.txt +1 −0 Original line number Diff line number Diff line Loading @@ -23663,6 +23663,7 @@ package android.os { method public deprecated void setUserRestriction(java.lang.String, boolean); method public deprecated void setUserRestrictions(android.os.Bundle); method public deprecated void setUserRestrictions(android.os.Bundle, android.os.UserHandle); field public static final java.lang.String ALLOW_PARENT_APP_LINKING = "allow_parent_app_linking"; field public static final java.lang.String DISALLOW_ADD_USER = "no_add_user"; field public static final java.lang.String DISALLOW_ADJUST_VOLUME = "no_adjust_volume"; field public static final java.lang.String DISALLOW_APPS_CONTROL = "no_control_apps"; api/system-current.txt +1 −0 Original line number Diff line number Diff line Loading @@ -25608,6 +25608,7 @@ package android.os { method public deprecated void setUserRestriction(java.lang.String, boolean); method public deprecated void setUserRestrictions(android.os.Bundle); method public deprecated void setUserRestrictions(android.os.Bundle, android.os.UserHandle); field public static final java.lang.String ALLOW_PARENT_APP_LINKING = "allow_parent_app_linking"; field public static final java.lang.String DISALLOW_ADD_USER = "no_add_user"; field public static final java.lang.String DISALLOW_ADJUST_VOLUME = "no_adjust_volume"; field public static final java.lang.String DISALLOW_APPS_CONTROL = "no_control_apps"; core/java/android/os/UserManager.java +16 −0 Original line number Diff line number Diff line Loading @@ -448,6 +448,22 @@ public class UserManager { */ public static final String DISALLOW_RECORD_AUDIO = "no_record_audio"; /** * This user restriction has an effect only in a managed profile. * If set: * Intent filters of activities in the parent profile with action * {@link android.content.Intent#ACTION_VIEW}, * category {@link android.content.Intent#CATEGORY_BROWSABLE}, scheme http or https, and which * define a host can handle intents from the managed profile. * The default value is <code>false</code>. * * <p/>Key for user restrictions. * <p/>Type: Boolean * @see #setUserRestrictions(Bundle) * @see #getUserRestrictions() */ public static final String ALLOW_PARENT_APP_LINKING = "allow_parent_app_linking"; /** * Application restriction key that is used to indicate the pending arrival * of real restrictions for the app. Loading services/core/java/com/android/server/pm/PackageManagerService.java +121 −11 Original line number Diff line number Diff line Loading @@ -4118,9 +4118,26 @@ public class PackageManagerService extends IPackageManager.Stub { if (matches.get(i).getTargetUserId() == targetUserId) return true; } } if (hasWebURI(intent)) { // cross-profile app linking works only towards the parent. final UserInfo parent = getProfileParent(sourceUserId); synchronized(mPackages) { return getCrossProfileDomainPreferredLpr(intent, resolvedType, 0, sourceUserId, parent.id) != null; } } return false; } private UserInfo getProfileParent(int userId) { final long identity = Binder.clearCallingIdentity(); try { return sUserManager.getProfileParent(userId); } finally { Binder.restoreCallingIdentity(identity); } } private List<CrossProfileIntentFilter> getMatchingCrossProfileIntentFilters(Intent intent, String resolvedType, int userId) { CrossProfileIntentResolver resolver = mSettings.mCrossProfileIntentResolvers.get(userId); Loading Loading @@ -4161,11 +4178,11 @@ public class PackageManagerService extends IPackageManager.Stub { List<CrossProfileIntentFilter> matchingFilters = getMatchingCrossProfileIntentFilters(intent, resolvedType, userId); // Check for results that need to skip the current profile. ResolveInfo resolveInfo = querySkipCurrentProfileIntents(matchingFilters, intent, ResolveInfo xpResolveInfo = querySkipCurrentProfileIntents(matchingFilters, intent, resolvedType, flags, userId); if (resolveInfo != null && isUserEnabled(resolveInfo.targetUserId)) { if (xpResolveInfo != null && isUserEnabled(xpResolveInfo.targetUserId)) { List<ResolveInfo> result = new ArrayList<ResolveInfo>(1); result.add(resolveInfo); result.add(xpResolveInfo); return filterIfNotPrimaryUser(result, userId); } Loading @@ -4174,15 +4191,36 @@ public class PackageManagerService extends IPackageManager.Stub { intent, resolvedType, flags, userId); // Check for cross profile results. resolveInfo = queryCrossProfileIntents( xpResolveInfo = queryCrossProfileIntents( matchingFilters, intent, resolvedType, flags, userId); if (resolveInfo != null && isUserEnabled(resolveInfo.targetUserId)) { result.add(resolveInfo); if (xpResolveInfo != null && isUserEnabled(xpResolveInfo.targetUserId)) { result.add(xpResolveInfo); Collections.sort(result, mResolvePrioritySorter); } result = filterIfNotPrimaryUser(result, userId); if (result.size() > 1 && hasWebURI(intent)) { return filterCandidatesWithDomainPreferedActivitiesLPr(flags, result); if (hasWebURI(intent)) { CrossProfileDomainInfo xpDomainInfo = null; final UserInfo parent = getProfileParent(userId); if (parent != null) { xpDomainInfo = getCrossProfileDomainPreferredLpr(intent, resolvedType, flags, userId, parent.id); } if (xpDomainInfo != null) { if (xpResolveInfo != null) { // If we didn't remove it, the cross-profile ResolveInfo would be twice // in the result. result.remove(xpResolveInfo); } if (result.size() == 0) { result.add(xpDomainInfo.resolveInfo); return result; } } else if (result.size() <= 1) { return result; } result = filterCandidatesWithDomainPreferredActivitiesLPr(flags, result, xpDomainInfo); Collections.sort(result, mResolvePrioritySorter); } return result; } Loading @@ -4197,6 +4235,67 @@ public class PackageManagerService extends IPackageManager.Stub { } } private static class CrossProfileDomainInfo { /* ResolveInfo for IntentForwarderActivity to send the intent to the other profile */ ResolveInfo resolveInfo; /* Best domain verification status of the activities found in the other profile */ int bestDomainVerificationStatus; } private CrossProfileDomainInfo getCrossProfileDomainPreferredLpr(Intent intent, String resolvedType, int flags, int sourceUserId, int parentUserId) { if (!sUserManager.hasUserRestriction(UserManager.ALLOW_PARENT_APP_LINKING, sourceUserId)) { return null; } List<ResolveInfo> resultTargetUser = mActivities.queryIntent(intent, resolvedType, flags, parentUserId); if (resultTargetUser == null || resultTargetUser.isEmpty()) { return null; } CrossProfileDomainInfo result = null; int size = resultTargetUser.size(); for (int i = 0; i < size; i++) { ResolveInfo riTargetUser = resultTargetUser.get(i); // Intent filter verification is only for filters that specify a host. So don't return // those that handle all web uris. if (riTargetUser.handleAllWebDataURI) { continue; } String packageName = riTargetUser.activityInfo.packageName; PackageSetting ps = mSettings.mPackages.get(packageName); if (ps == null) { continue; } int status = getDomainVerificationStatusLPr(ps, parentUserId); if (result == null) { result = new CrossProfileDomainInfo(); result.resolveInfo = createForwardingResolveInfo(null, sourceUserId, parentUserId); result.bestDomainVerificationStatus = status; } else { result.bestDomainVerificationStatus = bestDomainVerificationStatus(status, result.bestDomainVerificationStatus); } } return result; } /** * Verification statuses are ordered from the worse to the best, except for * INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER, which is the worse. */ private int bestDomainVerificationStatus(int status1, int status2) { if (status1 == INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER) { return status2; } if (status2 == INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER) { return status1; } return (int) MathUtils.max(status1, status2); } private boolean isUserEnabled(int userId) { long callingId = Binder.clearCallingIdentity(); try { Loading Loading @@ -4236,8 +4335,8 @@ public class PackageManagerService extends IPackageManager.Stub { return scheme.equals(IntentFilter.SCHEME_HTTP) || scheme.equals(IntentFilter.SCHEME_HTTPS); } private List<ResolveInfo> filterCandidatesWithDomainPreferedActivitiesLPr( int flags, List<ResolveInfo> candidates) { private List<ResolveInfo> filterCandidatesWithDomainPreferredActivitiesLPr( int flags, List<ResolveInfo> candidates, CrossProfileDomainInfo xpDomainInfo) { if (DEBUG_PREFERRED) { Slog.v("TAG", "Filtering results with prefered activities. Candidates count: " + candidates.size()); Loading Loading @@ -4277,12 +4376,23 @@ public class PackageManagerService extends IPackageManager.Stub { } } } // First try to add the "always" if there is any // First try to add the "always" resolution for the current user if there is any if (alwaysList.size() > 0) { result.addAll(alwaysList); // if there is an "always" for the parent user, add it. } else if (xpDomainInfo != null && xpDomainInfo.bestDomainVerificationStatus == INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS) { result.add(xpDomainInfo.resolveInfo); } else { // Add all undefined Apps as we want them to appear in the Disambiguation dialog. result.addAll(undefinedList); if (xpDomainInfo != null && ( xpDomainInfo.bestDomainVerificationStatus == INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED || xpDomainInfo.bestDomainVerificationStatus == INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK)) { result.add(xpDomainInfo.resolveInfo); } // Also add Browsers (all of them or only the default one) if ((flags & MATCH_ALL) != 0) { result.addAll(matchAllList); Loading services/core/java/com/android/server/pm/UserManagerService.java +2 −0 Original line number Diff line number Diff line Loading @@ -972,6 +972,7 @@ public class UserManagerService extends IUserManager.Stub { writeBoolean(serializer, restrictions, UserManager.DISALLOW_OUTGOING_BEAM); writeBoolean(serializer, restrictions, UserManager.DISALLOW_WALLPAPER); writeBoolean(serializer, restrictions, UserManager.DISALLOW_SAFE_BOOT); writeBoolean(serializer, restrictions, UserManager.ALLOW_PARENT_APP_LINKING); serializer.endTag(null, TAG_RESTRICTIONS); } Loading Loading @@ -1103,6 +1104,7 @@ public class UserManagerService extends IUserManager.Stub { readBoolean(parser, restrictions, UserManager.DISALLOW_OUTGOING_BEAM); readBoolean(parser, restrictions, UserManager.DISALLOW_WALLPAPER); readBoolean(parser, restrictions, UserManager.DISALLOW_SAFE_BOOT); readBoolean(parser, restrictions, UserManager.ALLOW_PARENT_APP_LINKING); } private void readBoolean(XmlPullParser parser, Bundle restrictions, Loading Loading
api/current.txt +1 −0 Original line number Diff line number Diff line Loading @@ -23663,6 +23663,7 @@ package android.os { method public deprecated void setUserRestriction(java.lang.String, boolean); method public deprecated void setUserRestrictions(android.os.Bundle); method public deprecated void setUserRestrictions(android.os.Bundle, android.os.UserHandle); field public static final java.lang.String ALLOW_PARENT_APP_LINKING = "allow_parent_app_linking"; field public static final java.lang.String DISALLOW_ADD_USER = "no_add_user"; field public static final java.lang.String DISALLOW_ADJUST_VOLUME = "no_adjust_volume"; field public static final java.lang.String DISALLOW_APPS_CONTROL = "no_control_apps";
api/system-current.txt +1 −0 Original line number Diff line number Diff line Loading @@ -25608,6 +25608,7 @@ package android.os { method public deprecated void setUserRestriction(java.lang.String, boolean); method public deprecated void setUserRestrictions(android.os.Bundle); method public deprecated void setUserRestrictions(android.os.Bundle, android.os.UserHandle); field public static final java.lang.String ALLOW_PARENT_APP_LINKING = "allow_parent_app_linking"; field public static final java.lang.String DISALLOW_ADD_USER = "no_add_user"; field public static final java.lang.String DISALLOW_ADJUST_VOLUME = "no_adjust_volume"; field public static final java.lang.String DISALLOW_APPS_CONTROL = "no_control_apps";
core/java/android/os/UserManager.java +16 −0 Original line number Diff line number Diff line Loading @@ -448,6 +448,22 @@ public class UserManager { */ public static final String DISALLOW_RECORD_AUDIO = "no_record_audio"; /** * This user restriction has an effect only in a managed profile. * If set: * Intent filters of activities in the parent profile with action * {@link android.content.Intent#ACTION_VIEW}, * category {@link android.content.Intent#CATEGORY_BROWSABLE}, scheme http or https, and which * define a host can handle intents from the managed profile. * The default value is <code>false</code>. * * <p/>Key for user restrictions. * <p/>Type: Boolean * @see #setUserRestrictions(Bundle) * @see #getUserRestrictions() */ public static final String ALLOW_PARENT_APP_LINKING = "allow_parent_app_linking"; /** * Application restriction key that is used to indicate the pending arrival * of real restrictions for the app. Loading
services/core/java/com/android/server/pm/PackageManagerService.java +121 −11 Original line number Diff line number Diff line Loading @@ -4118,9 +4118,26 @@ public class PackageManagerService extends IPackageManager.Stub { if (matches.get(i).getTargetUserId() == targetUserId) return true; } } if (hasWebURI(intent)) { // cross-profile app linking works only towards the parent. final UserInfo parent = getProfileParent(sourceUserId); synchronized(mPackages) { return getCrossProfileDomainPreferredLpr(intent, resolvedType, 0, sourceUserId, parent.id) != null; } } return false; } private UserInfo getProfileParent(int userId) { final long identity = Binder.clearCallingIdentity(); try { return sUserManager.getProfileParent(userId); } finally { Binder.restoreCallingIdentity(identity); } } private List<CrossProfileIntentFilter> getMatchingCrossProfileIntentFilters(Intent intent, String resolvedType, int userId) { CrossProfileIntentResolver resolver = mSettings.mCrossProfileIntentResolvers.get(userId); Loading Loading @@ -4161,11 +4178,11 @@ public class PackageManagerService extends IPackageManager.Stub { List<CrossProfileIntentFilter> matchingFilters = getMatchingCrossProfileIntentFilters(intent, resolvedType, userId); // Check for results that need to skip the current profile. ResolveInfo resolveInfo = querySkipCurrentProfileIntents(matchingFilters, intent, ResolveInfo xpResolveInfo = querySkipCurrentProfileIntents(matchingFilters, intent, resolvedType, flags, userId); if (resolveInfo != null && isUserEnabled(resolveInfo.targetUserId)) { if (xpResolveInfo != null && isUserEnabled(xpResolveInfo.targetUserId)) { List<ResolveInfo> result = new ArrayList<ResolveInfo>(1); result.add(resolveInfo); result.add(xpResolveInfo); return filterIfNotPrimaryUser(result, userId); } Loading @@ -4174,15 +4191,36 @@ public class PackageManagerService extends IPackageManager.Stub { intent, resolvedType, flags, userId); // Check for cross profile results. resolveInfo = queryCrossProfileIntents( xpResolveInfo = queryCrossProfileIntents( matchingFilters, intent, resolvedType, flags, userId); if (resolveInfo != null && isUserEnabled(resolveInfo.targetUserId)) { result.add(resolveInfo); if (xpResolveInfo != null && isUserEnabled(xpResolveInfo.targetUserId)) { result.add(xpResolveInfo); Collections.sort(result, mResolvePrioritySorter); } result = filterIfNotPrimaryUser(result, userId); if (result.size() > 1 && hasWebURI(intent)) { return filterCandidatesWithDomainPreferedActivitiesLPr(flags, result); if (hasWebURI(intent)) { CrossProfileDomainInfo xpDomainInfo = null; final UserInfo parent = getProfileParent(userId); if (parent != null) { xpDomainInfo = getCrossProfileDomainPreferredLpr(intent, resolvedType, flags, userId, parent.id); } if (xpDomainInfo != null) { if (xpResolveInfo != null) { // If we didn't remove it, the cross-profile ResolveInfo would be twice // in the result. result.remove(xpResolveInfo); } if (result.size() == 0) { result.add(xpDomainInfo.resolveInfo); return result; } } else if (result.size() <= 1) { return result; } result = filterCandidatesWithDomainPreferredActivitiesLPr(flags, result, xpDomainInfo); Collections.sort(result, mResolvePrioritySorter); } return result; } Loading @@ -4197,6 +4235,67 @@ public class PackageManagerService extends IPackageManager.Stub { } } private static class CrossProfileDomainInfo { /* ResolveInfo for IntentForwarderActivity to send the intent to the other profile */ ResolveInfo resolveInfo; /* Best domain verification status of the activities found in the other profile */ int bestDomainVerificationStatus; } private CrossProfileDomainInfo getCrossProfileDomainPreferredLpr(Intent intent, String resolvedType, int flags, int sourceUserId, int parentUserId) { if (!sUserManager.hasUserRestriction(UserManager.ALLOW_PARENT_APP_LINKING, sourceUserId)) { return null; } List<ResolveInfo> resultTargetUser = mActivities.queryIntent(intent, resolvedType, flags, parentUserId); if (resultTargetUser == null || resultTargetUser.isEmpty()) { return null; } CrossProfileDomainInfo result = null; int size = resultTargetUser.size(); for (int i = 0; i < size; i++) { ResolveInfo riTargetUser = resultTargetUser.get(i); // Intent filter verification is only for filters that specify a host. So don't return // those that handle all web uris. if (riTargetUser.handleAllWebDataURI) { continue; } String packageName = riTargetUser.activityInfo.packageName; PackageSetting ps = mSettings.mPackages.get(packageName); if (ps == null) { continue; } int status = getDomainVerificationStatusLPr(ps, parentUserId); if (result == null) { result = new CrossProfileDomainInfo(); result.resolveInfo = createForwardingResolveInfo(null, sourceUserId, parentUserId); result.bestDomainVerificationStatus = status; } else { result.bestDomainVerificationStatus = bestDomainVerificationStatus(status, result.bestDomainVerificationStatus); } } return result; } /** * Verification statuses are ordered from the worse to the best, except for * INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER, which is the worse. */ private int bestDomainVerificationStatus(int status1, int status2) { if (status1 == INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER) { return status2; } if (status2 == INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER) { return status1; } return (int) MathUtils.max(status1, status2); } private boolean isUserEnabled(int userId) { long callingId = Binder.clearCallingIdentity(); try { Loading Loading @@ -4236,8 +4335,8 @@ public class PackageManagerService extends IPackageManager.Stub { return scheme.equals(IntentFilter.SCHEME_HTTP) || scheme.equals(IntentFilter.SCHEME_HTTPS); } private List<ResolveInfo> filterCandidatesWithDomainPreferedActivitiesLPr( int flags, List<ResolveInfo> candidates) { private List<ResolveInfo> filterCandidatesWithDomainPreferredActivitiesLPr( int flags, List<ResolveInfo> candidates, CrossProfileDomainInfo xpDomainInfo) { if (DEBUG_PREFERRED) { Slog.v("TAG", "Filtering results with prefered activities. Candidates count: " + candidates.size()); Loading Loading @@ -4277,12 +4376,23 @@ public class PackageManagerService extends IPackageManager.Stub { } } } // First try to add the "always" if there is any // First try to add the "always" resolution for the current user if there is any if (alwaysList.size() > 0) { result.addAll(alwaysList); // if there is an "always" for the parent user, add it. } else if (xpDomainInfo != null && xpDomainInfo.bestDomainVerificationStatus == INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS) { result.add(xpDomainInfo.resolveInfo); } else { // Add all undefined Apps as we want them to appear in the Disambiguation dialog. result.addAll(undefinedList); if (xpDomainInfo != null && ( xpDomainInfo.bestDomainVerificationStatus == INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED || xpDomainInfo.bestDomainVerificationStatus == INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK)) { result.add(xpDomainInfo.resolveInfo); } // Also add Browsers (all of them or only the default one) if ((flags & MATCH_ALL) != 0) { result.addAll(matchAllList); Loading
services/core/java/com/android/server/pm/UserManagerService.java +2 −0 Original line number Diff line number Diff line Loading @@ -972,6 +972,7 @@ public class UserManagerService extends IUserManager.Stub { writeBoolean(serializer, restrictions, UserManager.DISALLOW_OUTGOING_BEAM); writeBoolean(serializer, restrictions, UserManager.DISALLOW_WALLPAPER); writeBoolean(serializer, restrictions, UserManager.DISALLOW_SAFE_BOOT); writeBoolean(serializer, restrictions, UserManager.ALLOW_PARENT_APP_LINKING); serializer.endTag(null, TAG_RESTRICTIONS); } Loading Loading @@ -1103,6 +1104,7 @@ public class UserManagerService extends IUserManager.Stub { readBoolean(parser, restrictions, UserManager.DISALLOW_OUTGOING_BEAM); readBoolean(parser, restrictions, UserManager.DISALLOW_WALLPAPER); readBoolean(parser, restrictions, UserManager.DISALLOW_SAFE_BOOT); readBoolean(parser, restrictions, UserManager.ALLOW_PARENT_APP_LINKING); } private void readBoolean(XmlPullParser parser, Bundle restrictions, Loading