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.security.screenlock;
18 
19 import static android.provider.Settings.System.SCREEN_OFF_TIMEOUT;
20 
21 import android.app.admin.DevicePolicyManager;
22 import android.content.Context;
23 import android.os.UserHandle;
24 import android.provider.Settings;
25 import android.text.TextUtils;
26 import android.util.Log;
27 
28 import androidx.preference.Preference;
29 
30 import com.android.internal.widget.LockPatternUtils;
31 import com.android.settings.R;
32 import com.android.settings.core.PreferenceControllerMixin;
33 import com.android.settings.display.TimeoutListPreference;
34 import com.android.settings.overlay.FeatureFactory;
35 import com.android.settings.security.trustagent.TrustAgentManager;
36 import com.android.settingslib.RestrictedLockUtils;
37 import com.android.settingslib.RestrictedLockUtilsInternal;
38 import com.android.settingslib.core.AbstractPreferenceController;
39 
40 public class LockAfterTimeoutPreferenceController extends AbstractPreferenceController
41         implements PreferenceControllerMixin, Preference.OnPreferenceChangeListener {
42 
43     private static final String KEY_LOCK_AFTER_TIMEOUT = "lock_after_timeout";
44 
45     private final int mUserId;
46     private final LockPatternUtils mLockPatternUtils;
47     private final TrustAgentManager mTrustAgentManager;
48     private final DevicePolicyManager mDPM;
49 
LockAfterTimeoutPreferenceController(Context context, int userId, LockPatternUtils lockPatternUtils)50     public LockAfterTimeoutPreferenceController(Context context, int userId,
51             LockPatternUtils lockPatternUtils) {
52         super(context);
53         mUserId = userId;
54         mLockPatternUtils = lockPatternUtils;
55         mDPM = (DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE);
56         mTrustAgentManager = FeatureFactory.getFactory(context)
57                 .getSecurityFeatureProvider().getTrustAgentManager();
58     }
59 
60     @Override
isAvailable()61     public boolean isAvailable() {
62         if (!mLockPatternUtils.isSecure(mUserId)) {
63             return false;
64         }
65         switch (mLockPatternUtils.getKeyguardStoredPasswordQuality(mUserId)) {
66             case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING:
67             case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC:
68             case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX:
69             case DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC:
70             case DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC:
71             case DevicePolicyManager.PASSWORD_QUALITY_COMPLEX:
72             case DevicePolicyManager.PASSWORD_QUALITY_MANAGED:
73                 return true;
74             default:
75                 return false;
76         }
77     }
78 
79     @Override
getPreferenceKey()80     public String getPreferenceKey() {
81         return KEY_LOCK_AFTER_TIMEOUT;
82     }
83 
84     @Override
updateState(Preference preference)85     public void updateState(Preference preference) {
86         setupLockAfterPreference((TimeoutListPreference) preference);
87         updateLockAfterPreferenceSummary((TimeoutListPreference) preference);
88     }
89 
90     @Override
onPreferenceChange(Preference preference, Object newValue)91     public boolean onPreferenceChange(Preference preference, Object newValue) {
92         try {
93             final int timeout = Integer.parseInt((String) newValue);
94             Settings.Secure.putInt(mContext.getContentResolver(),
95                     Settings.Secure.LOCK_SCREEN_LOCK_AFTER_TIMEOUT, timeout);
96             updateState(preference);
97         } catch (NumberFormatException e) {
98             Log.e(TAG, "could not persist lockAfter timeout setting", e);
99         }
100         return true;
101     }
102 
setupLockAfterPreference(TimeoutListPreference preference)103     private void setupLockAfterPreference(TimeoutListPreference preference) {
104         // Compatible with pre-Froyo
105         long currentTimeout = Settings.Secure.getLong(mContext.getContentResolver(),
106                 Settings.Secure.LOCK_SCREEN_LOCK_AFTER_TIMEOUT, 5000);
107         preference.setValue(String.valueOf(currentTimeout));
108         if (mDPM != null) {
109             final RestrictedLockUtils.EnforcedAdmin admin =
110                     RestrictedLockUtilsInternal.checkIfMaximumTimeToLockIsSet(mContext);
111             final long adminTimeout =
112                     mDPM.getMaximumTimeToLock(null /* admin */, UserHandle.myUserId());
113             final long displayTimeout = Math.max(0,
114                     Settings.System.getInt(mContext.getContentResolver(), SCREEN_OFF_TIMEOUT, 0));
115             // This setting is a slave to display timeout when a device policy is enforced.
116             // As such, maxLockTimeout = adminTimeout - displayTimeout.
117             // If there isn't enough time, shows "immediately" setting.
118             final long maxTimeout = Math.max(0, adminTimeout - displayTimeout);
119             preference.removeUnusableTimeouts(maxTimeout, admin);
120         }
121     }
122 
updateLockAfterPreferenceSummary(TimeoutListPreference preference)123     private void updateLockAfterPreferenceSummary(TimeoutListPreference preference) {
124         final CharSequence summary;
125         if (preference.isDisabledByAdmin()) {
126             summary = mContext.getText(R.string.disabled_by_policy_title);
127         } else {
128             // Update summary message with current value
129             long currentTimeout = Settings.Secure.getLong(mContext.getContentResolver(),
130                     Settings.Secure.LOCK_SCREEN_LOCK_AFTER_TIMEOUT, 5000);
131             final CharSequence[] entries = preference.getEntries();
132             final CharSequence[] values = preference.getEntryValues();
133             int best = 0;
134             for (int i = 0; i < values.length; i++) {
135                 long timeout = Long.valueOf(values[i].toString());
136                 if (currentTimeout >= timeout) {
137                     best = i;
138                 }
139             }
140 
141             final CharSequence trustAgentLabel = mTrustAgentManager
142                     .getActiveTrustAgentLabel(mContext, mLockPatternUtils);
143             if (!TextUtils.isEmpty(trustAgentLabel)) {
144                 if (Long.valueOf(values[best].toString()) == 0) {
145                     summary = mContext.getString(R.string.lock_immediately_summary_with_exception,
146                             trustAgentLabel);
147                 } else {
148                     summary = mContext.getString(R.string.lock_after_timeout_summary_with_exception,
149                             entries[best], trustAgentLabel);
150                 }
151             } else {
152                 summary = mContext.getString(R.string.lock_after_timeout_summary, entries[best]);
153             }
154         }
155         preference.setSummary(summary);
156     }
157 }
158