2 * Copyright (C) 2016 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package com.android.settingslib;
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.Color;
27 import android.graphics.drawable.Drawable;
28 import android.os.Bundle;
29 import android.os.RemoteException;
30 import android.os.UserHandle;
31 import android.os.UserManager;
32 import android.provider.Settings;
33 import android.text.Spanned;
34 import android.text.SpannableStringBuilder;
35 import android.text.style.ForegroundColorSpan;
36 import android.text.style.ImageSpan;
37 import android.view.MenuItem;
38 import android.widget.TextView;
40 import com.android.internal.widget.LockPatternUtils;
42 import java.util.List;
45 * Utility class to host methods usable in adding a restricted padlock icon and showing admin
46 * support message dialog.
48 public class RestrictedLockUtils {
50 * @return drawables for displaying with settings that are locked by a device admin.
52 public static Drawable getRestrictedPadlock(Context context) {
53 Drawable restrictedPadlock = context.getDrawable(R.drawable.ic_settings_lock_outline);
54 final int iconSize = context.getResources().getDimensionPixelSize(
55 R.dimen.restricted_lock_icon_size);
56 restrictedPadlock.setBounds(0, 0, iconSize, iconSize);
57 return restrictedPadlock;
61 * Checks if a restriction is enforced on a user and returns the enforced admin and
64 * @param userRestriction Restriction to check
65 * @param userId User which we need to check if restriction is enforced on.
66 * @return EnforcedAdmin Object containing the enforced admin component and admin user details,
67 * or {@code null} If the restriction is not set. If the restriction is set by both device owner
68 * and profile owner, then the admin component will be set to {@code null} and userId to
69 * {@link UserHandle#USER_NULL}.
71 public static EnforcedAdmin checkIfRestrictionEnforced(Context context,
72 String userRestriction, int userId) {
73 DevicePolicyManager dpm = (DevicePolicyManager) context.getSystemService(
74 Context.DEVICE_POLICY_SERVICE);
78 ComponentName deviceOwner = dpm.getDeviceOwnerComponentOnAnyUser();
79 int deviceOwnerUserId = dpm.getDeviceOwnerUserId();
80 boolean enforcedByDeviceOwner = false;
81 if (deviceOwner != null && deviceOwnerUserId != UserHandle.USER_NULL) {
82 Bundle enforcedRestrictions = dpm.getUserRestrictions(deviceOwner, deviceOwnerUserId);
83 if (enforcedRestrictions != null
84 && enforcedRestrictions.getBoolean(userRestriction, false)) {
85 enforcedByDeviceOwner = true;
89 ComponentName profileOwner = null;
90 boolean enforcedByProfileOwner = false;
91 if (userId != UserHandle.USER_NULL) {
92 profileOwner = dpm.getProfileOwnerAsUser(userId);
93 if (profileOwner != null) {
94 Bundle enforcedRestrictions = dpm.getUserRestrictions(profileOwner, userId);
95 if (enforcedRestrictions != null
96 && enforcedRestrictions.getBoolean(userRestriction, false)) {
97 enforcedByProfileOwner = true;
102 if (!enforcedByDeviceOwner && !enforcedByProfileOwner) {
106 EnforcedAdmin admin = null;
107 if (enforcedByDeviceOwner && enforcedByProfileOwner) {
108 admin = new EnforcedAdmin();
109 } else if (enforcedByDeviceOwner) {
110 admin = new EnforcedAdmin(deviceOwner, deviceOwnerUserId);
112 admin = new EnforcedAdmin(profileOwner, userId);
118 * Checks if keyguard features are disabled by policy.
120 * @param keyguardFeatures Could be any of keyguard features that can be
121 * disabled by {@link android.app.admin.DevicePolicyManager#setKeyguardDisabledFeatures}.
122 * @return EnforcedAdmin Object containing the enforced admin component and admin user details,
123 * or {@code null} If the notification features are not disabled. If the restriction is set by
124 * multiple admins, then the admin component will be set to {@code null} and userId to
125 * {@link UserHandle#USER_NULL}.
127 public static EnforcedAdmin checkIfKeyguardFeaturesDisabled(Context context,
128 int keyguardFeatures) {
129 final DevicePolicyManager dpm = (DevicePolicyManager) context.getSystemService(
130 Context.DEVICE_POLICY_SERVICE);
134 final UserManager um = (UserManager) context.getSystemService(Context.USER_SERVICE);
135 LockPatternUtils lockPatternUtils = new LockPatternUtils(context);
136 EnforcedAdmin enforcedAdmin = null;
137 final int userId = UserHandle.myUserId();
138 if (um.getUserInfo(userId).isManagedProfile()) {
139 final List<ComponentName> admins = dpm.getActiveAdminsAsUser(userId);
140 if (admins == null) {
143 for (ComponentName admin : admins) {
144 if ((dpm.getKeyguardDisabledFeatures(admin, userId) & keyguardFeatures) != 0) {
145 if (enforcedAdmin == null) {
146 enforcedAdmin = new EnforcedAdmin(admin, userId);
148 return EnforcedAdmin.MULTIPLE_ENFORCED_ADMIN;
153 // Consider all admins for this user and the profiles that are visible from this
154 // user that do not use a separate work challenge.
155 for (UserInfo userInfo : um.getProfiles(userId)) {
156 final List<ComponentName> admins = dpm.getActiveAdminsAsUser(userInfo.id);
157 if (admins == null) {
160 final boolean isSeparateProfileChallengeEnabled =
161 lockPatternUtils.isSeparateProfileChallengeEnabled(userInfo.id);
162 for (ComponentName admin : admins) {
163 if (!isSeparateProfileChallengeEnabled) {
164 if ((dpm.getKeyguardDisabledFeatures(admin, userInfo.id)
165 & keyguardFeatures) != 0) {
166 if (enforcedAdmin == null) {
167 enforcedAdmin = new EnforcedAdmin(admin, userInfo.id);
169 return EnforcedAdmin.MULTIPLE_ENFORCED_ADMIN;
171 // This same admins could have set policies both on the managed profile
172 // and on the parent. So, if the admin has set the policy on the
173 // managed profile here, we don't need to further check if that admin
174 // has set policy on the parent admin.
178 if (userInfo.isManagedProfile()) {
179 // If userInfo.id is a managed profile, we also need to look at
180 // the policies set on the parent.
181 DevicePolicyManager parentDpm = dpm.getParentProfileInstance(admin);
182 if ((parentDpm.getKeyguardDisabledFeatures(admin, userInfo.id)
183 & keyguardFeatures) != 0) {
184 if (enforcedAdmin == null) {
185 enforcedAdmin = new EnforcedAdmin(admin, userInfo.id);
187 return EnforcedAdmin.MULTIPLE_ENFORCED_ADMIN;
194 return enforcedAdmin;
197 public static EnforcedAdmin checkIfUninstallBlocked(Context context,
198 String packageName, int userId) {
199 EnforcedAdmin allAppsControlDisallowedAdmin = checkIfRestrictionEnforced(context,
200 UserManager.DISALLOW_APPS_CONTROL, userId);
201 if (allAppsControlDisallowedAdmin != null) {
202 return allAppsControlDisallowedAdmin;
204 EnforcedAdmin allAppsUninstallDisallowedAdmin = checkIfRestrictionEnforced(context,
205 UserManager.DISALLOW_UNINSTALL_APPS, userId);
206 if (allAppsUninstallDisallowedAdmin != null) {
207 return allAppsUninstallDisallowedAdmin;
209 IPackageManager ipm = AppGlobals.getPackageManager();
211 if (ipm.getBlockUninstallForUser(packageName, userId)) {
212 DevicePolicyManager dpm = (DevicePolicyManager) context.getSystemService(
213 Context.DEVICE_POLICY_SERVICE);
217 ComponentName admin = dpm.getProfileOwner();
219 admin = dpm.getDeviceOwnerComponentOnCallingUser();
221 return new EnforcedAdmin(admin, UserHandle.myUserId());
223 } catch (RemoteException e) {
230 * Check if account management for a specific type of account is disabled by admin.
231 * Only a profile or device owner can disable account management. So, we check if account
232 * management is disabled and return profile or device owner on the calling user.
234 * @return EnforcedAdmin Object containing the enforced admin component and admin user details,
235 * or {@code null} if the account management is not disabled.
237 public static EnforcedAdmin checkIfAccountManagementDisabled(Context context,
238 String accountType) {
239 if (accountType == null) {
242 DevicePolicyManager dpm = (DevicePolicyManager) context.getSystemService(
243 Context.DEVICE_POLICY_SERVICE);
247 boolean isAccountTypeDisabled = false;
248 String[] disabledTypes = dpm.getAccountTypesWithManagementDisabled();
249 for (String type : disabledTypes) {
250 if (accountType.equals(type)) {
251 isAccountTypeDisabled = true;
255 if (!isAccountTypeDisabled) {
258 return getProfileOrDeviceOwnerOnCallingUser(context);
262 * Checks if {@link android.app.admin.DevicePolicyManager#setAutoTimeRequired} is enforced
265 * @return EnforcedAdmin Object containing the device owner component and
266 * userId the device owner is running as, or {@code null} setAutoTimeRequired is not enforced.
268 public static EnforcedAdmin checkIfAutoTimeRequired(Context context) {
269 DevicePolicyManager dpm = (DevicePolicyManager) context.getSystemService(
270 Context.DEVICE_POLICY_SERVICE);
271 if (dpm == null || !dpm.getAutoTimeRequired()) {
274 ComponentName adminComponent = dpm.getDeviceOwnerComponentOnCallingUser();
275 return new EnforcedAdmin(adminComponent, UserHandle.myUserId());
279 * Checks if an admin has enforced minimum password quality requirements on the device.
281 * @return EnforcedAdmin Object containing the enforced admin component and admin user details,
282 * or {@code null} if no quality requirements are set. If the requirements are set by
283 * multiple device admins, then the admin component will be set to {@code null} and userId to
284 * {@link UserHandle#USER_NULL}.
287 public static EnforcedAdmin checkIfPasswordQualityIsSet(Context context) {
288 final DevicePolicyManager dpm = (DevicePolicyManager) context.getSystemService(
289 Context.DEVICE_POLICY_SERVICE);
293 boolean isDisabledByMultipleAdmins = false;
294 ComponentName adminComponent = null;
295 List<ComponentName> admins = dpm.getActiveAdmins();
297 if (admins != null) {
298 for (ComponentName admin : admins) {
299 quality = dpm.getPasswordQuality(admin);
300 if (quality >= DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
301 if (adminComponent == null) {
302 adminComponent = admin;
304 isDisabledByMultipleAdmins = true;
310 EnforcedAdmin enforcedAdmin = null;
311 if (adminComponent != null) {
312 if (!isDisabledByMultipleAdmins) {
313 enforcedAdmin = new EnforcedAdmin(adminComponent, UserHandle.myUserId());
315 enforcedAdmin = new EnforcedAdmin();
318 return enforcedAdmin;
322 * Checks if any admin has set maximum time to lock.
324 * @return EnforcedAdmin Object containing the enforced admin component and admin user details,
325 * or {@code null} if no admin has set this restriction. If multiple admins has set this, then
326 * the admin component will be set to {@code null} and userId to {@link UserHandle#USER_NULL}
328 public static EnforcedAdmin checkIfMaximumTimeToLockIsSet(Context context) {
329 final DevicePolicyManager dpm = (DevicePolicyManager) context.getSystemService(
330 Context.DEVICE_POLICY_SERVICE);
331 LockPatternUtils lockPatternUtils = new LockPatternUtils(context);
332 EnforcedAdmin enforcedAdmin = null;
333 final int userId = UserHandle.myUserId();
334 if (lockPatternUtils.isSeparateProfileChallengeEnabled(userId)) {
335 // If the user has a separate challenge, only consider the admins in that user.
336 final List<ComponentName> admins = dpm.getActiveAdminsAsUser(userId);
337 if (admins == null) {
340 for (ComponentName admin : admins) {
341 if (dpm.getMaximumTimeToLock(admin, userId) > 0) {
342 if (enforcedAdmin == null) {
343 enforcedAdmin = new EnforcedAdmin(admin, userId);
345 return EnforcedAdmin.MULTIPLE_ENFORCED_ADMIN;
350 // Return all admins for this user and the profiles that are visible from this
351 // user that do not use a separate work challenge.
352 final UserManager um = (UserManager) context.getSystemService(Context.USER_SERVICE);
353 for (UserInfo userInfo : um.getProfiles(userId)) {
354 final List<ComponentName> admins = dpm.getActiveAdminsAsUser(userInfo.id);
355 if (admins == null) {
358 final boolean isSeparateProfileChallengeEnabled =
359 lockPatternUtils.isSeparateProfileChallengeEnabled(userInfo.id);
360 for (ComponentName admin : admins) {
361 if (!isSeparateProfileChallengeEnabled) {
362 if (dpm.getMaximumTimeToLock(admin, userInfo.id) > 0) {
363 if (enforcedAdmin == null) {
364 enforcedAdmin = new EnforcedAdmin(admin, userInfo.id);
366 return EnforcedAdmin.MULTIPLE_ENFORCED_ADMIN;
368 // This same admins could have set policies both on the managed profile
369 // and on the parent. So, if the admin has set the policy on the
370 // managed profile here, we don't need to further check if that admin
371 // has set policy on the parent admin.
375 if (userInfo.isManagedProfile()) {
376 // If userInfo.id is a managed profile, we also need to look at
377 // the policies set on the parent.
378 DevicePolicyManager parentDpm = dpm.getParentProfileInstance(admin);
379 if (parentDpm.getMaximumTimeToLock(admin, userInfo.id) > 0) {
380 if (enforcedAdmin == null) {
381 enforcedAdmin = new EnforcedAdmin(admin, userInfo.id);
383 return EnforcedAdmin.MULTIPLE_ENFORCED_ADMIN;
390 return enforcedAdmin;
393 public static EnforcedAdmin getProfileOrDeviceOwnerOnCallingUser(Context context) {
394 final DevicePolicyManager dpm = (DevicePolicyManager) context.getSystemService(
395 Context.DEVICE_POLICY_SERVICE);
399 ComponentName adminComponent = dpm.getDeviceOwnerComponentOnCallingUser();
400 if (adminComponent != null) {
401 return new EnforcedAdmin(adminComponent, UserHandle.myUserId());
403 adminComponent = dpm.getProfileOwner();
404 if (adminComponent != null) {
405 return new EnforcedAdmin(adminComponent, UserHandle.myUserId());
411 * Set the menu item as disabled by admin by adding a restricted padlock at the end of the
412 * text and set the click listener which will send an intent to show the admin support details
413 * dialog. If the admin is null, remove the padlock and disabled color span. When the admin is
414 * null, we also set the OnMenuItemClickListener to null, so if you want to set a custom
415 * OnMenuItemClickListener, set it after calling this method.
417 public static void setMenuItemAsDisabledByAdmin(final Context context,
418 final MenuItem item, final EnforcedAdmin admin) {
419 SpannableStringBuilder sb = new SpannableStringBuilder(item.getTitle());
420 removeExistingRestrictedSpans(sb);
423 final int disabledColor = context.getColor(R.color.disabled_text_color);
424 sb.setSpan(new ForegroundColorSpan(disabledColor), 0, sb.length(),
425 Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
426 ImageSpan image = new RestrictedLockImageSpan(context);
427 sb.append(" ", image, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
429 item.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
431 public boolean onMenuItemClick(MenuItem item) {
432 sendShowAdminSupportDetailsIntent(context, admin);
437 item.setOnMenuItemClickListener(null);
442 private static void removeExistingRestrictedSpans(SpannableStringBuilder sb) {
443 final int length = sb.length();
444 RestrictedLockImageSpan[] imageSpans = sb.getSpans(length - 1, length,
445 RestrictedLockImageSpan.class);
446 for (ImageSpan span : imageSpans) {
447 final int start = sb.getSpanStart(span);
448 final int end = sb.getSpanEnd(span);
450 sb.delete(start, end);
452 ForegroundColorSpan[] colorSpans = sb.getSpans(0, length, ForegroundColorSpan.class);
453 for (ForegroundColorSpan span : colorSpans) {
459 * Send the intent to trigger the {@link android.settings.ShowAdminSupportDetailsDialog}.
461 public static void sendShowAdminSupportDetailsIntent(Context context, EnforcedAdmin admin) {
462 final Intent intent = getShowAdminSupportDetailsIntent(context, admin);
463 int adminUserId = UserHandle.myUserId();
464 if (admin.userId != UserHandle.USER_NULL) {
465 adminUserId = admin.userId;
467 context.startActivityAsUser(intent, new UserHandle(adminUserId));
470 public static Intent getShowAdminSupportDetailsIntent(Context context, EnforcedAdmin admin) {
471 final Intent intent = new Intent(Settings.ACTION_SHOW_ADMIN_SUPPORT_DETAILS);
473 if (admin.component != null) {
474 intent.putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN, admin.component);
476 int adminUserId = UserHandle.myUserId();
477 if (admin.userId != UserHandle.USER_NULL) {
478 adminUserId = admin.userId;
480 intent.putExtra(Intent.EXTRA_USER_ID, adminUserId);
485 public static void setTextViewPadlock(Context context,
486 TextView textView, boolean showPadlock) {
487 final SpannableStringBuilder sb = new SpannableStringBuilder(textView.getText());
488 removeExistingRestrictedSpans(sb);
490 final ImageSpan image = new RestrictedLockImageSpan(context);
491 sb.append(" ", image, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
493 textView.setText(sb);
497 * Takes a {@link android.widget.TextView} and applies an alpha so that the text looks like
498 * disabled and appends a padlock to the text. This assumes that there are no
499 * ForegroundColorSpans and RestrictedLockImageSpans used on the TextView.
501 public static void setTextViewAsDisabledByAdmin(Context context,
502 TextView textView, boolean disabled) {
503 final SpannableStringBuilder sb = new SpannableStringBuilder(textView.getText());
504 removeExistingRestrictedSpans(sb);
506 final int disabledColor = context.getColor(R.color.disabled_text_color);
507 sb.setSpan(new ForegroundColorSpan(disabledColor), 0, sb.length(),
508 Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
509 final ImageSpan image = new RestrictedLockImageSpan(context);
510 sb.append(" ", image, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
512 textView.setText(sb);
515 public static class EnforcedAdmin {
516 public ComponentName component = null;
517 public int userId = UserHandle.USER_NULL;
519 // We use this to represent the case where a policy is enforced by multiple admins.
520 public final static EnforcedAdmin MULTIPLE_ENFORCED_ADMIN = new EnforcedAdmin();
522 public EnforcedAdmin(ComponentName component, int userId) {
523 this.component = component;
524 this.userId = userId;
527 public EnforcedAdmin(EnforcedAdmin other) {
529 throw new IllegalArgumentException();
531 this.component = other.component;
532 this.userId = other.userId;
535 public EnforcedAdmin() {}
538 public boolean equals(Object object) {
539 if (object == this) return true;
540 if (!(object instanceof EnforcedAdmin)) return false;
541 EnforcedAdmin other = (EnforcedAdmin) object;
542 if (userId != other.userId) {
545 if ((component == null && other == null) ||
546 (component != null && component.equals(other))) {
553 public String toString() {
554 return "EnforcedAdmin{component=" + component + ",userId=" + userId + "}";
557 public void copyTo(EnforcedAdmin other) {
559 throw new IllegalArgumentException();
561 other.component = component;
562 other.userId = userId;