1 /*
2  * Copyright (C) 2021 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.tv.settings.library.settingslib;
18 
19 import static android.app.admin.DevicePolicyManager.KEYGUARD_DISABLE_FEATURES_NONE;
20 import static android.app.admin.DevicePolicyManager.PROFILE_KEYGUARD_FEATURES_AFFECT_OWNER;
21 
22 import android.annotation.NonNull;
23 import android.annotation.Nullable;
24 import android.annotation.UserIdInt;
25 import android.app.AppGlobals;
26 import android.app.admin.DevicePolicyManager;
27 import android.content.ComponentName;
28 import android.content.Context;
29 import android.content.pm.IPackageManager;
30 import android.content.pm.PackageManager;
31 import android.content.pm.UserInfo;
32 import android.content.res.TypedArray;
33 import android.graphics.drawable.Drawable;
34 import android.os.RemoteException;
35 import android.os.UserHandle;
36 import android.os.UserManager;
37 
38 import androidx.annotation.VisibleForTesting;
39 
40 import com.android.internal.widget.LockPatternUtils;
41 
42 import java.util.List;
43 
44 /**
45  * Utility class to host methods usable in adding a restricted padlock icon and showing admin
46  * support message dialog.
47  */
48 public class RestrictedLockUtilsInternal extends RestrictedLockUtils {
49 
50     private static final String LOG_TAG = "RestrictedLockUtils";
51 
52     /**
53      * @return drawables for displaying with settings that are locked by a device admin.
54      */
getRestrictedPadlock(Context context)55     public static Drawable getRestrictedPadlock(Context context) {
56         Drawable restrictedPadlock = context.getDrawable(android.R.drawable.ic_info);
57         final int iconSize = context.getResources().getDimensionPixelSize(
58                 android.R.dimen.config_restrictedIconSize);
59 
60         TypedArray ta = context.obtainStyledAttributes(new int[]{android.R.attr.colorAccent});
61         int colorAccent = ta.getColor(0, 0);
62         ta.recycle();
63         restrictedPadlock.setTint(colorAccent);
64 
65         restrictedPadlock.setBounds(0, 0, iconSize, iconSize);
66         return restrictedPadlock;
67     }
68 
69     /**
70      * Checks if a restriction is enforced on a user and returns the enforced admin and
71      * admin userId.
72      *
73      * @param userRestriction Restriction to check
74      * @param userId          User which we need to check if restriction is enforced on.
75      * @return EnforcedAdmin Object containing the enforced admin component and admin user details,
76      * or {@code null} If the restriction is not set. If the restriction is set by both device owner
77      * and profile owner, then the admin component will be set to {@code null} and userId to
78      * {@link UserHandle#USER_NULL}.
79      */
checkIfRestrictionEnforced(Context context, String userRestriction, int userId)80     public static EnforcedAdmin checkIfRestrictionEnforced(Context context,
81             String userRestriction, int userId) {
82         final DevicePolicyManager dpm = context.getSystemService(DevicePolicyManager.class);
83         if (dpm == null) {
84             return null;
85         }
86 
87         final UserManager um = UserManager.get(context);
88         final List<UserManager.EnforcingUser> enforcingUsers =
89                 um.getUserRestrictionSources(userRestriction, UserHandle.of(userId));
90 
91         if (enforcingUsers.isEmpty()) {
92             // Restriction is not enforced.
93             return null;
94         } else if (enforcingUsers.size() > 1) {
95             return EnforcedAdmin.createDefaultEnforcedAdminWithRestriction(userRestriction);
96         }
97 
98         final int restrictionSource = enforcingUsers.get(0).getUserRestrictionSource();
99         final int adminUserId = enforcingUsers.get(0).getUserHandle().getIdentifier();
100         if (restrictionSource == UserManager.RESTRICTION_SOURCE_PROFILE_OWNER) {
101             // Check if it is a profile owner of the user under consideration.
102             if (adminUserId == userId) {
103                 return getProfileOwner(context, userRestriction, adminUserId);
104             } else {
105                 // Check if it is a profile owner of a managed profile of the current user.
106                 // Otherwise it is in a separate user and we return a default EnforcedAdmin.
107                 final UserInfo parentUser = um.getProfileParent(adminUserId);
108                 return (parentUser != null && parentUser.id == userId)
109                         ? getProfileOwner(context, userRestriction, adminUserId)
110                         : EnforcedAdmin.createDefaultEnforcedAdminWithRestriction(userRestriction);
111             }
112         } else if (restrictionSource == UserManager.RESTRICTION_SOURCE_DEVICE_OWNER) {
113             // When the restriction is enforced by device owner, return the device owner admin only
114             // if the admin is for the {@param userId} otherwise return a default EnforcedAdmin.
115             return adminUserId == userId
116                     ? getDeviceOwner(context, userRestriction)
117                     : EnforcedAdmin.createDefaultEnforcedAdminWithRestriction(userRestriction);
118         }
119 
120         // If the restriction is enforced by system then return null.
121         return null;
122     }
123 
hasBaseUserRestriction(Context context, String userRestriction, int userId)124     public static boolean hasBaseUserRestriction(Context context,
125             String userRestriction, int userId) {
126         final UserManager um = (UserManager) context.getSystemService(Context.USER_SERVICE);
127         return um.hasBaseUserRestriction(userRestriction, UserHandle.of(userId));
128     }
129 
130     /**
131      * Checks whether keyguard features are disabled by policy.
132      *
133      * @param context          {@link Context} for the calling user.
134      * @param keyguardFeatures Any one of keyguard features that can be
135      *                         disabled by {@link DevicePolicyManager#setKeyguardDisabledFeatures}.
136      * @param userId           User to check enforced admin status for.
137      * @return EnforcedAdmin Object containing the enforced admin component and admin user details,
138      * or {@code null} If the notification features are not disabled. If the restriction is set by
139      * multiple admins, then the admin component will be set to {@code null} and userId to
140      * {@link UserHandle#USER_NULL}.
141      */
checkIfKeyguardFeaturesDisabled(Context context, int keyguardFeatures, final @UserIdInt int userId)142     public static EnforcedAdmin checkIfKeyguardFeaturesDisabled(Context context,
143             int keyguardFeatures, final @UserIdInt int userId) {
144         final LockSettingCheck check = (dpm, admin, checkUser) -> {
145             int effectiveFeatures = dpm.getKeyguardDisabledFeatures(admin, checkUser);
146             if (checkUser != userId) {
147                 effectiveFeatures &= PROFILE_KEYGUARD_FEATURES_AFFECT_OWNER;
148             }
149             return (effectiveFeatures & keyguardFeatures) != KEYGUARD_DISABLE_FEATURES_NONE;
150         };
151         if (UserManager.get(context).getUserInfo(userId).isManagedProfile()) {
152             DevicePolicyManager dpm = context.getSystemService(DevicePolicyManager.class);
153             return findEnforcedAdmin(dpm.getActiveAdminsAsUser(userId), dpm, userId, check);
154         }
155         return checkForLockSetting(context, userId, check);
156     }
157 
158     /**
159      * @return the UserHandle for a userId. Return null for USER_NULL
160      */
getUserHandleOf(@serIdInt int userId)161     private static UserHandle getUserHandleOf(@UserIdInt int userId) {
162         if (userId == UserHandle.USER_NULL) {
163             return null;
164         } else {
165             return UserHandle.of(userId);
166         }
167     }
168 
169     /**
170      * Filter a set of device admins based on a predicate {@code check}. This is equivalent to
171      * {@code admins.stream().filter(check).map(x → new EnforcedAdmin(admin, userId)} except it's
172      * returning a zero/one/many-type thing.
173      *
174      * @param admins set of candidate device admins identified by {@link ComponentName}.
175      * @param userId user to create the resultant {@link EnforcedAdmin} as.
176      * @param check  filter predicate.
177      * @return {@code null} if none of the {@param admins} match.
178      * An {@link EnforcedAdmin} if exactly one of the admins matches.
179      * Otherwise, {@link EnforcedAdmin#MULTIPLE_ENFORCED_ADMIN} for multiple matches.
180      */
181     @Nullable
findEnforcedAdmin(@ullable List<ComponentName> admins, @NonNull DevicePolicyManager dpm, @UserIdInt int userId, @NonNull LockSettingCheck check)182     private static EnforcedAdmin findEnforcedAdmin(@Nullable List<ComponentName> admins,
183             @NonNull DevicePolicyManager dpm, @UserIdInt int userId,
184             @NonNull LockSettingCheck check) {
185         if (admins == null) {
186             return null;
187         }
188 
189         final UserHandle user = getUserHandleOf(userId);
190         EnforcedAdmin enforcedAdmin = null;
191         for (ComponentName admin : admins) {
192             if (check.isEnforcing(dpm, admin, userId)) {
193                 if (enforcedAdmin == null) {
194                     enforcedAdmin = new EnforcedAdmin(admin, user);
195                 } else {
196                     return EnforcedAdmin.MULTIPLE_ENFORCED_ADMIN;
197                 }
198             }
199         }
200         return enforcedAdmin;
201     }
202 
checkIfUninstallBlocked(Context context, String packageName, int userId)203     public static EnforcedAdmin checkIfUninstallBlocked(Context context,
204             String packageName, int userId) {
205         EnforcedAdmin allAppsControlDisallowedAdmin = checkIfRestrictionEnforced(context,
206                 UserManager.DISALLOW_APPS_CONTROL, userId);
207         if (allAppsControlDisallowedAdmin != null) {
208             return allAppsControlDisallowedAdmin;
209         }
210         EnforcedAdmin allAppsUninstallDisallowedAdmin = checkIfRestrictionEnforced(context,
211                 UserManager.DISALLOW_UNINSTALL_APPS, userId);
212         if (allAppsUninstallDisallowedAdmin != null) {
213             return allAppsUninstallDisallowedAdmin;
214         }
215         IPackageManager ipm = AppGlobals.getPackageManager();
216         try {
217             if (ipm.getBlockUninstallForUser(packageName, userId)) {
218                 return getProfileOrDeviceOwner(context, getUserHandleOf(userId));
219             }
220         } catch (RemoteException e) {
221             // Nothing to do
222         }
223         return null;
224     }
225 
226     /**
227      * Check if an application is suspended.
228      *
229      * @return EnforcedAdmin Object containing the enforced admin component and admin user details,
230      * or {@code null} if the application is not suspended.
231      */
checkIfApplicationIsSuspended(Context context, String packageName, int userId)232     public static EnforcedAdmin checkIfApplicationIsSuspended(Context context, String packageName,
233             int userId) {
234         IPackageManager ipm = AppGlobals.getPackageManager();
235         try {
236             if (ipm.isPackageSuspendedForUser(packageName, userId)) {
237                 return getProfileOrDeviceOwner(context, getUserHandleOf(userId));
238             }
239         } catch (RemoteException | IllegalArgumentException e) {
240             // Nothing to do
241         }
242         return null;
243     }
244 
checkIfInputMethodDisallowed(Context context, String packageName, int userId)245     public static EnforcedAdmin checkIfInputMethodDisallowed(Context context,
246             String packageName, int userId) {
247         DevicePolicyManager dpm = context.getSystemService(DevicePolicyManager.class);
248         if (dpm == null) {
249             return null;
250         }
251         EnforcedAdmin admin = getProfileOrDeviceOwner(context, getUserHandleOf(userId));
252         boolean permitted = true;
253         if (admin != null) {
254             permitted = dpm.isInputMethodPermittedByAdmin(admin.component,
255                     packageName, userId);
256         }
257 
258         boolean permittedByParentAdmin = true;
259         EnforcedAdmin profileAdmin = null;
260         int managedProfileId = getManagedProfileId(context, userId);
261         if (managedProfileId != UserHandle.USER_NULL) {
262             profileAdmin = getProfileOrDeviceOwner(context, getUserHandleOf(managedProfileId));
263             // If the device is an organization-owned device with a managed profile, the
264             // managedProfileId will be used instead of the affected userId. This is because
265             // isInputMethodPermittedByAdmin is called on the parent DPM instance, which will
266             // return results affecting the personal profile.
267             if (profileAdmin != null && dpm.isOrganizationOwnedDeviceWithManagedProfile()) {
268                 DevicePolicyManager parentDpm = sProxy.getParentProfileInstance(dpm,
269                         UserManager.get(context).getUserInfo(managedProfileId));
270                 permittedByParentAdmin = parentDpm.isInputMethodPermittedByAdmin(
271                         profileAdmin.component, packageName, managedProfileId);
272             }
273         }
274         if (!permitted && !permittedByParentAdmin) {
275             return EnforcedAdmin.MULTIPLE_ENFORCED_ADMIN;
276         } else if (!permitted) {
277             return admin;
278         } else if (!permittedByParentAdmin) {
279             return profileAdmin;
280         }
281         return null;
282     }
283 
284     /**
285      * @param userId user id of a managed profile.
286      * @return is remote contacts search disallowed.
287      */
checkIfRemoteContactSearchDisallowed(Context context, int userId)288     public static EnforcedAdmin checkIfRemoteContactSearchDisallowed(Context context, int userId) {
289         DevicePolicyManager dpm = context.getSystemService(DevicePolicyManager.class);
290         if (dpm == null) {
291             return null;
292         }
293         EnforcedAdmin admin = getProfileOwner(context, userId);
294         if (admin == null) {
295             return null;
296         }
297         UserHandle userHandle = UserHandle.of(userId);
298         if (dpm.getCrossProfileContactsSearchDisabled(userHandle)
299                 && dpm.getCrossProfileCallerIdDisabled(userHandle)) {
300             return admin;
301         }
302         return null;
303     }
304 
checkIfAccessibilityServiceDisallowed(Context context, String packageName, int userId)305     public static EnforcedAdmin checkIfAccessibilityServiceDisallowed(Context context,
306             String packageName, int userId) {
307         DevicePolicyManager dpm = context.getSystemService(DevicePolicyManager.class);
308         if (dpm == null) {
309             return null;
310         }
311         EnforcedAdmin admin = getProfileOrDeviceOwner(context, getUserHandleOf(userId));
312         boolean permitted = true;
313         if (admin != null) {
314             permitted = dpm.isAccessibilityServicePermittedByAdmin(admin.component,
315                     packageName, userId);
316         }
317         int managedProfileId = getManagedProfileId(context, userId);
318         EnforcedAdmin profileAdmin = getProfileOrDeviceOwner(context,
319                 getUserHandleOf(managedProfileId));
320         boolean permittedByProfileAdmin = true;
321         if (profileAdmin != null) {
322             permittedByProfileAdmin = dpm.isAccessibilityServicePermittedByAdmin(
323                     profileAdmin.component, packageName, managedProfileId);
324         }
325         if (!permitted && !permittedByProfileAdmin) {
326             return EnforcedAdmin.MULTIPLE_ENFORCED_ADMIN;
327         } else if (!permitted) {
328             return admin;
329         } else if (!permittedByProfileAdmin) {
330             return profileAdmin;
331         }
332         return null;
333     }
334 
getManagedProfileId(Context context, int userId)335     private static int getManagedProfileId(Context context, int userId) {
336         UserManager um = (UserManager) context.getSystemService(Context.USER_SERVICE);
337         List<UserInfo> userProfiles = um.getProfiles(userId);
338         for (UserInfo uInfo : userProfiles) {
339             if (uInfo.id == userId) {
340                 continue;
341             }
342             if (uInfo.isManagedProfile()) {
343                 return uInfo.id;
344             }
345         }
346         return UserHandle.USER_NULL;
347     }
348 
349     /**
350      * Check if account management for a specific type of account is disabled by admin.
351      * Only a profile or device owner can disable account management. So, we check if account
352      * management is disabled and return profile or device owner on the calling user.
353      *
354      * @return EnforcedAdmin Object containing the enforced admin component and admin user details,
355      * or {@code null} if the account management is not disabled.
356      */
checkIfAccountManagementDisabled(Context context, String accountType, int userId)357     public static EnforcedAdmin checkIfAccountManagementDisabled(Context context,
358             String accountType, int userId) {
359         if (accountType == null) {
360             return null;
361         }
362         DevicePolicyManager dpm = context.getSystemService(DevicePolicyManager.class);
363         PackageManager pm = context.getPackageManager();
364         if (!pm.hasSystemFeature(PackageManager.FEATURE_DEVICE_ADMIN) || dpm == null) {
365             return null;
366         }
367         boolean isAccountTypeDisabled = false;
368         String[] disabledTypes = dpm.getAccountTypesWithManagementDisabledAsUser(userId);
369         for (String type : disabledTypes) {
370             if (accountType.equals(type)) {
371                 isAccountTypeDisabled = true;
372                 break;
373             }
374         }
375         if (!isAccountTypeDisabled) {
376             return null;
377         }
378         return getProfileOrDeviceOwner(context, getUserHandleOf(userId));
379     }
380 
381     /**
382      * Check if USB data signaling (except from charging functions) is disabled by the admin.
383      * Only a device owner or a profile owner on an organization-owned managed profile can disable
384      * USB data signaling.
385      *
386      * @return EnforcedAdmin Object containing the enforced admin component and admin user details,
387      * or {@code null} if USB data signaling is not disabled.
388      */
checkIfUsbDataSignalingIsDisabled(Context context, int userId)389     public static EnforcedAdmin checkIfUsbDataSignalingIsDisabled(Context context, int userId) {
390         DevicePolicyManager dpm = context.getSystemService(DevicePolicyManager.class);
391         if (dpm == null || dpm.isUsbDataSignalingEnabled()) {
392             return null;
393         } else {
394             EnforcedAdmin admin = getProfileOrDeviceOwner(context, getUserHandleOf(userId));
395             int managedProfileId = getManagedProfileId(context, userId);
396             if (admin == null && managedProfileId != UserHandle.USER_NULL) {
397                 admin = getProfileOrDeviceOwner(context, getUserHandleOf(managedProfileId));
398             }
399             return admin;
400         }
401     }
402 
403     /**
404      * Check if {@param packageName} is restricted by the profile or device owner from using
405      * metered data.
406      *
407      * @return EnforcedAdmin object containing the enforced admin component and admin user details,
408      * or {@code null} if the {@param packageName} is not restricted.
409      */
checkIfMeteredDataRestricted(Context context, String packageName, int userId)410     public static EnforcedAdmin checkIfMeteredDataRestricted(Context context,
411             String packageName, int userId) {
412         final EnforcedAdmin enforcedAdmin = getProfileOrDeviceOwner(context,
413                 getUserHandleOf(userId));
414         if (enforcedAdmin == null) {
415             return null;
416         }
417 
418         final DevicePolicyManager dpm = context.getSystemService(DevicePolicyManager.class);
419         return dpm.isMeteredDataDisabledPackageForUser(enforcedAdmin.component, packageName, userId)
420                 ? enforcedAdmin : null;
421     }
422 
423     /**
424      * Checks if an admin has enforced minimum password quality or complexity requirements on the
425      * given user.
426      *
427      * @return EnforcedAdmin Object containing the enforced admin component and admin user details,
428      * or {@code null} if no quality requirements are set. If the requirements are set by
429      * multiple device admins, then the admin component will be set to {@code null} and userId to
430      * {@link UserHandle#USER_NULL}.
431      */
checkIfPasswordQualityIsSet(Context context, int userId)432     public static EnforcedAdmin checkIfPasswordQualityIsSet(Context context, int userId) {
433         final LockSettingCheck check =
434                 (DevicePolicyManager dpm, ComponentName admin, @UserIdInt int checkUser) ->
435                         dpm.getPasswordQuality(admin, checkUser)
436                                 > DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
437 
438         final DevicePolicyManager dpm = context.getSystemService(DevicePolicyManager.class);
439         if (dpm == null) {
440             return null;
441         }
442 
443         LockPatternUtils lockPatternUtils = new LockPatternUtils(context);
444         final int aggregatedComplexity = dpm.getAggregatedPasswordComplexityForUser(userId);
445         if (aggregatedComplexity > DevicePolicyManager.PASSWORD_COMPLEXITY_NONE) {
446             // First, check if there's a Device Owner. If so, then only it can apply password
447             // complexity requiremnts (there can be no secondary profiles).
448             final UserHandle deviceOwnerUser = dpm.getDeviceOwnerUser();
449             if (deviceOwnerUser != null) {
450                 return new EnforcedAdmin(dpm.getDeviceOwnerComponentOnAnyUser(), deviceOwnerUser);
451             }
452 
453             // The complexity could be enforced by a Profile Owner - either in the current user
454             // or the current user is the parent user that is affected by the profile owner.
455             for (UserInfo userInfo : UserManager.get(context).getProfiles(userId)) {
456                 final ComponentName profileOwnerComponent = dpm.getProfileOwnerAsUser(userInfo.id);
457                 if (profileOwnerComponent != null) {
458                     return new EnforcedAdmin(profileOwnerComponent, getUserHandleOf(userInfo.id));
459                 }
460             }
461 
462             // Should not get here: A Device Owner or Profile Owner should be found.
463             throw new IllegalStateException(
464                     String.format("Could not find admin enforcing complexity %d for user %d",
465                             aggregatedComplexity, userId));
466         }
467 
468         if (sProxy.isSeparateProfileChallengeEnabled(lockPatternUtils, userId)) {
469             // userId is managed profile and has a separate challenge, only consider
470             // the admins in that user.
471             final List<ComponentName> admins = dpm.getActiveAdminsAsUser(userId);
472             if (admins == null) {
473                 return null;
474             }
475             EnforcedAdmin enforcedAdmin = null;
476             final UserHandle user = getUserHandleOf(userId);
477             for (ComponentName admin : admins) {
478                 if (check.isEnforcing(dpm, admin, userId)) {
479                     if (enforcedAdmin == null) {
480                         enforcedAdmin = new EnforcedAdmin(admin, user);
481                     } else {
482                         return EnforcedAdmin.MULTIPLE_ENFORCED_ADMIN;
483                     }
484                 }
485             }
486             return enforcedAdmin;
487         } else {
488             return checkForLockSetting(context, userId, check);
489         }
490     }
491 
492     /**
493      * Checks if any admin has set maximum time to lock.
494      *
495      * @return EnforcedAdmin Object containing the enforced admin component and admin user details,
496      * or {@code null} if no admin has set this restriction. If multiple admins has set this, then
497      * the admin component will be set to {@code null} and userId to {@link UserHandle#USER_NULL}
498      */
checkIfMaximumTimeToLockIsSet(Context context)499     public static EnforcedAdmin checkIfMaximumTimeToLockIsSet(Context context) {
500         return checkForLockSetting(context, UserHandle.myUserId(),
501                 (DevicePolicyManager dpm, ComponentName admin, @UserIdInt int userId) ->
502                         dpm.getMaximumTimeToLock(admin, userId) > 0);
503     }
504 
505     private interface LockSettingCheck {
isEnforcing(DevicePolicyManager dpm, ComponentName admin, @UserIdInt int userId)506         boolean isEnforcing(DevicePolicyManager dpm, ComponentName admin, @UserIdInt int userId);
507     }
508 
509     /**
510      * Checks whether any of the user's profiles enforce the lock setting. A managed profile is only
511      * included if it does not have a separate challenge.
512      *
513      * The user identified by {@param userId} is always included.
514      */
checkForLockSetting( Context context, @UserIdInt int userId, LockSettingCheck check)515     private static EnforcedAdmin checkForLockSetting(
516             Context context, @UserIdInt int userId, LockSettingCheck check) {
517         final DevicePolicyManager dpm = context.getSystemService(DevicePolicyManager.class);
518         if (dpm == null) {
519             return null;
520         }
521         final LockPatternUtils lockPatternUtils = new LockPatternUtils(context);
522         EnforcedAdmin enforcedAdmin = null;
523         // Return all admins for this user and the profiles that are visible from this
524         // user that do not use a separate work challenge.
525         for (UserInfo userInfo : UserManager.get(context).getProfiles(userId)) {
526             final List<ComponentName> admins = dpm.getActiveAdminsAsUser(userInfo.id);
527             if (admins == null) {
528                 continue;
529             }
530             final UserHandle user = getUserHandleOf(userInfo.id);
531             final boolean isSeparateProfileChallengeEnabled =
532                     sProxy.isSeparateProfileChallengeEnabled(lockPatternUtils, userInfo.id);
533             for (ComponentName admin : admins) {
534                 if (!isSeparateProfileChallengeEnabled) {
535                     if (check.isEnforcing(dpm, admin, userInfo.id)) {
536                         if (enforcedAdmin == null) {
537                             enforcedAdmin = new EnforcedAdmin(admin, user);
538                         } else {
539                             return EnforcedAdmin.MULTIPLE_ENFORCED_ADMIN;
540                         }
541                         // This same admins could have set policies both on the managed profile
542                         // and on the parent. So, if the admin has set the policy on the
543                         // managed profile here, we don't need to further check if that admin
544                         // has set policy on the parent admin.
545                         continue;
546                     }
547                 }
548                 if (userInfo.isManagedProfile()) {
549                     // If userInfo.id is a managed profile, we also need to look at
550                     // the policies set on the parent.
551                     DevicePolicyManager parentDpm = sProxy.getParentProfileInstance(dpm, userInfo);
552                     if (check.isEnforcing(parentDpm, admin, userInfo.id)) {
553                         if (enforcedAdmin == null) {
554                             enforcedAdmin = new EnforcedAdmin(admin, user);
555                         } else {
556                             return EnforcedAdmin.MULTIPLE_ENFORCED_ADMIN;
557                         }
558                     }
559                 }
560             }
561         }
562         return enforcedAdmin;
563     }
564 
getDeviceOwner(Context context)565     public static EnforcedAdmin getDeviceOwner(Context context) {
566         return getDeviceOwner(context, null);
567     }
568 
getDeviceOwner(Context context, String enforcedRestriction)569     private static EnforcedAdmin getDeviceOwner(Context context, String enforcedRestriction) {
570         final DevicePolicyManager dpm = context.getSystemService(DevicePolicyManager.class);
571         if (dpm == null) {
572             return null;
573         }
574         ComponentName adminComponent = dpm.getDeviceOwnerComponentOnAnyUser();
575         if (adminComponent != null) {
576             return new EnforcedAdmin(
577                     adminComponent, enforcedRestriction, dpm.getDeviceOwnerUser());
578         }
579         return null;
580     }
581 
getProfileOwner(Context context, int userId)582     private static EnforcedAdmin getProfileOwner(Context context, int userId) {
583         return getProfileOwner(context, null, userId);
584     }
585 
getProfileOwner( Context context, String enforcedRestriction, int userId)586     private static EnforcedAdmin getProfileOwner(
587             Context context, String enforcedRestriction, int userId) {
588         if (userId == UserHandle.USER_NULL) {
589             return null;
590         }
591         final DevicePolicyManager dpm = context.getSystemService(DevicePolicyManager.class);
592         if (dpm == null) {
593             return null;
594         }
595         ComponentName adminComponent = dpm.getProfileOwnerAsUser(userId);
596         if (adminComponent != null) {
597             return new EnforcedAdmin(adminComponent, enforcedRestriction, getUserHandleOf(userId));
598         }
599         return null;
600     }
601 
isAdminInCurrentUserOrProfile(Context context, ComponentName admin)602     public static boolean isAdminInCurrentUserOrProfile(Context context, ComponentName admin) {
603         DevicePolicyManager dpm = context.getSystemService(DevicePolicyManager.class);
604         UserManager um = UserManager.get(context);
605         for (UserInfo userInfo : um.getProfiles(UserHandle.myUserId())) {
606             if (dpm.isAdminActiveAsUser(admin, userInfo.id)) {
607                 return true;
608             }
609         }
610         return false;
611     }
612 
613 
614     /**
615      * Static {@link LockPatternUtils} and {@link DevicePolicyManager} wrapper for testing purposes.
616      * {@link LockPatternUtils} is an internal API not supported by robolectric.
617      * {@link DevicePolicyManager} has a {@code getProfileParent} not yet suppored by robolectric.
618      */
619     @VisibleForTesting
620     static Proxy sProxy = new Proxy();
621 
622     @VisibleForTesting
623     static class Proxy {
isSeparateProfileChallengeEnabled(LockPatternUtils utils, int userHandle)624         public boolean isSeparateProfileChallengeEnabled(LockPatternUtils utils, int userHandle) {
625             return utils.isSeparateProfileChallengeEnabled(userHandle);
626         }
627 
getParentProfileInstance(DevicePolicyManager dpm, UserInfo ui)628         public DevicePolicyManager getParentProfileInstance(DevicePolicyManager dpm, UserInfo ui) {
629             return dpm.getParentProfileInstance(ui);
630         }
631     }
632 }
633