1 /*
2  * Copyright (C) 2014 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 package com.android.settings.security;
17 
18 import android.app.admin.DevicePolicyManager;
19 import android.app.settings.SettingsEnums;
20 import android.content.Context;
21 import android.content.DialogInterface;
22 import android.content.Intent;
23 import android.os.Bundle;
24 import android.os.UserHandle;
25 import android.os.UserManager;
26 import android.provider.SearchIndexableResource;
27 import android.provider.Settings;
28 import android.widget.Switch;
29 
30 import androidx.appcompat.app.AlertDialog;
31 import androidx.preference.Preference;
32 import androidx.preference.Preference.OnPreferenceChangeListener;
33 import androidx.preference.PreferenceScreen;
34 import androidx.preference.SwitchPreference;
35 
36 import com.android.internal.widget.LockPatternUtils;
37 import com.android.settings.R;
38 import com.android.settings.SettingsActivity;
39 import com.android.settings.SettingsPreferenceFragment;
40 import com.android.settings.password.ChooseLockGeneric;
41 import com.android.settings.search.BaseSearchIndexProvider;
42 import com.android.settings.widget.SwitchBar;
43 import com.android.settingslib.search.SearchIndexable;
44 import com.android.settingslib.widget.FooterPreference;
45 
46 import java.util.Arrays;
47 import java.util.List;
48 
49 
50 /**
51  * Screen pinning settings.
52  */
53 @SearchIndexable
54 public class ScreenPinningSettings extends SettingsPreferenceFragment
55         implements SwitchBar.OnSwitchChangeListener, DialogInterface.OnClickListener {
56 
57     private static final String KEY_USE_SCREEN_LOCK = "use_screen_lock";
58     private static final String KEY_FOOTER = "screen_pinning_settings_screen_footer";
59     private static final int CHANGE_LOCK_METHOD_REQUEST = 43;
60 
61     private SwitchBar mSwitchBar;
62     private SwitchPreference mUseScreenLock;
63     private FooterPreference mFooterPreference;
64     private LockPatternUtils mLockPatternUtils;
65     private UserManager mUserManager;
66 
67     @Override
getMetricsCategory()68     public int getMetricsCategory() {
69         return SettingsEnums.SCREEN_PINNING;
70     }
71 
72     @Override
onActivityCreated(Bundle savedInstanceState)73     public void onActivityCreated(Bundle savedInstanceState) {
74         super.onActivityCreated(savedInstanceState);
75 
76         final SettingsActivity activity = (SettingsActivity) getActivity();
77         activity.setTitle(R.string.screen_pinning_title);
78         mLockPatternUtils = new LockPatternUtils(activity);
79         mUserManager = activity.getSystemService(UserManager.class);
80 
81         addPreferencesFromResource(R.xml.screen_pinning_settings);
82         final PreferenceScreen root = getPreferenceScreen();
83         mUseScreenLock = root.findPreference(KEY_USE_SCREEN_LOCK);
84         mFooterPreference = root.findPreference(KEY_FOOTER);
85 
86         mSwitchBar = activity.getSwitchBar();
87         mSwitchBar.show();
88         mSwitchBar.setChecked(isLockToAppEnabled(getActivity()));
89         mSwitchBar.addOnSwitchChangeListener(this);
90 
91         updateDisplay();
92     }
93 
94     @Override
getHelpResource()95     public int getHelpResource() {
96         return R.string.help_url_screen_pinning;
97     }
98 
99     @Override
onDestroyView()100     public void onDestroyView() {
101         super.onDestroyView();
102 
103         mSwitchBar.removeOnSwitchChangeListener(this);
104         mSwitchBar.hide();
105     }
106 
isLockToAppEnabled(Context context)107     private static boolean isLockToAppEnabled(Context context) {
108         return Settings.System.getInt(context.getContentResolver(),
109                 Settings.System.LOCK_TO_APP_ENABLED, 0) != 0;
110     }
111 
setLockToAppEnabled(boolean isEnabled)112     private void setLockToAppEnabled(boolean isEnabled) {
113         Settings.System.putInt(getContentResolver(), Settings.System.LOCK_TO_APP_ENABLED,
114                 isEnabled ? 1 : 0);
115         if (isEnabled) {
116             // Set the value to match what we have defaulted to in the UI.
117             setScreenLockUsedSetting(isScreenLockUsed());
118         }
119     }
120 
isScreenLockUsed()121     private boolean isScreenLockUsed() {
122         // This functionality should be kept consistent with
123         // com.android.server.wm.LockTaskController (see b/127605586)
124         int defaultValueIfSettingNull = mLockPatternUtils.isSecure(UserHandle.myUserId()) ? 1 : 0;
125         return Settings.Secure.getInt(
126                 getContentResolver(),
127                 Settings.Secure.LOCK_TO_APP_EXIT_LOCKED,
128                 defaultValueIfSettingNull) != 0;
129     }
130 
setScreenLockUsed(boolean isEnabled)131     private boolean setScreenLockUsed(boolean isEnabled) {
132         if (isEnabled) {
133             LockPatternUtils lockPatternUtils = new LockPatternUtils(getActivity());
134             int passwordQuality = lockPatternUtils
135                     .getKeyguardStoredPasswordQuality(UserHandle.myUserId());
136             if (passwordQuality == DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
137                 Intent chooseLockIntent = new Intent(DevicePolicyManager.ACTION_SET_NEW_PASSWORD);
138                 chooseLockIntent.putExtra(
139                         ChooseLockGeneric.ChooseLockGenericFragment.MINIMUM_QUALITY_KEY,
140                         DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
141                 startActivityForResult(chooseLockIntent, CHANGE_LOCK_METHOD_REQUEST);
142                 return false;
143             }
144         }
145         setScreenLockUsedSetting(isEnabled);
146         return true;
147     }
148 
setScreenLockUsedSetting(boolean isEnabled)149     private void setScreenLockUsedSetting(boolean isEnabled) {
150         Settings.Secure.putInt(getContentResolver(), Settings.Secure.LOCK_TO_APP_EXIT_LOCKED,
151                 isEnabled ? 1 : 0);
152     }
153 
154     @Override
onActivityResult(int requestCode, int resultCode, Intent data)155     public void onActivityResult(int requestCode, int resultCode, Intent data) {
156         super.onActivityResult(requestCode, resultCode, data);
157         if (requestCode == CHANGE_LOCK_METHOD_REQUEST) {
158             LockPatternUtils lockPatternUtils = new LockPatternUtils(getActivity());
159             boolean validPassQuality = lockPatternUtils.getKeyguardStoredPasswordQuality(
160                     UserHandle.myUserId())
161                     != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
162             setScreenLockUsed(validPassQuality);
163             // Make sure the screen updates.
164             mUseScreenLock.setChecked(validPassQuality);
165         }
166     }
167 
getCurrentSecurityTitle()168     private int getCurrentSecurityTitle() {
169         int quality = mLockPatternUtils.getKeyguardStoredPasswordQuality(
170                 UserHandle.myUserId());
171         switch (quality) {
172             case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC:
173             case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX:
174                 return R.string.screen_pinning_unlock_pin;
175             case DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC:
176             case DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC:
177             case DevicePolicyManager.PASSWORD_QUALITY_COMPLEX:
178             case DevicePolicyManager.PASSWORD_QUALITY_MANAGED:
179                 return R.string.screen_pinning_unlock_password;
180             case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING:
181                 if (mLockPatternUtils.isLockPatternEnabled(UserHandle.myUserId())) {
182                     return R.string.screen_pinning_unlock_pattern;
183                 }
184         }
185         return R.string.screen_pinning_unlock_none;
186     }
187 
188     /**
189      * Listens to the state change of the lock-to-app master switch.
190      */
191     @Override
onSwitchChanged(Switch switchView, boolean isChecked)192     public void onSwitchChanged(Switch switchView, boolean isChecked) {
193         if (isChecked) {
194             new AlertDialog.Builder(getContext())
195                     .setMessage(R.string.screen_pinning_dialog_message)
196                     .setPositiveButton(R.string.dlg_ok, this)
197                     .setNegativeButton(R.string.dlg_cancel, this)
198                     .setCancelable(false)
199                     .show();
200         } else {
201             setLockToAppEnabled(false);
202             updateDisplay();
203         }
204     }
205 
206     @Override
onClick(DialogInterface dialogInterface, int which)207     public void onClick(DialogInterface dialogInterface, int which) {
208         if (which == DialogInterface.BUTTON_POSITIVE) {
209             setLockToAppEnabled(true);
210         } else {
211             mSwitchBar.setChecked(false);
212         }
213         updateDisplay();
214     }
215 
updateDisplay()216     private void updateDisplay() {
217         if (isLockToAppEnabled(getActivity())) {
218             mUseScreenLock.setVisible(true);
219             mUseScreenLock.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
220                 @Override
221                 public boolean onPreferenceChange(Preference preference, Object newValue) {
222                     return setScreenLockUsed((boolean) newValue);
223                 }
224             });
225             mUseScreenLock.setChecked(isScreenLockUsed());
226             mUseScreenLock.setTitle(getCurrentSecurityTitle());
227         } else {
228             mFooterPreference.setSummary(getAppPinningContent());
229             mUseScreenLock.setVisible(false);
230         }
231     }
232 
isGuestModeSupported()233     private boolean isGuestModeSupported() {
234         return UserManager.supportsMultipleUsers()
235                 && !mUserManager.hasUserRestriction(UserManager.DISALLOW_USER_SWITCH);
236     }
237 
getAppPinningContent()238     private CharSequence getAppPinningContent() {
239         return isGuestModeSupported()
240                 ? getActivity().getText(R.string.screen_pinning_guest_user_description)
241                 : getActivity().getText(R.string.screen_pinning_description);
242     }
243 
244     /**
245      * For search
246      */
247     public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
248             new BaseSearchIndexProvider() {
249 
250                 @Override
251                 public List<SearchIndexableResource> getXmlResourcesToIndex(Context context,
252                         boolean enabled) {
253                     final SearchIndexableResource sir = new SearchIndexableResource(context);
254                     sir.xmlResId = R.xml.screen_pinning_settings;
255                     return Arrays.asList(sir);
256                 }
257             };
258 }
259