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