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