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