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         int dpmUpgradedQuality = Math.max(quality, mDpm.getPasswordQuality(null, mUserId));
96         return Math.max(dpmUpgradedQuality,
97                 PasswordMetrics.complexityLevelToMinQuality(mRequestedMinComplexity));
98     }
99 
100     /**
101      * Whether the given screen lock type should be visible in the given context.
102      */
isScreenLockVisible(ScreenLockType type)103     public boolean isScreenLockVisible(ScreenLockType type) {
104         final boolean managedProfile = mUserId != UserHandle.myUserId();
105         switch (type) {
106             case NONE:
107                 return !mContext.getResources().getBoolean(R.bool.config_hide_none_security_option)
108                     && !managedProfile; // Profiles should use unified challenge instead.
109             case SWIPE:
110                 return !mContext.getResources().getBoolean(R.bool.config_hide_swipe_security_option)
111                     && !managedProfile; // Swipe doesn't make sense for profiles.
112             case MANAGED:
113                 return mManagedPasswordProvider.isManagedPasswordChoosable();
114             case PIN:
115             case PATTERN:
116             case PASSWORD:
117                 // Hide the secure lock screen options if the device doesn't support the secure lock
118                 // screen feature.
119                 return mLockPatternUtils.hasSecureLockScreen();
120         }
121         return true;
122     }
123 
124     /**
125      * Whether screen lock with {@code type} should be enabled.
126      *
127      * @param type The screen lock type.
128      * @param quality The minimum required quality. This can either be requirement by device policy
129      *                manager or because some flow only makes sense with secure lock screens.
130      */
isScreenLockEnabled(ScreenLockType type, int quality)131     public boolean isScreenLockEnabled(ScreenLockType type, int quality) {
132         return type.maxQuality >= quality;
133     }
134 
135     /**
136      * Whether screen lock with {@code type} is disabled by device policy admin.
137      *
138      * @param type The screen lock type.
139      * @param adminEnforcedQuality The minimum quality that the admin enforces.
140      */
isScreenLockDisabledByAdmin(ScreenLockType type, int adminEnforcedQuality)141     public boolean isScreenLockDisabledByAdmin(ScreenLockType type, int adminEnforcedQuality) {
142         boolean disabledByAdmin = type.maxQuality < adminEnforcedQuality;
143         if (type == ScreenLockType.MANAGED) {
144             disabledByAdmin = disabledByAdmin
145                     || !mManagedPasswordProvider.isManagedPasswordChoosable();
146         }
147         return disabledByAdmin;
148     }
149 
150     /**
151      * User friendly title for the given screen lock type.
152      */
153     public CharSequence getTitle(ScreenLockType type) {
154         switch (type) {
155             case NONE:
156                 return mContext.getText(R.string.unlock_set_unlock_off_title);
157             case SWIPE:
158                 return mContext.getText(R.string.unlock_set_unlock_none_title);
159             case PATTERN:
160                 return mContext.getText(R.string.unlock_set_unlock_pattern_title);
161             case PIN:
162                 return mContext.getText(R.string.unlock_set_unlock_pin_title);
163             case PASSWORD:
164                 return mContext.getText(R.string.unlock_set_unlock_password_title);
165             case MANAGED:
166                 return mManagedPasswordProvider.getPickerOptionTitle(false);
167         }
168         return null;
169     }
170 
171     /**
172      * Gets a list of screen locks that should be visible for the given quality. The returned list
173      * is ordered in the natural order of the enum (the order those enums were defined).
174      *
175      * @param quality The minimum quality required in the context of the current flow. This should
176      *                be one of the constants defined in
177      *                {@code DevicePolicyManager#PASSWORD_QUALITY_*}.
178      * @param includeDisabled Whether to include screen locks disabled by {@code quality}
179      *                        requirements in the returned list.
180      */
181     @NonNull
182     public List<ScreenLockType> getVisibleScreenLockTypes(int quality, boolean includeDisabled) {
183         int upgradedQuality = upgradeQuality(quality);
184         List<ScreenLockType> locks = new ArrayList<>();
185         // EnumSet's iterator guarantees the natural order of the enums
186         for (ScreenLockType lock : ScreenLockType.values()) {
187             if (isScreenLockVisible(lock)) {
188                 if (includeDisabled || isScreenLockEnabled(lock, upgradedQuality)) {
189                     locks.add(lock);
190                 }
191             }
192         }
193         return locks;
194     }
195 }
196