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