blob: e86ca82bf2159fe2a7e88c52021822e1fa6437fa [file] [log] [blame]
Sudheer Shanka7ff866d2016-01-12 17:22:06 +00001/*
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
17package com.android.settingslib;
18
Sudheer Shanka7664cba2016-01-15 11:39:04 +000019import android.app.AppGlobals;
Sudheer Shanka7ff866d2016-01-12 17:22:06 +000020import android.app.admin.DevicePolicyManager;
21import android.content.ComponentName;
22import android.content.Context;
23import android.content.Intent;
Sudheer Shanka7664cba2016-01-15 11:39:04 +000024import android.content.pm.IPackageManager;
Sudheer Shanka45e298f2016-01-14 18:41:14 +000025import android.content.pm.UserInfo;
Sudheer Shanka7ff866d2016-01-12 17:22:06 +000026import android.graphics.drawable.Drawable;
27import android.os.Bundle;
Sudheer Shanka7664cba2016-01-15 11:39:04 +000028import android.os.RemoteException;
Sudheer Shanka7ff866d2016-01-12 17:22:06 +000029import android.os.UserHandle;
Sudheer Shanka7664cba2016-01-15 11:39:04 +000030import android.os.UserManager;
Sudheer Shanka7ff866d2016-01-12 17:22:06 +000031import android.provider.Settings;
32import android.text.Spanned;
33import android.text.SpannableStringBuilder;
34import android.text.style.ForegroundColorSpan;
35import android.text.style.ImageSpan;
36import android.view.MenuItem;
37import android.widget.TextView;
38
Sudheer Shanka45e298f2016-01-14 18:41:14 +000039import com.android.internal.widget.LockPatternUtils;
40
Sudheer Shanka7ff866d2016-01-12 17:22:06 +000041import java.util.List;
42
43/**
44 * Utility class to host methods usable in adding a restricted padlock icon and showing admin
45 * support message dialog.
46 */
47public class RestrictedLockUtils {
48 /**
49 * @return drawables for displaying with settings that are locked by a device admin.
50 */
51 public static Drawable getRestrictedPadlock(Context context) {
Sudheer Shanka40400a62016-02-23 11:42:11 +000052 Drawable restrictedPadlock = context.getDrawable(R.drawable.ic_info);
Sudheer Shanka7ff866d2016-01-12 17:22:06 +000053 final int iconSize = context.getResources().getDimensionPixelSize(
Sudheer Shanka40400a62016-02-23 11:42:11 +000054 R.dimen.restricted_icon_size);
Sudheer Shanka7ff866d2016-01-12 17:22:06 +000055 restrictedPadlock.setBounds(0, 0, iconSize, iconSize);
56 return restrictedPadlock;
57 }
58
59 /**
60 * Checks if a restriction is enforced on a user and returns the enforced admin and
61 * admin userId.
62 *
63 * @param userRestriction Restriction to check
64 * @param userId User which we need to check if restriction is enforced on.
Sudheer Shanka45e298f2016-01-14 18:41:14 +000065 * @return EnforcedAdmin Object containing the enforced admin component and admin user details,
66 * or {@code null} If the restriction is not set. If the restriction is set by both device owner
67 * and profile owner, then the admin component will be set to {@code null} and userId to
Sudheer Shanka7ff866d2016-01-12 17:22:06 +000068 * {@link UserHandle#USER_NULL}.
69 */
70 public static EnforcedAdmin checkIfRestrictionEnforced(Context context,
71 String userRestriction, int userId) {
72 DevicePolicyManager dpm = (DevicePolicyManager) context.getSystemService(
73 Context.DEVICE_POLICY_SERVICE);
Sudheer Shankac61087102016-01-26 14:00:16 +000074 if (dpm == null) {
75 return null;
76 }
Sudheer Shanka7ff866d2016-01-12 17:22:06 +000077 ComponentName deviceOwner = dpm.getDeviceOwnerComponentOnAnyUser();
78 int deviceOwnerUserId = dpm.getDeviceOwnerUserId();
79 boolean enforcedByDeviceOwner = false;
80 if (deviceOwner != null && deviceOwnerUserId != UserHandle.USER_NULL) {
Sudheer Shanka549b9692016-03-30 17:12:07 -070081 Bundle enforcedRestrictions =
82 dpm.getUserRestrictionsForUser(deviceOwner, deviceOwnerUserId);
Sudheer Shanka7ff866d2016-01-12 17:22:06 +000083 if (enforcedRestrictions != null
84 && enforcedRestrictions.getBoolean(userRestriction, false)) {
85 enforcedByDeviceOwner = true;
86 }
87 }
88
89 ComponentName profileOwner = null;
90 boolean enforcedByProfileOwner = false;
91 if (userId != UserHandle.USER_NULL) {
92 profileOwner = dpm.getProfileOwnerAsUser(userId);
93 if (profileOwner != null) {
Sudheer Shanka549b9692016-03-30 17:12:07 -070094 Bundle enforcedRestrictions =
95 dpm.getUserRestrictionsForUser(profileOwner, userId);
Sudheer Shanka7ff866d2016-01-12 17:22:06 +000096 if (enforcedRestrictions != null
97 && enforcedRestrictions.getBoolean(userRestriction, false)) {
98 enforcedByProfileOwner = true;
99 }
100 }
101 }
102
103 if (!enforcedByDeviceOwner && !enforcedByProfileOwner) {
104 return null;
105 }
106
107 EnforcedAdmin admin = null;
108 if (enforcedByDeviceOwner && enforcedByProfileOwner) {
109 admin = new EnforcedAdmin();
110 } else if (enforcedByDeviceOwner) {
111 admin = new EnforcedAdmin(deviceOwner, deviceOwnerUserId);
112 } else {
113 admin = new EnforcedAdmin(profileOwner, userId);
114 }
115 return admin;
116 }
117
Sudheer Shankaa8fbbb32016-02-11 17:17:57 +0000118 public static boolean hasBaseUserRestriction(Context context,
119 String userRestriction, int userId) {
120 UserManager um = (UserManager) context.getSystemService(Context.USER_SERVICE);
121 return um.hasBaseUserRestriction(userRestriction, UserHandle.of(userId));
122 }
123
Sudheer Shanka7ff866d2016-01-12 17:22:06 +0000124 /**
Sudheer Shanka39cef942016-01-22 20:48:04 +0000125 * Checks if keyguard features are disabled by policy.
Sudheer Shanka7ff866d2016-01-12 17:22:06 +0000126 *
Sudheer Shanka39cef942016-01-22 20:48:04 +0000127 * @param keyguardFeatures Could be any of keyguard features that can be
Sudheer Shanka7ff866d2016-01-12 17:22:06 +0000128 * disabled by {@link android.app.admin.DevicePolicyManager#setKeyguardDisabledFeatures}.
Sudheer Shanka45e298f2016-01-14 18:41:14 +0000129 * @return EnforcedAdmin Object containing the enforced admin component and admin user details,
130 * or {@code null} If the notification features are not disabled. If the restriction is set by
131 * multiple admins, then the admin component will be set to {@code null} and userId to
Sudheer Shanka7ff866d2016-01-12 17:22:06 +0000132 * {@link UserHandle#USER_NULL}.
133 */
Sudheer Shanka39cef942016-01-22 20:48:04 +0000134 public static EnforcedAdmin checkIfKeyguardFeaturesDisabled(Context context,
Clara Bayarri6b6c5a22016-01-28 11:33:25 +0000135 int keyguardFeatures, int userId) {
Sudheer Shanka7ff866d2016-01-12 17:22:06 +0000136 final DevicePolicyManager dpm = (DevicePolicyManager) context.getSystemService(
137 Context.DEVICE_POLICY_SERVICE);
Sudheer Shankac61087102016-01-26 14:00:16 +0000138 if (dpm == null) {
139 return null;
140 }
Sudheer Shanka39cef942016-01-22 20:48:04 +0000141 final UserManager um = (UserManager) context.getSystemService(Context.USER_SERVICE);
142 LockPatternUtils lockPatternUtils = new LockPatternUtils(context);
143 EnforcedAdmin enforcedAdmin = null;
Sudheer Shanka39cef942016-01-22 20:48:04 +0000144 if (um.getUserInfo(userId).isManagedProfile()) {
145 final List<ComponentName> admins = dpm.getActiveAdminsAsUser(userId);
146 if (admins == null) {
147 return null;
148 }
Ruben Brunk74272132016-01-20 21:59:09 -0800149 for (ComponentName admin : admins) {
Sudheer Shanka39cef942016-01-22 20:48:04 +0000150 if ((dpm.getKeyguardDisabledFeatures(admin, userId) & keyguardFeatures) != 0) {
151 if (enforcedAdmin == null) {
152 enforcedAdmin = new EnforcedAdmin(admin, userId);
Ruben Brunk74272132016-01-20 21:59:09 -0800153 } else {
Sudheer Shanka39cef942016-01-22 20:48:04 +0000154 return EnforcedAdmin.MULTIPLE_ENFORCED_ADMIN;
Ruben Brunk74272132016-01-20 21:59:09 -0800155 }
Sudheer Shanka7ff866d2016-01-12 17:22:06 +0000156 }
157 }
Sudheer Shanka39cef942016-01-22 20:48:04 +0000158 } else {
159 // Consider all admins for this user and the profiles that are visible from this
160 // user that do not use a separate work challenge.
161 for (UserInfo userInfo : um.getProfiles(userId)) {
162 final List<ComponentName> admins = dpm.getActiveAdminsAsUser(userInfo.id);
163 if (admins == null) {
Sudheer Shanka56925862016-01-28 19:43:59 +0000164 continue;
Sudheer Shanka39cef942016-01-22 20:48:04 +0000165 }
166 final boolean isSeparateProfileChallengeEnabled =
167 lockPatternUtils.isSeparateProfileChallengeEnabled(userInfo.id);
168 for (ComponentName admin : admins) {
169 if (!isSeparateProfileChallengeEnabled) {
170 if ((dpm.getKeyguardDisabledFeatures(admin, userInfo.id)
171 & keyguardFeatures) != 0) {
172 if (enforcedAdmin == null) {
173 enforcedAdmin = new EnforcedAdmin(admin, userInfo.id);
174 } else {
175 return EnforcedAdmin.MULTIPLE_ENFORCED_ADMIN;
176 }
177 // This same admins could have set policies both on the managed profile
178 // and on the parent. So, if the admin has set the policy on the
179 // managed profile here, we don't need to further check if that admin
180 // has set policy on the parent admin.
181 continue;
182 }
183 }
184 if (userInfo.isManagedProfile()) {
185 // If userInfo.id is a managed profile, we also need to look at
186 // the policies set on the parent.
Sudheer Shanka978fc0d2016-01-28 13:51:10 +0000187 DevicePolicyManager parentDpm = dpm.getParentProfileInstance(userInfo);
Sudheer Shanka39cef942016-01-22 20:48:04 +0000188 if ((parentDpm.getKeyguardDisabledFeatures(admin, userInfo.id)
189 & keyguardFeatures) != 0) {
190 if (enforcedAdmin == null) {
191 enforcedAdmin = new EnforcedAdmin(admin, userInfo.id);
192 } else {
193 return EnforcedAdmin.MULTIPLE_ENFORCED_ADMIN;
194 }
195 }
196 }
197 }
Sudheer Shanka7ff866d2016-01-12 17:22:06 +0000198 }
199 }
200 return enforcedAdmin;
201 }
202
Sudheer Shanka7664cba2016-01-15 11:39:04 +0000203 public static EnforcedAdmin checkIfUninstallBlocked(Context context,
204 String packageName, int userId) {
205 EnforcedAdmin allAppsControlDisallowedAdmin = checkIfRestrictionEnforced(context,
206 UserManager.DISALLOW_APPS_CONTROL, userId);
207 if (allAppsControlDisallowedAdmin != null) {
208 return allAppsControlDisallowedAdmin;
209 }
210 EnforcedAdmin allAppsUninstallDisallowedAdmin = checkIfRestrictionEnforced(context,
211 UserManager.DISALLOW_UNINSTALL_APPS, userId);
212 if (allAppsUninstallDisallowedAdmin != null) {
213 return allAppsUninstallDisallowedAdmin;
214 }
215 IPackageManager ipm = AppGlobals.getPackageManager();
216 try {
217 if (ipm.getBlockUninstallForUser(packageName, userId)) {
Sudheer Shanka56925862016-01-28 19:43:59 +0000218 return getProfileOrDeviceOwner(context, userId);
Sudheer Shanka7664cba2016-01-15 11:39:04 +0000219 }
220 } catch (RemoteException e) {
221 // Nothing to do
222 }
223 return null;
224 }
225
Sudheer Shanka7ff866d2016-01-12 17:22:06 +0000226 /**
Andrei Stingaceanu44af4822016-01-28 20:03:41 +0000227 * Check if an application is suspended.
228 *
229 * @return EnforcedAdmin Object containing the enforced admin component and admin user details,
230 * or {@code null} if the application is not suspended.
231 */
232 public static EnforcedAdmin checkIfApplicationIsSuspended(Context context, String packageName,
233 int userId) {
234 IPackageManager ipm = AppGlobals.getPackageManager();
235 try {
Andrei Stingaceanu355b2322016-02-12 16:43:51 +0000236 if (ipm.isPackageSuspendedForUser(packageName, userId)) {
Sudheer Shanka56925862016-01-28 19:43:59 +0000237 return getProfileOrDeviceOwner(context, userId);
Andrei Stingaceanu44af4822016-01-28 20:03:41 +0000238 }
Andrei Stingaceanuefc4a342016-03-22 14:43:01 +0000239 } catch (RemoteException | IllegalArgumentException e) {
Andrei Stingaceanu44af4822016-01-28 20:03:41 +0000240 // Nothing to do
241 }
242 return null;
243 }
244
Sudheer Shanka56925862016-01-28 19:43:59 +0000245 public static EnforcedAdmin checkIfInputMethodDisallowed(Context context,
246 String packageName, int userId) {
247 DevicePolicyManager dpm = (DevicePolicyManager) context.getSystemService(
248 Context.DEVICE_POLICY_SERVICE);
249 if (dpm == null) {
250 return null;
251 }
252 EnforcedAdmin admin = getProfileOrDeviceOwner(context, userId);
253 boolean permitted = true;
254 if (admin != null) {
255 permitted = dpm.isInputMethodPermittedByAdmin(admin.component,
256 packageName, userId);
257 }
258 int managedProfileId = getManagedProfileId(context, userId);
259 EnforcedAdmin profileAdmin = getProfileOrDeviceOwner(context, managedProfileId);
260 boolean permittedByProfileAdmin = true;
261 if (profileAdmin != null) {
262 permittedByProfileAdmin = dpm.isInputMethodPermittedByAdmin(profileAdmin.component,
263 packageName, managedProfileId);
264 }
265 if (!permitted && !permittedByProfileAdmin) {
266 return EnforcedAdmin.MULTIPLE_ENFORCED_ADMIN;
267 } else if (!permitted) {
268 return admin;
269 } else if (!permittedByProfileAdmin) {
270 return profileAdmin;
271 }
272 return null;
273 }
274
275 public static EnforcedAdmin checkIfAccessibilityServiceDisallowed(Context context,
276 String packageName, int userId) {
277 DevicePolicyManager dpm = (DevicePolicyManager) context.getSystemService(
278 Context.DEVICE_POLICY_SERVICE);
279 if (dpm == null) {
280 return null;
281 }
282 EnforcedAdmin admin = getProfileOrDeviceOwner(context, userId);
283 boolean permitted = true;
284 if (admin != null) {
285 permitted = dpm.isAccessibilityServicePermittedByAdmin(admin.component,
286 packageName, userId);
287 }
288 int managedProfileId = getManagedProfileId(context, userId);
289 EnforcedAdmin profileAdmin = getProfileOrDeviceOwner(context, managedProfileId);
290 boolean permittedByProfileAdmin = true;
291 if (profileAdmin != null) {
292 permittedByProfileAdmin = dpm.isAccessibilityServicePermittedByAdmin(
293 profileAdmin.component, packageName, managedProfileId);
294 }
295 if (!permitted && !permittedByProfileAdmin) {
296 return EnforcedAdmin.MULTIPLE_ENFORCED_ADMIN;
297 } else if (!permitted) {
298 return admin;
299 } else if (!permittedByProfileAdmin) {
300 return profileAdmin;
301 }
302 return null;
303 }
304
305 private static int getManagedProfileId(Context context, int userId) {
306 UserManager um = (UserManager) context.getSystemService(Context.USER_SERVICE);
307 List<UserInfo> userProfiles = um.getProfiles(userId);
308 for (UserInfo uInfo : userProfiles) {
309 if (uInfo.id == userId) {
310 continue;
311 }
312 if (uInfo.isManagedProfile()) {
313 return uInfo.id;
314 }
315 }
316 return UserHandle.USER_NULL;
317 }
318
Andrei Stingaceanu44af4822016-01-28 20:03:41 +0000319 /**
Sudheer Shanka20e22962016-01-18 11:22:45 +0000320 * Check if account management for a specific type of account is disabled by admin.
321 * Only a profile or device owner can disable account management. So, we check if account
322 * management is disabled and return profile or device owner on the calling user.
323 *
324 * @return EnforcedAdmin Object containing the enforced admin component and admin user details,
325 * or {@code null} if the account management is not disabled.
326 */
327 public static EnforcedAdmin checkIfAccountManagementDisabled(Context context,
Sudheer Shanka56925862016-01-28 19:43:59 +0000328 String accountType, int userId) {
Sudheer Shanka20e22962016-01-18 11:22:45 +0000329 if (accountType == null) {
330 return null;
331 }
332 DevicePolicyManager dpm = (DevicePolicyManager) context.getSystemService(
333 Context.DEVICE_POLICY_SERVICE);
Sudheer Shankac61087102016-01-26 14:00:16 +0000334 if (dpm == null) {
335 return null;
336 }
Sudheer Shanka20e22962016-01-18 11:22:45 +0000337 boolean isAccountTypeDisabled = false;
Sudheer Shanka56925862016-01-28 19:43:59 +0000338 String[] disabledTypes = dpm.getAccountTypesWithManagementDisabledAsUser(userId);
Sudheer Shanka20e22962016-01-18 11:22:45 +0000339 for (String type : disabledTypes) {
340 if (accountType.equals(type)) {
341 isAccountTypeDisabled = true;
342 break;
343 }
344 }
345 if (!isAccountTypeDisabled) {
346 return null;
347 }
Sudheer Shanka56925862016-01-28 19:43:59 +0000348 return getProfileOrDeviceOwner(context, userId);
Sudheer Shanka20e22962016-01-18 11:22:45 +0000349 }
350
351 /**
352 * Checks if {@link android.app.admin.DevicePolicyManager#setAutoTimeRequired} is enforced
353 * on the device.
354 *
355 * @return EnforcedAdmin Object containing the device owner component and
356 * userId the device owner is running as, or {@code null} setAutoTimeRequired is not enforced.
357 */
358 public static EnforcedAdmin checkIfAutoTimeRequired(Context context) {
359 DevicePolicyManager dpm = (DevicePolicyManager) context.getSystemService(
360 Context.DEVICE_POLICY_SERVICE);
Sudheer Shankac61087102016-01-26 14:00:16 +0000361 if (dpm == null || !dpm.getAutoTimeRequired()) {
Sudheer Shanka20e22962016-01-18 11:22:45 +0000362 return null;
363 }
364 ComponentName adminComponent = dpm.getDeviceOwnerComponentOnCallingUser();
365 return new EnforcedAdmin(adminComponent, UserHandle.myUserId());
366 }
367
368 /**
Sudheer Shanka56925862016-01-28 19:43:59 +0000369 * Checks if an admin has enforced minimum password quality requirements on the given user.
Sudheer Shanka20e22962016-01-18 11:22:45 +0000370 *
371 * @return EnforcedAdmin Object containing the enforced admin component and admin user details,
372 * or {@code null} if no quality requirements are set. If the requirements are set by
373 * multiple device admins, then the admin component will be set to {@code null} and userId to
374 * {@link UserHandle#USER_NULL}.
375 *
376 */
Sudheer Shanka56925862016-01-28 19:43:59 +0000377 public static EnforcedAdmin checkIfPasswordQualityIsSet(Context context, int userId) {
Sudheer Shanka20e22962016-01-18 11:22:45 +0000378 final DevicePolicyManager dpm = (DevicePolicyManager) context.getSystemService(
379 Context.DEVICE_POLICY_SERVICE);
Sudheer Shankac61087102016-01-26 14:00:16 +0000380 if (dpm == null) {
381 return null;
382 }
Sudheer Shanka56925862016-01-28 19:43:59 +0000383
384 LockPatternUtils lockPatternUtils = new LockPatternUtils(context);
385 EnforcedAdmin enforcedAdmin = null;
386 if (lockPatternUtils.isSeparateProfileChallengeEnabled(userId)) {
387 // userId is managed profile and has a separate challenge, only consider
388 // the admins in that user.
389 final List<ComponentName> admins = dpm.getActiveAdminsAsUser(userId);
390 if (admins == null) {
391 return null;
392 }
Sudheer Shanka0fa74122016-01-21 13:47:51 +0000393 for (ComponentName admin : admins) {
Sudheer Shanka56925862016-01-28 19:43:59 +0000394 if (dpm.getPasswordQuality(admin, userId)
395 > DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
396 if (enforcedAdmin == null) {
397 enforcedAdmin = new EnforcedAdmin(admin, userId);
Sudheer Shanka0fa74122016-01-21 13:47:51 +0000398 } else {
Sudheer Shanka56925862016-01-28 19:43:59 +0000399 return EnforcedAdmin.MULTIPLE_ENFORCED_ADMIN;
Sudheer Shanka0fa74122016-01-21 13:47:51 +0000400 }
Sudheer Shanka20e22962016-01-18 11:22:45 +0000401 }
402 }
Sudheer Shanka56925862016-01-28 19:43:59 +0000403 } else {
404 // Return all admins for this user and the profiles that are visible from this
405 // user that do not use a separate work challenge.
406 final UserManager um = (UserManager) context.getSystemService(Context.USER_SERVICE);
407 for (UserInfo userInfo : um.getProfiles(userId)) {
408 final List<ComponentName> admins = dpm.getActiveAdminsAsUser(userInfo.id);
409 if (admins == null) {
410 continue;
411 }
412 final boolean isSeparateProfileChallengeEnabled =
413 lockPatternUtils.isSeparateProfileChallengeEnabled(userInfo.id);
414 for (ComponentName admin : admins) {
415 if (!isSeparateProfileChallengeEnabled) {
416 if (dpm.getPasswordQuality(admin, userInfo.id)
417 > DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
418 if (enforcedAdmin == null) {
419 enforcedAdmin = new EnforcedAdmin(admin, userInfo.id);
420 } else {
421 return EnforcedAdmin.MULTIPLE_ENFORCED_ADMIN;
422 }
423 // This same admins could have set policies both on the managed profile
424 // and on the parent. So, if the admin has set the policy on the
425 // managed profile here, we don't need to further check if that admin
426 // has set policy on the parent admin.
427 continue;
428 }
429 }
430 if (userInfo.isManagedProfile()) {
431 // If userInfo.id is a managed profile, we also need to look at
432 // the policies set on the parent.
433 DevicePolicyManager parentDpm = dpm.getParentProfileInstance(userInfo);
434 if (parentDpm.getPasswordQuality(admin, userInfo.id)
435 > DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
436 if (enforcedAdmin == null) {
437 enforcedAdmin = new EnforcedAdmin(admin, userInfo.id);
438 } else {
439 return EnforcedAdmin.MULTIPLE_ENFORCED_ADMIN;
440 }
441 }
442 }
443 }
Sudheer Shanka20e22962016-01-18 11:22:45 +0000444 }
445 }
446 return enforcedAdmin;
447 }
448
Sudheer Shanka45e298f2016-01-14 18:41:14 +0000449 /**
450 * Checks if any admin has set maximum time to lock.
451 *
452 * @return EnforcedAdmin Object containing the enforced admin component and admin user details,
453 * or {@code null} if no admin has set this restriction. If multiple admins has set this, then
454 * the admin component will be set to {@code null} and userId to {@link UserHandle#USER_NULL}
455 */
456 public static EnforcedAdmin checkIfMaximumTimeToLockIsSet(Context context) {
457 final DevicePolicyManager dpm = (DevicePolicyManager) context.getSystemService(
458 Context.DEVICE_POLICY_SERVICE);
459 LockPatternUtils lockPatternUtils = new LockPatternUtils(context);
460 EnforcedAdmin enforcedAdmin = null;
461 final int userId = UserHandle.myUserId();
462 if (lockPatternUtils.isSeparateProfileChallengeEnabled(userId)) {
Sudheer Shanka56925862016-01-28 19:43:59 +0000463 // userId is managed profile and has a separate challenge, only consider
464 // the admins in that user.
Sudheer Shanka45e298f2016-01-14 18:41:14 +0000465 final List<ComponentName> admins = dpm.getActiveAdminsAsUser(userId);
466 if (admins == null) {
467 return null;
468 }
469 for (ComponentName admin : admins) {
470 if (dpm.getMaximumTimeToLock(admin, userId) > 0) {
471 if (enforcedAdmin == null) {
472 enforcedAdmin = new EnforcedAdmin(admin, userId);
473 } else {
474 return EnforcedAdmin.MULTIPLE_ENFORCED_ADMIN;
475 }
476 }
477 }
478 } else {
479 // Return all admins for this user and the profiles that are visible from this
480 // user that do not use a separate work challenge.
481 final UserManager um = (UserManager) context.getSystemService(Context.USER_SERVICE);
482 for (UserInfo userInfo : um.getProfiles(userId)) {
483 final List<ComponentName> admins = dpm.getActiveAdminsAsUser(userInfo.id);
484 if (admins == null) {
Sudheer Shanka56925862016-01-28 19:43:59 +0000485 continue;
Sudheer Shanka45e298f2016-01-14 18:41:14 +0000486 }
Sudheer Shanka39cef942016-01-22 20:48:04 +0000487 final boolean isSeparateProfileChallengeEnabled =
488 lockPatternUtils.isSeparateProfileChallengeEnabled(userInfo.id);
Sudheer Shanka45e298f2016-01-14 18:41:14 +0000489 for (ComponentName admin : admins) {
Sudheer Shanka39cef942016-01-22 20:48:04 +0000490 if (!isSeparateProfileChallengeEnabled) {
Sudheer Shanka45e298f2016-01-14 18:41:14 +0000491 if (dpm.getMaximumTimeToLock(admin, userInfo.id) > 0) {
492 if (enforcedAdmin == null) {
493 enforcedAdmin = new EnforcedAdmin(admin, userInfo.id);
494 } else {
495 return EnforcedAdmin.MULTIPLE_ENFORCED_ADMIN;
496 }
497 // This same admins could have set policies both on the managed profile
498 // and on the parent. So, if the admin has set the policy on the
499 // managed profile here, we don't need to further check if that admin
500 // has set policy on the parent admin.
501 continue;
502 }
503 }
504 if (userInfo.isManagedProfile()) {
505 // If userInfo.id is a managed profile, we also need to look at
506 // the policies set on the parent.
Sudheer Shanka978fc0d2016-01-28 13:51:10 +0000507 DevicePolicyManager parentDpm = dpm.getParentProfileInstance(userInfo);
Sudheer Shanka45e298f2016-01-14 18:41:14 +0000508 if (parentDpm.getMaximumTimeToLock(admin, userInfo.id) > 0) {
509 if (enforcedAdmin == null) {
510 enforcedAdmin = new EnforcedAdmin(admin, userInfo.id);
511 } else {
512 return EnforcedAdmin.MULTIPLE_ENFORCED_ADMIN;
513 }
514 }
515 }
516 }
517 }
518 }
519 return enforcedAdmin;
520 }
521
Sudheer Shanka56925862016-01-28 19:43:59 +0000522 public static EnforcedAdmin getProfileOrDeviceOwner(Context context, int userId) {
523 if (userId == UserHandle.USER_NULL) {
524 return null;
525 }
Sudheer Shanka20e22962016-01-18 11:22:45 +0000526 final DevicePolicyManager dpm = (DevicePolicyManager) context.getSystemService(
527 Context.DEVICE_POLICY_SERVICE);
Sudheer Shankac61087102016-01-26 14:00:16 +0000528 if (dpm == null) {
529 return null;
530 }
Sudheer Shanka56925862016-01-28 19:43:59 +0000531 ComponentName adminComponent = dpm.getProfileOwnerAsUser(userId);
Sudheer Shanka20e22962016-01-18 11:22:45 +0000532 if (adminComponent != null) {
Sudheer Shanka56925862016-01-28 19:43:59 +0000533 return new EnforcedAdmin(adminComponent, userId);
Sudheer Shanka20e22962016-01-18 11:22:45 +0000534 }
Sudheer Shanka56925862016-01-28 19:43:59 +0000535 if (dpm.getDeviceOwnerUserId() == userId) {
536 adminComponent = dpm.getDeviceOwnerComponentOnAnyUser();
537 if (adminComponent != null) {
538 return new EnforcedAdmin(adminComponent, userId);
539 }
Sudheer Shanka20e22962016-01-18 11:22:45 +0000540 }
541 return null;
542 }
543
Sudheer Shanka1d0169b2016-02-03 00:25:50 +0000544 public static EnforcedAdmin getDeviceOwner(Context context) {
545 final DevicePolicyManager dpm = (DevicePolicyManager) context.getSystemService(
546 Context.DEVICE_POLICY_SERVICE);
547 if (dpm == null) {
548 return null;
549 }
550 ComponentName adminComponent = dpm.getDeviceOwnerComponentOnAnyUser();
551 if (adminComponent != null) {
552 return new EnforcedAdmin(adminComponent, dpm.getDeviceOwnerUserId());
553 }
554 return null;
555 }
556
Sudheer Shanka20e22962016-01-18 11:22:45 +0000557 /**
Sudheer Shanka7ff866d2016-01-12 17:22:06 +0000558 * Set the menu item as disabled by admin by adding a restricted padlock at the end of the
559 * text and set the click listener which will send an intent to show the admin support details
Sudheer Shanka7664cba2016-01-15 11:39:04 +0000560 * dialog. If the admin is null, remove the padlock and disabled color span. When the admin is
561 * null, we also set the OnMenuItemClickListener to null, so if you want to set a custom
562 * OnMenuItemClickListener, set it after calling this method.
Sudheer Shanka7ff866d2016-01-12 17:22:06 +0000563 */
564 public static void setMenuItemAsDisabledByAdmin(final Context context,
565 final MenuItem item, final EnforcedAdmin admin) {
566 SpannableStringBuilder sb = new SpannableStringBuilder(item.getTitle());
567 removeExistingRestrictedSpans(sb);
568
Sudheer Shanka7664cba2016-01-15 11:39:04 +0000569 if (admin != null) {
570 final int disabledColor = context.getColor(R.color.disabled_text_color);
571 sb.setSpan(new ForegroundColorSpan(disabledColor), 0, sb.length(),
572 Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
573 ImageSpan image = new RestrictedLockImageSpan(context);
574 sb.append(" ", image, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
Sudheer Shanka7ff866d2016-01-12 17:22:06 +0000575
Sudheer Shanka7664cba2016-01-15 11:39:04 +0000576 item.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
577 @Override
578 public boolean onMenuItemClick(MenuItem item) {
579 sendShowAdminSupportDetailsIntent(context, admin);
580 return true;
581 }
582 });
583 } else {
584 item.setOnMenuItemClickListener(null);
585 }
586 item.setTitle(sb);
Sudheer Shanka7ff866d2016-01-12 17:22:06 +0000587 }
588
589 private static void removeExistingRestrictedSpans(SpannableStringBuilder sb) {
590 final int length = sb.length();
591 RestrictedLockImageSpan[] imageSpans = sb.getSpans(length - 1, length,
592 RestrictedLockImageSpan.class);
593 for (ImageSpan span : imageSpans) {
Sudheer Shanka20e22962016-01-18 11:22:45 +0000594 final int start = sb.getSpanStart(span);
595 final int end = sb.getSpanEnd(span);
Sudheer Shanka7ff866d2016-01-12 17:22:06 +0000596 sb.removeSpan(span);
Sudheer Shanka20e22962016-01-18 11:22:45 +0000597 sb.delete(start, end);
Sudheer Shanka7ff866d2016-01-12 17:22:06 +0000598 }
599 ForegroundColorSpan[] colorSpans = sb.getSpans(0, length, ForegroundColorSpan.class);
600 for (ForegroundColorSpan span : colorSpans) {
601 sb.removeSpan(span);
602 }
603 }
604
605 /**
606 * Send the intent to trigger the {@link android.settings.ShowAdminSupportDetailsDialog}.
607 */
608 public static void sendShowAdminSupportDetailsIntent(Context context, EnforcedAdmin admin) {
Sudheer Shanka1c7cda82015-12-31 14:46:02 +0000609 final Intent intent = getShowAdminSupportDetailsIntent(context, admin);
Sudheer Shanka7ff866d2016-01-12 17:22:06 +0000610 int adminUserId = UserHandle.myUserId();
Sudheer Shanka1c7cda82015-12-31 14:46:02 +0000611 if (admin.userId != UserHandle.USER_NULL) {
612 adminUserId = admin.userId;
613 }
614 context.startActivityAsUser(intent, new UserHandle(adminUserId));
615 }
616
617 public static Intent getShowAdminSupportDetailsIntent(Context context, EnforcedAdmin admin) {
618 final Intent intent = new Intent(Settings.ACTION_SHOW_ADMIN_SUPPORT_DETAILS);
Sudheer Shanka7ff866d2016-01-12 17:22:06 +0000619 if (admin != null) {
620 if (admin.component != null) {
621 intent.putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN, admin.component);
622 }
Sudheer Shanka1c7cda82015-12-31 14:46:02 +0000623 int adminUserId = UserHandle.myUserId();
Sudheer Shanka7ff866d2016-01-12 17:22:06 +0000624 if (admin.userId != UserHandle.USER_NULL) {
625 adminUserId = admin.userId;
626 }
627 intent.putExtra(Intent.EXTRA_USER_ID, adminUserId);
628 }
Sudheer Shanka1c7cda82015-12-31 14:46:02 +0000629 return intent;
Sudheer Shanka7ff866d2016-01-12 17:22:06 +0000630 }
631
632 public static void setTextViewPadlock(Context context,
633 TextView textView, boolean showPadlock) {
634 final SpannableStringBuilder sb = new SpannableStringBuilder(textView.getText());
635 removeExistingRestrictedSpans(sb);
636 if (showPadlock) {
637 final ImageSpan image = new RestrictedLockImageSpan(context);
638 sb.append(" ", image, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
639 }
640 textView.setText(sb);
641 }
642
Sudheer Shanka9f77a712016-01-12 19:38:53 +0000643 /**
644 * Takes a {@link android.widget.TextView} and applies an alpha so that the text looks like
645 * disabled and appends a padlock to the text. This assumes that there are no
646 * ForegroundColorSpans and RestrictedLockImageSpans used on the TextView.
647 */
648 public static void setTextViewAsDisabledByAdmin(Context context,
649 TextView textView, boolean disabled) {
650 final SpannableStringBuilder sb = new SpannableStringBuilder(textView.getText());
651 removeExistingRestrictedSpans(sb);
652 if (disabled) {
653 final int disabledColor = context.getColor(R.color.disabled_text_color);
654 sb.setSpan(new ForegroundColorSpan(disabledColor), 0, sb.length(),
655 Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
Sudheer Shankaf271fd52016-03-07 13:13:22 -0800656 textView.setCompoundDrawables(null, null, getRestrictedPadlock(context), null);
657 textView.setCompoundDrawablePadding(context.getResources().getDimensionPixelSize(
658 R.dimen.restricted_icon_padding));
659 } else {
660 textView.setCompoundDrawables(null, null, null, null);
Sudheer Shanka9f77a712016-01-12 19:38:53 +0000661 }
662 textView.setText(sb);
663 }
664
Sudheer Shanka7ff866d2016-01-12 17:22:06 +0000665 public static class EnforcedAdmin {
666 public ComponentName component = null;
667 public int userId = UserHandle.USER_NULL;
668
Sudheer Shanka45e298f2016-01-14 18:41:14 +0000669 // We use this to represent the case where a policy is enforced by multiple admins.
670 public final static EnforcedAdmin MULTIPLE_ENFORCED_ADMIN = new EnforcedAdmin();
671
Sudheer Shanka7ff866d2016-01-12 17:22:06 +0000672 public EnforcedAdmin(ComponentName component, int userId) {
673 this.component = component;
674 this.userId = userId;
675 }
676
Sudheer Shanka1c09db22016-01-18 11:18:35 +0000677 public EnforcedAdmin(EnforcedAdmin other) {
678 if (other == null) {
679 throw new IllegalArgumentException();
680 }
681 this.component = other.component;
682 this.userId = other.userId;
683 }
684
685 public EnforcedAdmin() {}
686
Sudheer Shanka1c7cda82015-12-31 14:46:02 +0000687 @Override
688 public boolean equals(Object object) {
689 if (object == this) return true;
690 if (!(object instanceof EnforcedAdmin)) return false;
691 EnforcedAdmin other = (EnforcedAdmin) object;
692 if (userId != other.userId) {
693 return false;
694 }
695 if ((component == null && other == null) ||
696 (component != null && component.equals(other))) {
697 return true;
698 }
699 return false;
700 }
701
702 @Override
703 public String toString() {
704 return "EnforcedAdmin{component=" + component + ",userId=" + userId + "}";
705 }
706
707 public void copyTo(EnforcedAdmin other) {
708 if (other == null) {
Sudheer Shanka1c09db22016-01-18 11:18:35 +0000709 throw new IllegalArgumentException();
Sudheer Shanka1c7cda82015-12-31 14:46:02 +0000710 }
711 other.component = component;
712 other.userId = userId;
713 }
Sudheer Shanka7ff866d2016-01-12 17:22:06 +0000714 }
Ruben Brunk74272132016-01-20 21:59:09 -0800715}