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