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 static com.android.settings.security.SecuritySettings.UNIFY_LOCK_CONFIRM_PROFILE_REQUEST; 20 import static com.android.settings.security.SecuritySettings.UNUNIFY_LOCK_CONFIRM_DEVICE_REQUEST; 21 22 import android.app.Activity; 23 import android.app.admin.DevicePolicyManager; 24 import android.content.Context; 25 import android.content.Intent; 26 import android.os.Bundle; 27 import android.os.UserHandle; 28 import android.os.UserManager; 29 30 import androidx.preference.Preference; 31 import androidx.preference.PreferenceScreen; 32 33 import com.android.internal.widget.LockPatternUtils; 34 import com.android.internal.widget.LockscreenCredential; 35 import com.android.settings.R; 36 import com.android.settings.Utils; 37 import com.android.settings.core.PreferenceControllerMixin; 38 import com.android.settings.core.SubSettingLauncher; 39 import com.android.settings.overlay.FeatureFactory; 40 import com.android.settings.password.ChooseLockGeneric; 41 import com.android.settings.password.ChooseLockSettingsHelper; 42 import com.android.settingslib.RestrictedLockUtilsInternal; 43 import com.android.settingslib.RestrictedSwitchPreference; 44 import com.android.settingslib.core.AbstractPreferenceController; 45 46 /** 47 * Controller for password unification/un-unification flows. 48 * 49 * When password is being unified, there may be two cases: 50 * 1. If device password will satisfy device-wide policies post-unification (when password policy 51 * set on the work challenge will be enforced on device password), the device password is 52 * preserved while work challenge is unified. Only the current work challenge is required 53 * in this flow. 54 * 2. Otherwise the user will need to enroll a new compliant device password before unification 55 * takes place. In this case we first confirm the current work challenge, then guide the user 56 * through an enrollment flow for the new device password, and finally unify the work challenge 57 * at the very end. 58 */ 59 public class LockUnificationPreferenceController extends AbstractPreferenceController 60 implements PreferenceControllerMixin, Preference.OnPreferenceChangeListener { 61 62 private static final String KEY_UNIFICATION = "unification"; 63 64 private static final int MY_USER_ID = UserHandle.myUserId(); 65 66 private final UserManager mUm; 67 private final DevicePolicyManager mDpm; 68 private final LockPatternUtils mLockPatternUtils; 69 private final int mProfileUserId; 70 private final SecuritySettings mHost; 71 72 private RestrictedSwitchPreference mUnifyProfile; 73 74 75 private LockscreenCredential mCurrentDevicePassword; 76 private LockscreenCredential mCurrentProfilePassword; 77 private boolean mRequireNewDevicePassword; 78 79 @Override displayPreference(PreferenceScreen screen)80 public void displayPreference(PreferenceScreen screen) { 81 super.displayPreference(screen); 82 mUnifyProfile = screen.findPreference(KEY_UNIFICATION); 83 } 84 LockUnificationPreferenceController(Context context, SecuritySettings host)85 public LockUnificationPreferenceController(Context context, SecuritySettings host) { 86 super(context); 87 mHost = host; 88 mUm = context.getSystemService(UserManager.class); 89 mDpm = context.getSystemService(DevicePolicyManager.class); 90 mLockPatternUtils = FeatureFactory.getFactory(context) 91 .getSecurityFeatureProvider() 92 .getLockPatternUtils(context); 93 mProfileUserId = Utils.getManagedProfileId(mUm, MY_USER_ID); 94 mCurrentDevicePassword = LockscreenCredential.createNone(); 95 mCurrentProfilePassword = LockscreenCredential.createNone(); 96 } 97 98 @Override isAvailable()99 public boolean isAvailable() { 100 return mProfileUserId != UserHandle.USER_NULL 101 && mLockPatternUtils.isSeparateProfileChallengeAllowed(mProfileUserId); 102 } 103 104 @Override getPreferenceKey()105 public String getPreferenceKey() { 106 return KEY_UNIFICATION; 107 } 108 109 @Override onPreferenceChange(Preference preference, Object value)110 public boolean onPreferenceChange(Preference preference, Object value) { 111 if (Utils.startQuietModeDialogIfNecessary(mContext, mUm, mProfileUserId)) { 112 return false; 113 } 114 final boolean useOneLock = (Boolean) value; 115 if (useOneLock) { 116 mRequireNewDevicePassword = !mDpm.isPasswordSufficientAfterProfileUnification( 117 UserHandle.myUserId(), mProfileUserId); 118 startUnification(); 119 } else { 120 final String title = mContext.getString(R.string.unlock_set_unlock_launch_picker_title); 121 final ChooseLockSettingsHelper helper = 122 new ChooseLockSettingsHelper(mHost.getActivity(), mHost); 123 if (!helper.launchConfirmationActivity( 124 UNUNIFY_LOCK_CONFIRM_DEVICE_REQUEST, 125 title, true /* returnCredentials */, MY_USER_ID)) { 126 ununifyLocks(); 127 } 128 } 129 return true; 130 } 131 132 @Override updateState(Preference preference)133 public void updateState(Preference preference) { 134 if (mUnifyProfile != null) { 135 final boolean separate = 136 mLockPatternUtils.isSeparateProfileChallengeEnabled(mProfileUserId); 137 mUnifyProfile.setChecked(!separate); 138 if (separate) { 139 mUnifyProfile.setDisabledByAdmin(RestrictedLockUtilsInternal 140 .checkIfRestrictionEnforced(mContext, UserManager.DISALLOW_UNIFIED_PASSWORD, 141 mProfileUserId)); 142 } 143 } 144 } 145 handleActivityResult(int requestCode, int resultCode, Intent data)146 public boolean handleActivityResult(int requestCode, int resultCode, Intent data) { 147 if (requestCode == UNUNIFY_LOCK_CONFIRM_DEVICE_REQUEST 148 && resultCode == Activity.RESULT_OK) { 149 mCurrentDevicePassword = 150 data.getParcelableExtra(ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD); 151 ununifyLocks(); 152 return true; 153 } else if (requestCode == UNIFY_LOCK_CONFIRM_PROFILE_REQUEST 154 && resultCode == Activity.RESULT_OK) { 155 mCurrentProfilePassword = 156 data.getParcelableExtra(ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD); 157 unifyLocks(); 158 return true; 159 } 160 return false; 161 } 162 ununifyLocks()163 private void ununifyLocks() { 164 final Bundle extras = new Bundle(); 165 extras.putInt(Intent.EXTRA_USER_ID, mProfileUserId); 166 extras.putParcelable(ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD, mCurrentDevicePassword); 167 new SubSettingLauncher(mContext) 168 .setDestination(ChooseLockGeneric.ChooseLockGenericFragment.class.getName()) 169 .setTitleRes(R.string.lock_settings_picker_title_profile) 170 .setSourceMetricsCategory(mHost.getMetricsCategory()) 171 .setArguments(extras) 172 .launch(); 173 } 174 startUnification()175 void startUnification() { 176 // Confirm profile lock 177 final String title = mContext.getString( 178 R.string.unlock_set_unlock_launch_picker_title_profile); 179 final ChooseLockSettingsHelper helper = 180 new ChooseLockSettingsHelper(mHost.getActivity(), mHost); 181 if (!helper.launchConfirmationActivity( 182 UNIFY_LOCK_CONFIRM_PROFILE_REQUEST, title, true, mProfileUserId)) { 183 // If profile has no lock, go straight to unification. 184 unifyLocks(); 185 // TODO: update relevant prefs. 186 // createPreferenceHierarchy(); 187 } 188 } 189 unifyLocks()190 private void unifyLocks() { 191 if (mRequireNewDevicePassword) { 192 promptForNewDeviceLockAndThenUnify(); 193 } else { 194 unifyKeepingDeviceLock(); 195 } 196 if (mCurrentDevicePassword != null) { 197 mCurrentDevicePassword.zeroize(); 198 mCurrentDevicePassword = null; 199 } 200 if (mCurrentProfilePassword != null) { 201 mCurrentProfilePassword.zeroize(); 202 mCurrentProfilePassword = null; 203 } 204 } 205 unifyKeepingDeviceLock()206 private void unifyKeepingDeviceLock() { 207 mLockPatternUtils.setSeparateProfileChallengeEnabled(mProfileUserId, false, 208 mCurrentProfilePassword); 209 } 210 promptForNewDeviceLockAndThenUnify()211 private void promptForNewDeviceLockAndThenUnify() { 212 final Bundle extras = new Bundle(); 213 extras.putInt(ChooseLockSettingsHelper.EXTRA_KEY_UNIFICATION_PROFILE_ID, mProfileUserId); 214 extras.putParcelable(ChooseLockSettingsHelper.EXTRA_KEY_UNIFICATION_PROFILE_CREDENTIAL, 215 mCurrentProfilePassword); 216 new SubSettingLauncher(mContext) 217 .setDestination(ChooseLockGeneric.ChooseLockGenericFragment.class.getName()) 218 .setTitleRes(R.string.lock_settings_picker_title) 219 .setSourceMetricsCategory(mHost.getMetricsCategory()) 220 .setArguments(extras) 221 .launch(); 222 } 223 224 } 225