OSDN Git Service

d3c1364adac8d2096af71b7c7f9411ee7952f92a
[android-x86/frameworks-base.git] / packages / SettingsLib / src / com / android / settingslib / RestrictedLockUtils.java
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.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;
39
40 import com.android.internal.widget.LockPatternUtils;
41
42 import java.util.List;
43
44 /**
45  * Utility class to host methods usable in adding a restricted padlock icon and showing admin
46  * support message dialog.
47  */
48 public class RestrictedLockUtils {
49     /**
50      * @return drawables for displaying with settings that are locked by a device admin.
51      */
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;
58     }
59
60     /**
61      * Checks if a restriction is enforced on a user and returns the enforced admin and
62      * admin userId.
63      *
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}.
70      */
71     public static EnforcedAdmin checkIfRestrictionEnforced(Context context,
72             String userRestriction, int userId) {
73         DevicePolicyManager dpm = (DevicePolicyManager) context.getSystemService(
74                 Context.DEVICE_POLICY_SERVICE);
75         if (dpm == null) {
76             return null;
77         }
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;
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) {
94                 Bundle enforcedRestrictions = dpm.getUserRestrictions(profileOwner, userId);
95                 if (enforcedRestrictions != null
96                         && enforcedRestrictions.getBoolean(userRestriction, false)) {
97                     enforcedByProfileOwner = true;
98                 }
99             }
100         }
101
102         if (!enforcedByDeviceOwner && !enforcedByProfileOwner) {
103             return null;
104         }
105
106         EnforcedAdmin admin = null;
107         if (enforcedByDeviceOwner && enforcedByProfileOwner) {
108             admin = new EnforcedAdmin();
109         } else if (enforcedByDeviceOwner) {
110             admin = new EnforcedAdmin(deviceOwner, deviceOwnerUserId);
111         } else {
112             admin = new EnforcedAdmin(profileOwner, userId);
113         }
114         return admin;
115     }
116
117     /**
118      * Checks if keyguard features are disabled by policy.
119      *
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}.
126      */
127     public static EnforcedAdmin checkIfKeyguardFeaturesDisabled(Context context,
128             int keyguardFeatures) {
129         final DevicePolicyManager dpm = (DevicePolicyManager) context.getSystemService(
130                 Context.DEVICE_POLICY_SERVICE);
131         if (dpm == null) {
132             return null;
133         }
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) {
141                 return null;
142             }
143             for (ComponentName admin : admins) {
144                 if ((dpm.getKeyguardDisabledFeatures(admin, userId) & keyguardFeatures) != 0) {
145                     if (enforcedAdmin == null) {
146                         enforcedAdmin = new EnforcedAdmin(admin, userId);
147                     } else {
148                         return EnforcedAdmin.MULTIPLE_ENFORCED_ADMIN;
149                     }
150                 }
151             }
152         } else {
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) {
158                     return null;
159                 }
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);
168                             } else {
169                                 return EnforcedAdmin.MULTIPLE_ENFORCED_ADMIN;
170                             }
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.
175                             continue;
176                         }
177                     }
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);
186                             } else {
187                                 return EnforcedAdmin.MULTIPLE_ENFORCED_ADMIN;
188                             }
189                         }
190                     }
191                 }
192             }
193         }
194         return enforcedAdmin;
195     }
196
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;
203         }
204         EnforcedAdmin allAppsUninstallDisallowedAdmin = checkIfRestrictionEnforced(context,
205                 UserManager.DISALLOW_UNINSTALL_APPS, userId);
206         if (allAppsUninstallDisallowedAdmin != null) {
207             return allAppsUninstallDisallowedAdmin;
208         }
209         IPackageManager ipm = AppGlobals.getPackageManager();
210         try {
211             if (ipm.getBlockUninstallForUser(packageName, userId)) {
212                 DevicePolicyManager dpm = (DevicePolicyManager) context.getSystemService(
213                         Context.DEVICE_POLICY_SERVICE);
214                 if (dpm == null) {
215                     return null;
216                 }
217                 ComponentName admin = dpm.getProfileOwner();
218                 if (admin == null) {
219                     admin = dpm.getDeviceOwnerComponentOnCallingUser();
220                 }
221                 return new EnforcedAdmin(admin, UserHandle.myUserId());
222             }
223         } catch (RemoteException e) {
224             // Nothing to do
225         }
226         return null;
227     }
228
229     /**
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.
233      *
234      * @return EnforcedAdmin Object containing the enforced admin component and admin user details,
235      * or {@code null} if the account management is not disabled.
236      */
237     public static EnforcedAdmin checkIfAccountManagementDisabled(Context context,
238             String accountType) {
239         if (accountType == null) {
240             return null;
241         }
242         DevicePolicyManager dpm = (DevicePolicyManager) context.getSystemService(
243                 Context.DEVICE_POLICY_SERVICE);
244         if (dpm == null) {
245             return null;
246         }
247         boolean isAccountTypeDisabled = false;
248         String[] disabledTypes = dpm.getAccountTypesWithManagementDisabled();
249         for (String type : disabledTypes) {
250             if (accountType.equals(type)) {
251                 isAccountTypeDisabled = true;
252                 break;
253             }
254         }
255         if (!isAccountTypeDisabled) {
256             return null;
257         }
258         return getProfileOrDeviceOwnerOnCallingUser(context);
259     }
260
261     /**
262      * Checks if {@link android.app.admin.DevicePolicyManager#setAutoTimeRequired} is enforced
263      * on the device.
264      *
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.
267      */
268     public static EnforcedAdmin checkIfAutoTimeRequired(Context context) {
269         DevicePolicyManager dpm = (DevicePolicyManager) context.getSystemService(
270                 Context.DEVICE_POLICY_SERVICE);
271         if (dpm == null || !dpm.getAutoTimeRequired()) {
272             return null;
273         }
274         ComponentName adminComponent = dpm.getDeviceOwnerComponentOnCallingUser();
275         return new EnforcedAdmin(adminComponent, UserHandle.myUserId());
276     }
277
278     /**
279      * Checks if an admin has enforced minimum password quality requirements on the device.
280      *
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}.
285      *
286      */
287     public static EnforcedAdmin checkIfPasswordQualityIsSet(Context context) {
288         final DevicePolicyManager dpm = (DevicePolicyManager) context.getSystemService(
289                 Context.DEVICE_POLICY_SERVICE);
290         if (dpm == null) {
291             return null;
292         }
293         boolean isDisabledByMultipleAdmins = false;
294         ComponentName adminComponent = null;
295         List<ComponentName> admins = dpm.getActiveAdmins();
296         int quality;
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;
303                     } else {
304                         isDisabledByMultipleAdmins = true;
305                         break;
306                     }
307                 }
308             }
309         }
310         EnforcedAdmin enforcedAdmin = null;
311         if (adminComponent != null) {
312             if (!isDisabledByMultipleAdmins) {
313                 enforcedAdmin = new EnforcedAdmin(adminComponent, UserHandle.myUserId());
314             } else {
315                 enforcedAdmin = new EnforcedAdmin();
316             }
317         }
318         return enforcedAdmin;
319     }
320
321     /**
322      * Checks if any admin has set maximum time to lock.
323      *
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}
327      */
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) {
338                 return null;
339             }
340             for (ComponentName admin : admins) {
341                 if (dpm.getMaximumTimeToLock(admin, userId) > 0) {
342                     if (enforcedAdmin == null) {
343                         enforcedAdmin = new EnforcedAdmin(admin, userId);
344                     } else {
345                         return EnforcedAdmin.MULTIPLE_ENFORCED_ADMIN;
346                     }
347                 }
348             }
349         } else {
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) {
356                     return null;
357                 }
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);
365                             } else {
366                                 return EnforcedAdmin.MULTIPLE_ENFORCED_ADMIN;
367                             }
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.
372                             continue;
373                         }
374                     }
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);
382                             } else {
383                                 return EnforcedAdmin.MULTIPLE_ENFORCED_ADMIN;
384                             }
385                         }
386                     }
387                 }
388             }
389         }
390         return enforcedAdmin;
391     }
392
393     public static EnforcedAdmin getProfileOrDeviceOwnerOnCallingUser(Context context) {
394         final DevicePolicyManager dpm = (DevicePolicyManager) context.getSystemService(
395                 Context.DEVICE_POLICY_SERVICE);
396         if (dpm == null) {
397             return null;
398         }
399         ComponentName adminComponent = dpm.getDeviceOwnerComponentOnCallingUser();
400         if (adminComponent != null) {
401             return new EnforcedAdmin(adminComponent, UserHandle.myUserId());
402         }
403         adminComponent = dpm.getProfileOwner();
404         if (adminComponent != null) {
405             return new EnforcedAdmin(adminComponent, UserHandle.myUserId());
406         }
407         return null;
408     }
409
410     /**
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.
416      */
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);
421
422         if (admin != null) {
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);
428
429             item.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
430                 @Override
431                 public boolean onMenuItemClick(MenuItem item) {
432                     sendShowAdminSupportDetailsIntent(context, admin);
433                     return true;
434                 }
435             });
436         } else {
437             item.setOnMenuItemClickListener(null);
438         }
439         item.setTitle(sb);
440     }
441
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);
449             sb.removeSpan(span);
450             sb.delete(start, end);
451         }
452         ForegroundColorSpan[] colorSpans = sb.getSpans(0, length, ForegroundColorSpan.class);
453         for (ForegroundColorSpan span : colorSpans) {
454             sb.removeSpan(span);
455         }
456     }
457
458     /**
459      * Send the intent to trigger the {@link android.settings.ShowAdminSupportDetailsDialog}.
460      */
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;
466         }
467         context.startActivityAsUser(intent, new UserHandle(adminUserId));
468     }
469
470     public static Intent getShowAdminSupportDetailsIntent(Context context, EnforcedAdmin admin) {
471         final Intent intent = new Intent(Settings.ACTION_SHOW_ADMIN_SUPPORT_DETAILS);
472         if (admin != null) {
473             if (admin.component != null) {
474                 intent.putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN, admin.component);
475             }
476             int adminUserId = UserHandle.myUserId();
477             if (admin.userId != UserHandle.USER_NULL) {
478                 adminUserId = admin.userId;
479             }
480             intent.putExtra(Intent.EXTRA_USER_ID, adminUserId);
481         }
482         return intent;
483     }
484
485     public static void setTextViewPadlock(Context context,
486             TextView textView, boolean showPadlock) {
487         final SpannableStringBuilder sb = new SpannableStringBuilder(textView.getText());
488         removeExistingRestrictedSpans(sb);
489         if (showPadlock) {
490             final ImageSpan image = new RestrictedLockImageSpan(context);
491             sb.append(" ", image, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
492         }
493         textView.setText(sb);
494     }
495
496     /**
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.
500      */
501     public static void setTextViewAsDisabledByAdmin(Context context,
502             TextView textView, boolean disabled) {
503         final SpannableStringBuilder sb = new SpannableStringBuilder(textView.getText());
504         removeExistingRestrictedSpans(sb);
505         if (disabled) {
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);
511         }
512         textView.setText(sb);
513     }
514
515     public static class EnforcedAdmin {
516         public ComponentName component = null;
517         public int userId = UserHandle.USER_NULL;
518
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();
521
522         public EnforcedAdmin(ComponentName component, int userId) {
523             this.component = component;
524             this.userId = userId;
525         }
526
527         public EnforcedAdmin(EnforcedAdmin other) {
528             if (other == null) {
529                 throw new IllegalArgumentException();
530             }
531             this.component = other.component;
532             this.userId = other.userId;
533         }
534
535         public EnforcedAdmin() {}
536
537         @Override
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) {
543                 return false;
544             }
545             if ((component == null && other == null) ||
546                     (component != null && component.equals(other))) {
547                 return true;
548             }
549             return false;
550         }
551
552         @Override
553         public String toString() {
554             return "EnforcedAdmin{component=" + component + ",userId=" + userId + "}";
555         }
556
557         public void copyTo(EnforcedAdmin other) {
558             if (other == null) {
559                 throw new IllegalArgumentException();
560             }
561             other.component = component;
562             other.userId = userId;
563         }
564     }
565 }