Home | History | Annotate | Download | only in settingslib
      1 /*
      2  * Copyright (C) 2016 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.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.Intent;
     30 import android.content.pm.IPackageManager;
     31 import android.content.pm.UserInfo;
     32 import android.graphics.drawable.Drawable;
     33 import android.os.RemoteException;
     34 import android.os.UserHandle;
     35 import android.os.UserManager;
     36 import android.provider.Settings;
     37 import android.support.annotation.VisibleForTesting;
     38 import android.text.SpannableStringBuilder;
     39 import android.text.Spanned;
     40 import android.text.style.ForegroundColorSpan;
     41 import android.text.style.ImageSpan;
     42 import android.view.MenuItem;
     43 import android.widget.TextView;
     44 
     45 import com.android.internal.widget.LockPatternUtils;
     46 
     47 import java.util.List;
     48 
     49 /**
     50  * Utility class to host methods usable in adding a restricted padlock icon and showing admin
     51  * support message dialog.
     52  */
     53 public class RestrictedLockUtils {
     54     /**
     55      * @return drawables for displaying with settings that are locked by a device admin.
     56      */
     57     public static Drawable getRestrictedPadlock(Context context) {
     58         Drawable restrictedPadlock = context.getDrawable(R.drawable.ic_info);
     59         final int iconSize = context.getResources().getDimensionPixelSize(
     60                 R.dimen.restricted_icon_size);
     61         restrictedPadlock.setBounds(0, 0, iconSize, iconSize);
     62         return restrictedPadlock;
     63     }
     64 
     65     /**
     66      * Checks if a restriction is enforced on a user and returns the enforced admin and
     67      * admin userId.
     68      *
     69      * @param userRestriction Restriction to check
     70      * @param userId User which we need to check if restriction is enforced on.
     71      * @return EnforcedAdmin Object containing the enforced admin component and admin user details,
     72      * or {@code null} If the restriction is not set. If the restriction is set by both device owner
     73      * and profile owner, then the admin component will be set to {@code null} and userId to
     74      * {@link UserHandle#USER_NULL}.
     75      */
     76     public static EnforcedAdmin checkIfRestrictionEnforced(Context context,
     77             String userRestriction, int userId) {
     78         final DevicePolicyManager dpm = (DevicePolicyManager) context.getSystemService(
     79                 Context.DEVICE_POLICY_SERVICE);
     80         if (dpm == null) {
     81             return null;
     82         }
     83 
     84         final UserManager um = UserManager.get(context);
     85         final List<UserManager.EnforcingUser> enforcingUsers =
     86                 um.getUserRestrictionSources(userRestriction, UserHandle.of(userId));
     87 
     88         if (enforcingUsers.isEmpty()) {
     89             // Restriction is not enforced.
     90             return null;
     91         } else if (enforcingUsers.size() > 1) {
     92             return EnforcedAdmin.MULTIPLE_ENFORCED_ADMIN;
     93         }
     94 
     95         final int restrictionSource = enforcingUsers.get(0).getUserRestrictionSource();
     96         final int adminUserId = enforcingUsers.get(0).getUserHandle().getIdentifier();
     97 
     98         if (restrictionSource == UserManager.RESTRICTION_SOURCE_PROFILE_OWNER) {
     99             // Check if it is a profile owner of the user under consideration.
    100             if (adminUserId == userId) {
    101                 return getProfileOwner(context, adminUserId);
    102             } else {
    103                 // Check if it is a profile owner of a managed profile of the current user.
    104                 // Otherwise it is in a separate user and we return a default EnforcedAdmin.
    105                 final UserInfo parentUser = um.getProfileParent(adminUserId);
    106                 return (parentUser != null && parentUser.id == userId)
    107                         ? getProfileOwner(context, adminUserId)
    108                         : EnforcedAdmin.MULTIPLE_ENFORCED_ADMIN;
    109             }
    110         } else if (restrictionSource == UserManager.RESTRICTION_SOURCE_DEVICE_OWNER) {
    111             // When the restriction is enforced by device owner, return the device owner admin only
    112             // if the admin is for the {@param userId} otherwise return a default EnforcedAdmin.
    113             return adminUserId == userId
    114                     ? getDeviceOwner(context) : EnforcedAdmin.MULTIPLE_ENFORCED_ADMIN;
    115         }
    116 
    117         // If the restriction is enforced by system then return null.
    118         return null;
    119     }
    120 
    121     public static boolean hasBaseUserRestriction(Context context,
    122             String userRestriction, int userId) {
    123         final UserManager um = (UserManager) context.getSystemService(Context.USER_SERVICE);
    124         return um.hasBaseUserRestriction(userRestriction, UserHandle.of(userId));
    125     }
    126 
    127     /**
    128      * Checks whether keyguard features are disabled by policy.
    129      *
    130      * @param context {@link Context} for the calling user.
    131      *
    132      * @param keyguardFeatures Any one of keyguard features that can be
    133      * disabled by {@link android.app.admin.DevicePolicyManager#setKeyguardDisabledFeatures}.
    134      *
    135      * @param userId User to check enforced admin status for.
    136      *
    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      */
    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 =
    153                     (DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE);
    154             return findEnforcedAdmin(dpm.getActiveAdminsAsUser(userId), dpm, userId, check);
    155         }
    156         return checkForLockSetting(context, userId, check);
    157     }
    158 
    159     /**
    160      * Filter a set of device admins based on a predicate {@code check}. This is equivalent to
    161      * {@code admins.stream().filter(check).map(x  new EnforcedAdmin(admin, userId)} except it's
    162      * returning a zero/one/many-type thing.
    163      *
    164      * @param admins set of candidate device admins identified by {@link ComponentName}.
    165      * @param userId user to create the resultant {@link EnforcedAdmin} as.
    166      * @param check filter predicate.
    167      *
    168      * @return {@code null} if none of the {@param admins} match.
    169      *         An {@link EnforcedAdmin} if exactly one of the admins matches.
    170      *         Otherwise, {@link EnforcedAdmin#MULTIPLE_ENFORCED_ADMIN} for multiple matches.
    171      */
    172     @Nullable
    173     private static EnforcedAdmin findEnforcedAdmin(@Nullable List<ComponentName> admins,
    174             @NonNull DevicePolicyManager dpm, @UserIdInt int userId,
    175             @NonNull LockSettingCheck check) {
    176         if (admins == null) {
    177             return null;
    178         }
    179         EnforcedAdmin enforcedAdmin = null;
    180         for (ComponentName admin : admins) {
    181             if (check.isEnforcing(dpm, admin, userId)) {
    182                 if (enforcedAdmin == null) {
    183                     enforcedAdmin = new EnforcedAdmin(admin, userId);
    184                 } else {
    185                     return EnforcedAdmin.MULTIPLE_ENFORCED_ADMIN;
    186                 }
    187             }
    188         }
    189         return enforcedAdmin;
    190     }
    191 
    192     public static EnforcedAdmin checkIfUninstallBlocked(Context context,
    193             String packageName, int userId) {
    194         EnforcedAdmin allAppsControlDisallowedAdmin = checkIfRestrictionEnforced(context,
    195                 UserManager.DISALLOW_APPS_CONTROL, userId);
    196         if (allAppsControlDisallowedAdmin != null) {
    197             return allAppsControlDisallowedAdmin;
    198         }
    199         EnforcedAdmin allAppsUninstallDisallowedAdmin = checkIfRestrictionEnforced(context,
    200                 UserManager.DISALLOW_UNINSTALL_APPS, userId);
    201         if (allAppsUninstallDisallowedAdmin != null) {
    202             return allAppsUninstallDisallowedAdmin;
    203         }
    204         IPackageManager ipm = AppGlobals.getPackageManager();
    205         try {
    206             if (ipm.getBlockUninstallForUser(packageName, userId)) {
    207                 return getProfileOrDeviceOwner(context, userId);
    208             }
    209         } catch (RemoteException e) {
    210             // Nothing to do
    211         }
    212         return null;
    213     }
    214 
    215     /**
    216      * Check if an application is suspended.
    217      *
    218      * @return EnforcedAdmin Object containing the enforced admin component and admin user details,
    219      * or {@code null} if the application is not suspended.
    220      */
    221     public static EnforcedAdmin checkIfApplicationIsSuspended(Context context, String packageName,
    222             int userId) {
    223         IPackageManager ipm = AppGlobals.getPackageManager();
    224         try {
    225             if (ipm.isPackageSuspendedForUser(packageName, userId)) {
    226                 return getProfileOrDeviceOwner(context, userId);
    227             }
    228         } catch (RemoteException | IllegalArgumentException e) {
    229             // Nothing to do
    230         }
    231         return null;
    232     }
    233 
    234     public static EnforcedAdmin checkIfInputMethodDisallowed(Context context,
    235             String packageName, int userId) {
    236         DevicePolicyManager dpm = (DevicePolicyManager) context.getSystemService(
    237                 Context.DEVICE_POLICY_SERVICE);
    238         if (dpm == null) {
    239             return null;
    240         }
    241         EnforcedAdmin admin = getProfileOrDeviceOwner(context, userId);
    242         boolean permitted = true;
    243         if (admin != null) {
    244             permitted = dpm.isInputMethodPermittedByAdmin(admin.component,
    245                     packageName, userId);
    246         }
    247         int managedProfileId = getManagedProfileId(context, userId);
    248         EnforcedAdmin profileAdmin = getProfileOrDeviceOwner(context, managedProfileId);
    249         boolean permittedByProfileAdmin = true;
    250         if (profileAdmin != null) {
    251             permittedByProfileAdmin = dpm.isInputMethodPermittedByAdmin(profileAdmin.component,
    252                     packageName, managedProfileId);
    253         }
    254         if (!permitted && !permittedByProfileAdmin) {
    255             return EnforcedAdmin.MULTIPLE_ENFORCED_ADMIN;
    256         } else if (!permitted) {
    257             return admin;
    258         } else if (!permittedByProfileAdmin) {
    259             return profileAdmin;
    260         }
    261         return null;
    262     }
    263 
    264     /**
    265      * @param context
    266      * @param userId user id of a managed profile.
    267      * @return is remote contacts search disallowed.
    268      */
    269     public static EnforcedAdmin checkIfRemoteContactSearchDisallowed(Context context, int userId) {
    270         DevicePolicyManager dpm = (DevicePolicyManager) context.getSystemService(
    271                 Context.DEVICE_POLICY_SERVICE);
    272         if (dpm == null) {
    273             return null;
    274         }
    275         EnforcedAdmin admin = getProfileOwner(context, userId);
    276         if (admin == null) {
    277             return null;
    278         }
    279         UserHandle userHandle = UserHandle.of(userId);
    280         if (dpm.getCrossProfileContactsSearchDisabled(userHandle)
    281                 && dpm.getCrossProfileCallerIdDisabled(userHandle)) {
    282             return admin;
    283         }
    284         return null;
    285     }
    286 
    287     public static EnforcedAdmin checkIfAccessibilityServiceDisallowed(Context context,
    288             String packageName, int userId) {
    289         DevicePolicyManager dpm = (DevicePolicyManager) context.getSystemService(
    290                 Context.DEVICE_POLICY_SERVICE);
    291         if (dpm == null) {
    292             return null;
    293         }
    294         EnforcedAdmin admin = getProfileOrDeviceOwner(context, userId);
    295         boolean permitted = true;
    296         if (admin != null) {
    297             permitted = dpm.isAccessibilityServicePermittedByAdmin(admin.component,
    298                     packageName, userId);
    299         }
    300         int managedProfileId = getManagedProfileId(context, userId);
    301         EnforcedAdmin profileAdmin = getProfileOrDeviceOwner(context, managedProfileId);
    302         boolean permittedByProfileAdmin = true;
    303         if (profileAdmin != null) {
    304             permittedByProfileAdmin = dpm.isAccessibilityServicePermittedByAdmin(
    305                     profileAdmin.component, packageName, managedProfileId);
    306         }
    307         if (!permitted && !permittedByProfileAdmin) {
    308             return EnforcedAdmin.MULTIPLE_ENFORCED_ADMIN;
    309         } else if (!permitted) {
    310             return admin;
    311         } else if (!permittedByProfileAdmin) {
    312             return profileAdmin;
    313         }
    314         return null;
    315     }
    316 
    317     private static int getManagedProfileId(Context context, int userId) {
    318         UserManager um = (UserManager) context.getSystemService(Context.USER_SERVICE);
    319         List<UserInfo> userProfiles = um.getProfiles(userId);
    320         for (UserInfo uInfo : userProfiles) {
    321             if (uInfo.id == userId) {
    322                 continue;
    323             }
    324             if (uInfo.isManagedProfile()) {
    325                 return uInfo.id;
    326             }
    327         }
    328         return UserHandle.USER_NULL;
    329     }
    330 
    331     /**
    332      * Check if account management for a specific type of account is disabled by admin.
    333      * Only a profile or device owner can disable account management. So, we check if account
    334      * management is disabled and return profile or device owner on the calling user.
    335      *
    336      * @return EnforcedAdmin Object containing the enforced admin component and admin user details,
    337      * or {@code null} if the account management is not disabled.
    338      */
    339     public static EnforcedAdmin checkIfAccountManagementDisabled(Context context,
    340             String accountType, int userId) {
    341         if (accountType == null) {
    342             return null;
    343         }
    344         DevicePolicyManager dpm = (DevicePolicyManager) context.getSystemService(
    345                 Context.DEVICE_POLICY_SERVICE);
    346         if (dpm == null) {
    347             return null;
    348         }
    349         boolean isAccountTypeDisabled = false;
    350         String[] disabledTypes = dpm.getAccountTypesWithManagementDisabledAsUser(userId);
    351         for (String type : disabledTypes) {
    352             if (accountType.equals(type)) {
    353                 isAccountTypeDisabled = true;
    354                 break;
    355             }
    356         }
    357         if (!isAccountTypeDisabled) {
    358             return null;
    359         }
    360         return getProfileOrDeviceOwner(context, userId);
    361     }
    362 
    363     /**
    364      * Checks if {@link android.app.admin.DevicePolicyManager#setAutoTimeRequired} is enforced
    365      * on the device.
    366      *
    367      * @return EnforcedAdmin Object containing the device owner component and
    368      * userId the device owner is running as, or {@code null} setAutoTimeRequired is not enforced.
    369      */
    370     public static EnforcedAdmin checkIfAutoTimeRequired(Context context) {
    371         DevicePolicyManager dpm = (DevicePolicyManager) context.getSystemService(
    372                 Context.DEVICE_POLICY_SERVICE);
    373         if (dpm == null || !dpm.getAutoTimeRequired()) {
    374             return null;
    375         }
    376         ComponentName adminComponent = dpm.getDeviceOwnerComponentOnCallingUser();
    377         return new EnforcedAdmin(adminComponent, UserHandle.myUserId());
    378     }
    379 
    380     /**
    381      * Checks if an admin has enforced minimum password quality requirements on the given user.
    382      *
    383      * @return EnforcedAdmin Object containing the enforced admin component and admin user details,
    384      * or {@code null} if no quality requirements are set. If the requirements are set by
    385      * multiple device admins, then the admin component will be set to {@code null} and userId to
    386      * {@link UserHandle#USER_NULL}.
    387      *
    388      */
    389     public static EnforcedAdmin checkIfPasswordQualityIsSet(Context context, int userId) {
    390         final LockSettingCheck check =
    391                 (DevicePolicyManager dpm, ComponentName admin, @UserIdInt int checkUser) ->
    392                         dpm.getPasswordQuality(admin, checkUser)
    393                                 > DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
    394 
    395         final DevicePolicyManager dpm = (DevicePolicyManager) context.getSystemService(
    396                 Context.DEVICE_POLICY_SERVICE);
    397         if (dpm == null) {
    398             return null;
    399         }
    400 
    401         LockPatternUtils lockPatternUtils = new LockPatternUtils(context);
    402         if (sProxy.isSeparateProfileChallengeEnabled(lockPatternUtils, userId)) {
    403             // userId is managed profile and has a separate challenge, only consider
    404             // the admins in that user.
    405             final List<ComponentName> admins = dpm.getActiveAdminsAsUser(userId);
    406             if (admins == null) {
    407                 return null;
    408             }
    409             EnforcedAdmin enforcedAdmin = null;
    410             for (ComponentName admin : admins) {
    411                 if (check.isEnforcing(dpm, admin, userId)) {
    412                     if (enforcedAdmin == null) {
    413                         enforcedAdmin = new EnforcedAdmin(admin, userId);
    414                     } else {
    415                         return EnforcedAdmin.MULTIPLE_ENFORCED_ADMIN;
    416                     }
    417                 }
    418             }
    419             return enforcedAdmin;
    420         } else {
    421             return checkForLockSetting(context, userId, check);
    422         }
    423     }
    424 
    425     /**
    426      * Checks if any admin has set maximum time to lock.
    427      *
    428      * @return EnforcedAdmin Object containing the enforced admin component and admin user details,
    429      * or {@code null} if no admin has set this restriction. If multiple admins has set this, then
    430      * the admin component will be set to {@code null} and userId to {@link UserHandle#USER_NULL}
    431      */
    432     public static EnforcedAdmin checkIfMaximumTimeToLockIsSet(Context context) {
    433         final DevicePolicyManager dpm = (DevicePolicyManager) context.getSystemService(
    434                 Context.DEVICE_POLICY_SERVICE);
    435         if (dpm == null) {
    436             return null;
    437         }
    438         EnforcedAdmin enforcedAdmin = null;
    439         final int userId = UserHandle.myUserId();
    440         final UserManager um = UserManager.get(context);
    441         final List<UserInfo> profiles = um.getProfiles(userId);
    442         final int profilesSize = profiles.size();
    443         // As we do not have a separate screen lock timeout settings for work challenge,
    444         // we need to combine all profiles maximum time to lock even work challenge is
    445         // enabled.
    446         for (int i = 0; i < profilesSize; i++) {
    447             final UserInfo userInfo = profiles.get(i);
    448             final List<ComponentName> admins = dpm.getActiveAdminsAsUser(userInfo.id);
    449             if (admins == null) {
    450                 continue;
    451             }
    452             for (ComponentName admin : admins) {
    453                 if (dpm.getMaximumTimeToLock(admin, userInfo.id) > 0) {
    454                     if (enforcedAdmin == null) {
    455                         enforcedAdmin = new EnforcedAdmin(admin, userInfo.id);
    456                     } else {
    457                         return EnforcedAdmin.MULTIPLE_ENFORCED_ADMIN;
    458                     }
    459                     // This same admins could have set policies both on the managed profile
    460                     // and on the parent. So, if the admin has set the policy on the
    461                     // managed profile here, we don't need to further check if that admin
    462                     // has set policy on the parent admin.
    463                     continue;
    464                 }
    465                 if (userInfo.isManagedProfile()) {
    466                     // If userInfo.id is a managed profile, we also need to look at
    467                     // the policies set on the parent.
    468                     DevicePolicyManager parentDpm = sProxy.getParentProfileInstance(dpm, userInfo);
    469                     if (parentDpm.getMaximumTimeToLock(admin, userInfo.id) > 0) {
    470                         if (enforcedAdmin == null) {
    471                             enforcedAdmin = new EnforcedAdmin(admin, userInfo.id);
    472                         } else {
    473                             return EnforcedAdmin.MULTIPLE_ENFORCED_ADMIN;
    474                         }
    475                     }
    476                 }
    477             }
    478         }
    479         return enforcedAdmin;
    480     }
    481 
    482     private interface LockSettingCheck {
    483         boolean isEnforcing(DevicePolicyManager dpm, ComponentName admin, @UserIdInt int userId);
    484     }
    485 
    486     /**
    487      * Checks whether any of the user's profiles enforce the lock setting. A managed profile is only
    488      * included if it does not have a separate challenge.
    489      *
    490      * The user identified by {@param userId} is always included.
    491      */
    492     private static EnforcedAdmin checkForLockSetting(
    493             Context context, @UserIdInt int userId, LockSettingCheck check) {
    494         final DevicePolicyManager dpm = (DevicePolicyManager) context.getSystemService(
    495                 Context.DEVICE_POLICY_SERVICE);
    496         if (dpm == null) {
    497             return null;
    498         }
    499         final LockPatternUtils lockPatternUtils = new LockPatternUtils(context);
    500         EnforcedAdmin enforcedAdmin = null;
    501         // Return all admins for this user and the profiles that are visible from this
    502         // user that do not use a separate work challenge.
    503         for (UserInfo userInfo : UserManager.get(context).getProfiles(userId)) {
    504             final List<ComponentName> admins = dpm.getActiveAdminsAsUser(userInfo.id);
    505             if (admins == null) {
    506                 continue;
    507             }
    508             final boolean isSeparateProfileChallengeEnabled =
    509                     sProxy.isSeparateProfileChallengeEnabled(lockPatternUtils, userInfo.id);
    510             for (ComponentName admin : admins) {
    511                 if (!isSeparateProfileChallengeEnabled) {
    512                     if (check.isEnforcing(dpm, admin, userInfo.id)) {
    513                         if (enforcedAdmin == null) {
    514                             enforcedAdmin = new EnforcedAdmin(admin, userInfo.id);
    515                         } else {
    516                             return EnforcedAdmin.MULTIPLE_ENFORCED_ADMIN;
    517                         }
    518                         // This same admins could have set policies both on the managed profile
    519                         // and on the parent. So, if the admin has set the policy on the
    520                         // managed profile here, we don't need to further check if that admin
    521                         // has set policy on the parent admin.
    522                         continue;
    523                     }
    524                 }
    525                 if (userInfo.isManagedProfile()) {
    526                     // If userInfo.id is a managed profile, we also need to look at
    527                     // the policies set on the parent.
    528                     DevicePolicyManager parentDpm = sProxy.getParentProfileInstance(dpm, userInfo);
    529                     if (check.isEnforcing(parentDpm, admin, userInfo.id)) {
    530                         if (enforcedAdmin == null) {
    531                             enforcedAdmin = new EnforcedAdmin(admin, userInfo.id);
    532                         } else {
    533                             return EnforcedAdmin.MULTIPLE_ENFORCED_ADMIN;
    534                         }
    535                     }
    536                 }
    537             }
    538         }
    539         return enforcedAdmin;
    540     }
    541 
    542     public static EnforcedAdmin getProfileOrDeviceOwner(Context context, int userId) {
    543         if (userId == UserHandle.USER_NULL) {
    544             return null;
    545         }
    546         final DevicePolicyManager dpm = (DevicePolicyManager) context.getSystemService(
    547                 Context.DEVICE_POLICY_SERVICE);
    548         if (dpm == null) {
    549             return null;
    550         }
    551         ComponentName adminComponent = dpm.getProfileOwnerAsUser(userId);
    552         if (adminComponent != null) {
    553             return new EnforcedAdmin(adminComponent, userId);
    554         }
    555         if (dpm.getDeviceOwnerUserId() == userId) {
    556             adminComponent = dpm.getDeviceOwnerComponentOnAnyUser();
    557             if (adminComponent != null) {
    558                 return new EnforcedAdmin(adminComponent, userId);
    559             }
    560         }
    561         return null;
    562     }
    563 
    564     public static EnforcedAdmin getDeviceOwner(Context context) {
    565         final DevicePolicyManager dpm = (DevicePolicyManager) context.getSystemService(
    566                 Context.DEVICE_POLICY_SERVICE);
    567         if (dpm == null) {
    568             return null;
    569         }
    570         ComponentName adminComponent = dpm.getDeviceOwnerComponentOnAnyUser();
    571         if (adminComponent != null) {
    572             return new EnforcedAdmin(adminComponent, dpm.getDeviceOwnerUserId());
    573         }
    574         return null;
    575     }
    576 
    577     private static EnforcedAdmin getProfileOwner(Context context, int userId) {
    578         if (userId == UserHandle.USER_NULL) {
    579             return null;
    580         }
    581         final DevicePolicyManager dpm = (DevicePolicyManager) context.getSystemService(
    582                 Context.DEVICE_POLICY_SERVICE);
    583         if (dpm == null) {
    584             return null;
    585         }
    586         ComponentName adminComponent = dpm.getProfileOwnerAsUser(userId);
    587         if (adminComponent != null) {
    588             return new EnforcedAdmin(adminComponent, userId);
    589         }
    590         return null;
    591     }
    592 
    593     /**
    594      * Set the menu item as disabled by admin by adding a restricted padlock at the end of the
    595      * text and set the click listener which will send an intent to show the admin support details
    596      * dialog. If the admin is null, remove the padlock and disabled color span. When the admin is
    597      * null, we also set the OnMenuItemClickListener to null, so if you want to set a custom
    598      * OnMenuItemClickListener, set it after calling this method.
    599      */
    600     public static void setMenuItemAsDisabledByAdmin(final Context context,
    601             final MenuItem item, final EnforcedAdmin admin) {
    602         SpannableStringBuilder sb = new SpannableStringBuilder(item.getTitle());
    603         removeExistingRestrictedSpans(sb);
    604 
    605         if (admin != null) {
    606             final int disabledColor = context.getColor(R.color.disabled_text_color);
    607             sb.setSpan(new ForegroundColorSpan(disabledColor), 0, sb.length(),
    608                     Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
    609             ImageSpan image = new RestrictedLockImageSpan(context);
    610             sb.append(" ", image, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
    611 
    612             item.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
    613                 @Override
    614                 public boolean onMenuItemClick(MenuItem item) {
    615                     sendShowAdminSupportDetailsIntent(context, admin);
    616                     return true;
    617                 }
    618             });
    619         } else {
    620             item.setOnMenuItemClickListener(null);
    621         }
    622         item.setTitle(sb);
    623     }
    624 
    625     private static void removeExistingRestrictedSpans(SpannableStringBuilder sb) {
    626         final int length = sb.length();
    627         RestrictedLockImageSpan[] imageSpans = sb.getSpans(length - 1, length,
    628                 RestrictedLockImageSpan.class);
    629         for (ImageSpan span : imageSpans) {
    630             final int start = sb.getSpanStart(span);
    631             final int end = sb.getSpanEnd(span);
    632             sb.removeSpan(span);
    633             sb.delete(start, end);
    634         }
    635         ForegroundColorSpan[] colorSpans = sb.getSpans(0, length, ForegroundColorSpan.class);
    636         for (ForegroundColorSpan span : colorSpans) {
    637             sb.removeSpan(span);
    638         }
    639     }
    640 
    641     /**
    642      * Send the intent to trigger the {@link android.settings.ShowAdminSupportDetailsDialog}.
    643      */
    644     public static void sendShowAdminSupportDetailsIntent(Context context, EnforcedAdmin admin) {
    645         final Intent intent = getShowAdminSupportDetailsIntent(context, admin);
    646         int targetUserId = UserHandle.myUserId();
    647         if (admin != null && admin.userId != UserHandle.USER_NULL
    648                 && isCurrentUserOrProfile(context, admin.userId)) {
    649             targetUserId = admin.userId;
    650         }
    651         context.startActivityAsUser(intent, new UserHandle(targetUserId));
    652     }
    653 
    654     public static Intent getShowAdminSupportDetailsIntent(Context context, EnforcedAdmin admin) {
    655         final Intent intent = new Intent(Settings.ACTION_SHOW_ADMIN_SUPPORT_DETAILS);
    656         if (admin != null) {
    657             if (admin.component != null) {
    658                 intent.putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN, admin.component);
    659             }
    660             int adminUserId = UserHandle.myUserId();
    661             if (admin.userId != UserHandle.USER_NULL) {
    662                 adminUserId = admin.userId;
    663             }
    664             intent.putExtra(Intent.EXTRA_USER_ID, adminUserId);
    665         }
    666         return intent;
    667     }
    668 
    669     public static boolean isCurrentUserOrProfile(Context context, int userId) {
    670         UserManager um = UserManager.get(context);
    671         for (UserInfo userInfo : um.getProfiles(UserHandle.myUserId())) {
    672             if (userInfo.id == userId) {
    673                 return true;
    674             }
    675         }
    676         return false;
    677     }
    678 
    679     public static boolean isAdminInCurrentUserOrProfile(Context context, ComponentName admin) {
    680         DevicePolicyManager dpm = (DevicePolicyManager) context.getSystemService(
    681                 Context.DEVICE_POLICY_SERVICE);
    682         UserManager um = UserManager.get(context);
    683         for (UserInfo userInfo : um.getProfiles(UserHandle.myUserId())) {
    684             if (dpm.isAdminActiveAsUser(admin, userInfo.id)) {
    685                 return true;
    686             }
    687         }
    688         return false;
    689     }
    690 
    691     public static void setTextViewPadlock(Context context,
    692             TextView textView, boolean showPadlock) {
    693         final SpannableStringBuilder sb = new SpannableStringBuilder(textView.getText());
    694         removeExistingRestrictedSpans(sb);
    695         if (showPadlock) {
    696             final ImageSpan image = new RestrictedLockImageSpan(context);
    697             sb.append(" ", image, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
    698         }
    699         textView.setText(sb);
    700     }
    701 
    702     /**
    703      * Takes a {@link android.widget.TextView} and applies an alpha so that the text looks like
    704      * disabled and appends a padlock to the text. This assumes that there are no
    705      * ForegroundColorSpans and RestrictedLockImageSpans used on the TextView.
    706      */
    707     public static void setTextViewAsDisabledByAdmin(Context context,
    708             TextView textView, boolean disabled) {
    709         final SpannableStringBuilder sb = new SpannableStringBuilder(textView.getText());
    710         removeExistingRestrictedSpans(sb);
    711         if (disabled) {
    712             final int disabledColor = context.getColor(R.color.disabled_text_color);
    713             sb.setSpan(new ForegroundColorSpan(disabledColor), 0, sb.length(),
    714                     Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
    715             textView.setCompoundDrawables(null, null, getRestrictedPadlock(context), null);
    716             textView.setCompoundDrawablePadding(context.getResources().getDimensionPixelSize(
    717                     R.dimen.restricted_icon_padding));
    718         } else {
    719             textView.setCompoundDrawables(null, null, null, null);
    720         }
    721         textView.setText(sb);
    722     }
    723 
    724     public static class EnforcedAdmin {
    725         public ComponentName component = null;
    726         public int userId = UserHandle.USER_NULL;
    727 
    728         // We use this to represent the case where a policy is enforced by multiple admins.
    729         public final static EnforcedAdmin MULTIPLE_ENFORCED_ADMIN = new EnforcedAdmin();
    730 
    731         public EnforcedAdmin(ComponentName component, int userId) {
    732             this.component = component;
    733             this.userId = userId;
    734         }
    735 
    736         public EnforcedAdmin(EnforcedAdmin other) {
    737             if (other == null) {
    738                 throw new IllegalArgumentException();
    739             }
    740             this.component = other.component;
    741             this.userId = other.userId;
    742         }
    743 
    744         public EnforcedAdmin() {}
    745 
    746         @Override
    747         public boolean equals(Object object) {
    748             if (object == this) return true;
    749             if (!(object instanceof EnforcedAdmin)) return false;
    750             EnforcedAdmin other = (EnforcedAdmin) object;
    751             if (userId != other.userId) {
    752                 return false;
    753             }
    754             if ((component == null && other.component == null) ||
    755                     (component != null && component.equals(other.component))) {
    756                 return true;
    757             }
    758             return false;
    759         }
    760 
    761         @Override
    762         public String toString() {
    763             return "EnforcedAdmin{component=" + component + ",userId=" + userId + "}";
    764         }
    765 
    766         public void copyTo(EnforcedAdmin other) {
    767             if (other == null) {
    768                 throw new IllegalArgumentException();
    769             }
    770             other.component = component;
    771             other.userId = userId;
    772         }
    773     }
    774 
    775     /**
    776      * Static {@link LockPatternUtils} and {@link DevicePolicyManager} wrapper for testing purposes.
    777      * {@link LockPatternUtils} is an internal API not supported by robolectric.
    778      * {@link DevicePolicyManager} has a {@code getProfileParent} not yet suppored by robolectric.
    779      */
    780     @VisibleForTesting
    781     static Proxy sProxy = new Proxy();
    782 
    783     @VisibleForTesting
    784     static class Proxy {
    785         public boolean isSeparateProfileChallengeEnabled(LockPatternUtils utils, int userHandle) {
    786             return utils.isSeparateProfileChallengeEnabled(userHandle);
    787         }
    788 
    789         public DevicePolicyManager getParentProfileInstance(DevicePolicyManager dpm, UserInfo ui) {
    790             return dpm.getParentProfileInstance(ui);
    791         }
    792     }
    793 }
    794