1 /* 2 * Copyright (C) 2018 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.security; 18 19 import android.app.admin.DevicePolicyManager; 20 import android.content.Context; 21 import android.os.UserHandle; 22 import android.os.UserManager; 23 import android.os.storage.StorageManager; 24 import android.text.TextUtils; 25 26 import androidx.preference.Preference; 27 import androidx.preference.PreferenceScreen; 28 29 import com.android.internal.widget.LockPatternUtils; 30 import com.android.settings.R; 31 import com.android.settings.Utils; 32 import com.android.settings.core.PreferenceControllerMixin; 33 import com.android.settings.core.SubSettingLauncher; 34 import com.android.settings.overlay.FeatureFactory; 35 import com.android.settings.password.ChooseLockGeneric; 36 import com.android.settings.security.screenlock.ScreenLockSettings; 37 import com.android.settings.widget.GearPreference; 38 import com.android.settingslib.RestrictedLockUtils; 39 import com.android.settingslib.RestrictedLockUtilsInternal; 40 import com.android.settingslib.RestrictedPreference; 41 import com.android.settingslib.core.AbstractPreferenceController; 42 43 public class ChangeScreenLockPreferenceController extends AbstractPreferenceController implements 44 PreferenceControllerMixin, GearPreference.OnGearClickListener { 45 46 private static final String KEY_UNLOCK_SET_OR_CHANGE = "unlock_set_or_change"; 47 48 protected final DevicePolicyManager mDPM; 49 protected final SecuritySettings mHost; 50 protected final UserManager mUm; 51 protected final LockPatternUtils mLockPatternUtils; 52 53 protected final int mUserId = UserHandle.myUserId(); 54 protected final int mProfileChallengeUserId; 55 56 protected RestrictedPreference mPreference; 57 ChangeScreenLockPreferenceController(Context context, SecuritySettings host)58 public ChangeScreenLockPreferenceController(Context context, SecuritySettings host) { 59 super(context); 60 mUm = (UserManager) context.getSystemService(Context.USER_SERVICE); 61 mDPM = (DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE); 62 mLockPatternUtils = FeatureFactory.getFactory(context) 63 .getSecurityFeatureProvider() 64 .getLockPatternUtils(context); 65 mHost = host; 66 mProfileChallengeUserId = Utils.getManagedProfileId(mUm, mUserId); 67 } 68 69 @Override isAvailable()70 public boolean isAvailable() { 71 return mContext.getResources().getBoolean(R.bool.config_show_unlock_set_or_change); 72 } 73 74 @Override getPreferenceKey()75 public String getPreferenceKey() { 76 return KEY_UNLOCK_SET_OR_CHANGE; 77 } 78 79 @Override displayPreference(PreferenceScreen screen)80 public void displayPreference(PreferenceScreen screen) { 81 super.displayPreference(screen); 82 mPreference = screen.findPreference(getPreferenceKey()); 83 } 84 85 @Override updateState(Preference preference)86 public void updateState(Preference preference) { 87 if (mPreference != null && mPreference instanceof GearPreference) { 88 if (mLockPatternUtils.isSecure(mUserId)) { 89 ((GearPreference) mPreference).setOnGearClickListener(this); 90 } else { 91 ((GearPreference) mPreference).setOnGearClickListener(null); 92 } 93 } 94 95 updateSummary(preference, mUserId); 96 disableIfPasswordQualityManaged(mUserId); 97 if (!mLockPatternUtils.isSeparateProfileChallengeEnabled(mProfileChallengeUserId)) { 98 // PO may disallow to change password for the profile, but screen lock and managed 99 // profile's lock is the same. Disable main "Screen lock" menu. 100 disableIfPasswordQualityManaged(mProfileChallengeUserId); 101 } 102 } 103 104 @Override onGearClick(GearPreference p)105 public void onGearClick(GearPreference p) { 106 if (TextUtils.equals(p.getKey(), getPreferenceKey())) { 107 new SubSettingLauncher(mContext) 108 .setDestination(ScreenLockSettings.class.getName()) 109 .setSourceMetricsCategory(mHost.getMetricsCategory()) 110 .launch(); 111 } 112 } 113 114 @Override handlePreferenceTreeClick(Preference preference)115 public boolean handlePreferenceTreeClick(Preference preference) { 116 if (!TextUtils.equals(preference.getKey(), getPreferenceKey())) { 117 return super.handlePreferenceTreeClick(preference); 118 } 119 // TODO(b/35930129): Remove once existing password can be passed into vold directly. 120 // Currently we need this logic to ensure that the QUIET_MODE is off for any work 121 // profile with unified challenge on FBE-enabled devices. Otherwise, vold would not be 122 // able to complete the operation due to the lack of (old) encryption key. 123 if (mProfileChallengeUserId != UserHandle.USER_NULL 124 && !mLockPatternUtils.isSeparateProfileChallengeEnabled(mProfileChallengeUserId) 125 && StorageManager.isFileEncryptedNativeOnly()) { 126 if (Utils.startQuietModeDialogIfNecessary(mContext, mUm, mProfileChallengeUserId)) { 127 return false; 128 } 129 } 130 131 new SubSettingLauncher(mContext) 132 .setDestination(ChooseLockGeneric.ChooseLockGenericFragment.class.getName()) 133 .setTitleRes(R.string.lock_settings_picker_title) 134 .setSourceMetricsCategory(mHost.getMetricsCategory()) 135 .launch(); 136 return true; 137 } 138 updateSummary(Preference preference, int userId)139 protected void updateSummary(Preference preference, int userId) { 140 if (!mLockPatternUtils.isSecure(userId)) { 141 if (userId == mProfileChallengeUserId 142 || mLockPatternUtils.isLockScreenDisabled(userId)) { 143 preference.setSummary(R.string.unlock_set_unlock_mode_off); 144 } else { 145 preference.setSummary(R.string.unlock_set_unlock_mode_none); 146 } 147 } else { 148 switch (mLockPatternUtils.getKeyguardStoredPasswordQuality(userId)) { 149 case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING: 150 preference.setSummary(R.string.unlock_set_unlock_mode_pattern); 151 break; 152 case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC: 153 case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX: 154 preference.setSummary(R.string.unlock_set_unlock_mode_pin); 155 break; 156 case DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC: 157 case DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC: 158 case DevicePolicyManager.PASSWORD_QUALITY_COMPLEX: 159 case DevicePolicyManager.PASSWORD_QUALITY_MANAGED: 160 preference.setSummary(R.string.unlock_set_unlock_mode_password); 161 break; 162 } 163 } 164 mPreference.setEnabled(true); 165 } 166 167 /** 168 * Sets the preference as disabled by admin if PASSWORD_QUALITY_MANAGED is set. 169 * The preference must be a RestrictedPreference. 170 * <p/> 171 * DO or PO installed in the user may disallow to change password. 172 */ disableIfPasswordQualityManaged(int userId)173 void disableIfPasswordQualityManaged(int userId) { 174 final RestrictedLockUtils.EnforcedAdmin admin = RestrictedLockUtilsInternal 175 .checkIfPasswordQualityIsSet(mContext, userId); 176 final DevicePolicyManager dpm = (DevicePolicyManager) mContext 177 .getSystemService(Context.DEVICE_POLICY_SERVICE); 178 if (admin != null && dpm.getPasswordQuality(admin.component, userId) 179 == DevicePolicyManager.PASSWORD_QUALITY_MANAGED) { 180 mPreference.setDisabledByAdmin(admin); 181 } 182 } 183 } 184