1 /*
2  * Copyright (C) 2017 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.settings.password;
18 
19 import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_NONE;
20 
21 import android.app.admin.DevicePolicyManager;
22 import android.app.admin.DevicePolicyManager.PasswordComplexity;
23 import android.app.admin.PasswordMetrics;
24 import android.content.Context;
25 import android.os.UserHandle;
26 
27 import androidx.annotation.NonNull;
28 import androidx.annotation.VisibleForTesting;
29 
30 import com.android.internal.widget.LockPatternUtils;
31 import com.android.settings.R;
32 
33 import java.util.ArrayList;
34 import java.util.List;
35 
36 /**
37  * A controller for ChooseLockGeneric, and other similar classes which shows a list of possible
38  * screen locks for the user to choose from.
39  */
40 public class ChooseLockGenericController {
41 
42     private final Context mContext;
43     private final int mUserId;
44     @PasswordComplexity private final int mRequestedMinComplexity;
45     private ManagedLockPasswordProvider mManagedPasswordProvider;
46     private DevicePolicyManager mDpm;
47     private final LockPatternUtils mLockPatternUtils;
48 
ChooseLockGenericController(Context context, int userId)49     public ChooseLockGenericController(Context context, int userId) {
50         this(
51                 context,
52                 userId,
53                 PASSWORD_COMPLEXITY_NONE,
54                 new LockPatternUtils(context));
55     }
56 
57     /**
58      * @param requestedMinComplexity specifies the min password complexity to be taken into account
59      *                               when determining the available screen lock types
60      */
ChooseLockGenericController(Context context, int userId, @PasswordComplexity int requestedMinComplexity, LockPatternUtils lockPatternUtils)61     public ChooseLockGenericController(Context context, int userId,
62             @PasswordComplexity int requestedMinComplexity, LockPatternUtils lockPatternUtils) {
63         this(
64                 context,
65                 userId,
66                 requestedMinComplexity,
67                 context.getSystemService(DevicePolicyManager.class),
68                 ManagedLockPasswordProvider.get(context, userId),
69                 lockPatternUtils);
70     }
71 
72     @VisibleForTesting
ChooseLockGenericController( Context context, int userId, @PasswordComplexity int requestedMinComplexity, DevicePolicyManager dpm, ManagedLockPasswordProvider managedLockPasswordProvider, LockPatternUtils lockPatternUtils)73     ChooseLockGenericController(
74             Context context,
75             int userId,
76             @PasswordComplexity int requestedMinComplexity,
77             DevicePolicyManager dpm,
78             ManagedLockPasswordProvider managedLockPasswordProvider,
79             LockPatternUtils lockPatternUtils) {
80         mContext = context;
81         mUserId = userId;
82         mRequestedMinComplexity = requestedMinComplexity;
83         mManagedPasswordProvider = managedLockPasswordProvider;
84         mDpm = dpm;
85         mLockPatternUtils = lockPatternUtils;
86     }
87 
88     /**
89      * Returns the highest quality among the specified {@code quality}, the quality required by
90      * {@link DevicePolicyManager#getPasswordQuality}, and the quality required by min password
91      * complexity.
92      */
upgradeQuality(int quality)93     public int upgradeQuality(int quality) {
94         // Compare specified quality and dpm quality
95         // TODO(b/142781408): convert from quality to credential type once PIN is supported.
96         int dpmUpgradedQuality = Math.max(quality, mDpm.getPasswordQuality(null, mUserId));
97         return Math.max(dpmUpgradedQuality,
98                 PasswordMetrics.complexityLevelToMinQuality(mRequestedMinComplexity));
99     }
100 
101     /**
102      * Whether the given screen lock type should be visible in the given context.
103      */
isScreenLockVisible(ScreenLockType type)104     public boolean isScreenLockVisible(ScreenLockType type) {
105         final boolean managedProfile = mUserId != UserHandle.myUserId();
106         switch (type) {
107             case NONE:
108                 return !mContext.getResources().getBoolean(R.bool.config_hide_none_security_option)
109                     && !managedProfile; // Profiles should use unified challenge instead.
110             case SWIPE:
111                 return !mContext.getResources().getBoolean(R.bool.config_hide_swipe_security_option)
112                     && !managedProfile; // Swipe doesn't make sense for profiles.
113             case MANAGED:
114                 return mManagedPasswordProvider.isManagedPasswordChoosable();
115             case PIN:
116             case PATTERN:
117             case PASSWORD:
118                 // Hide the secure lock screen options if the device doesn't support the secure lock
119                 // screen feature.
120                 return mLockPatternUtils.hasSecureLockScreen();
121         }
122         return true;
123     }
124 
125     /**
126      * Whether screen lock with {@code type} should be enabled.
127      *
128      * @param type The screen lock type.
129      * @param quality The minimum required quality. This can either be requirement by device policy
130      *                manager or because some flow only makes sense with secure lock screens.
131      */
isScreenLockEnabled(ScreenLockType type, int quality)132     public boolean isScreenLockEnabled(ScreenLockType type, int quality) {
133         return type.maxQuality >= quality;
134     }
135 
136     /**
137      * Whether screen lock with {@code type} is disabled by device policy admin.
138      *
139      * @param type The screen lock type.
140      * @param adminEnforcedQuality The minimum quality that the admin enforces.
141      */
isScreenLockDisabledByAdmin(ScreenLockType type, int adminEnforcedQuality)142     public boolean isScreenLockDisabledByAdmin(ScreenLockType type, int adminEnforcedQuality) {
143         boolean disabledByAdmin = type.maxQuality < adminEnforcedQuality;
144         if (type == ScreenLockType.MANAGED) {
145             disabledByAdmin = disabledByAdmin
146                     || !mManagedPasswordProvider.isManagedPasswordChoosable();
147         }
148         return disabledByAdmin;
149     }
150 
151     /**
152      * User friendly title for the given screen lock type.
153      */
154     public CharSequence getTitle(ScreenLockType type) {
155         switch (type) {
156             case NONE:
157                 return mContext.getText(R.string.unlock_set_unlock_off_title);
158             case SWIPE:
159                 return mContext.getText(R.string.unlock_set_unlock_none_title);
160             case PATTERN:
161                 return mContext.getText(R.string.unlock_set_unlock_pattern_title);
162             case PIN:
163                 return mContext.getText(R.string.unlock_set_unlock_pin_title);
164             case PASSWORD:
165                 return mContext.getText(R.string.unlock_set_unlock_password_title);
166             case MANAGED:
167                 return mManagedPasswordProvider.getPickerOptionTitle(false);
168         }
169         return null;
170     }
171 
172     /**
173      * Gets a list of screen locks that should be visible for the given quality. The returned list
174      * is ordered in the natural order of the enum (the order those enums were defined).
175      *
176      * @param quality The minimum quality required in the context of the current flow. This should
177      *                be one of the constants defined in
178      *                {@code DevicePolicyManager#PASSWORD_QUALITY_*}.
179      * @param includeDisabled Whether to include screen locks disabled by {@code quality}
180      *                        requirements in the returned list.
181      */
182     @NonNull
183     public List<ScreenLockType> getVisibleScreenLockTypes(int quality, boolean includeDisabled) {
184         int upgradedQuality = upgradeQuality(quality);
185         List<ScreenLockType> locks = new ArrayList<>();
186         // EnumSet's iterator guarantees the natural order of the enums
187         for (ScreenLockType lock : ScreenLockType.values()) {
188             if (isScreenLockVisible(lock)) {
189                 if (includeDisabled || isScreenLockEnabled(lock, upgradedQuality)) {
190                     locks.add(lock);
191                 }
192             }
193         }
194         return locks;
195     }
196 }
197