1 /* 2 * Copyright (C) 2023 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.privatespace.onelock; 18 19 import static com.android.settings.privatespace.PrivateSpaceSetupActivity.EXTRA_ACTION_TYPE; 20 import static com.android.settings.privatespace.PrivateSpaceSetupActivity.SET_LOCK_ACTION; 21 import static com.android.settings.privatespace.onelock.UseOneLockSettingsFragment.UNIFY_PRIVATE_LOCK_WITH_DEVICE_REQUEST; 22 import static com.android.settings.privatespace.onelock.UseOneLockSettingsFragment.UNUNIFY_PRIVATE_LOCK_FROM_DEVICE_REQUEST; 23 24 import android.app.Activity; 25 import android.app.AlertDialog; 26 import android.content.Context; 27 import android.content.DialogInterface; 28 import android.content.Intent; 29 import android.os.Bundle; 30 import android.os.UserHandle; 31 import android.os.UserManager; 32 import android.util.Log; 33 34 import androidx.annotation.Nullable; 35 import androidx.preference.Preference; 36 import androidx.preference.PreferenceScreen; 37 38 import com.android.internal.widget.LockPatternUtils; 39 import com.android.internal.widget.LockscreenCredential; 40 import com.android.settings.R; 41 import com.android.settings.SettingsPreferenceFragment; 42 import com.android.settings.Utils; 43 import com.android.settings.core.SubSettingLauncher; 44 import com.android.settings.overlay.FeatureFactory; 45 import com.android.settings.password.ChooseLockGeneric; 46 import com.android.settings.password.ChooseLockSettingsHelper; 47 import com.android.settings.privatespace.PrivateProfileContextHelperActivity; 48 import com.android.settings.privatespace.PrivateSpaceMaintainer; 49 import com.android.settingslib.core.AbstractPreferenceController; 50 import com.android.settingslib.transition.SettingsTransitionHelper; 51 import com.android.settingslib.widget.MainSwitchPreference; 52 53 /** Represents the preference controller for using the same lock as the screen lock */ 54 public class UseOneLockControllerSwitch extends AbstractPreferenceController 55 implements Preference.OnPreferenceChangeListener { 56 private static final String TAG = "UseOneLockSwitch"; 57 private static final String KEY_UNIFICATION = "private_lock_unification"; 58 private final String mPreferenceKey; 59 private final SettingsPreferenceFragment mHost; 60 private final LockPatternUtils mLockPatternUtils; 61 private final UserManager mUserManager; 62 private final int mProfileUserId; 63 private final UserHandle mUserHandle; 64 private LockscreenCredential mCurrentDevicePassword; 65 private LockscreenCredential mCurrentProfilePassword; 66 private MainSwitchPreference mUnifyProfile; 67 68 @Override displayPreference(PreferenceScreen screen)69 public void displayPreference(PreferenceScreen screen) { 70 super.displayPreference(screen); 71 mUnifyProfile = screen.findPreference(mPreferenceKey); 72 } UseOneLockControllerSwitch(Context context, SettingsPreferenceFragment host)73 public UseOneLockControllerSwitch(Context context, SettingsPreferenceFragment host) { 74 this(context, host, KEY_UNIFICATION); 75 } 76 UseOneLockControllerSwitch(Context context, SettingsPreferenceFragment host, String key)77 public UseOneLockControllerSwitch(Context context, SettingsPreferenceFragment host, 78 String key) { 79 super(context); 80 mHost = host; 81 mUserManager = context.getSystemService(UserManager.class); 82 mLockPatternUtils = FeatureFactory.getFeatureFactory().getSecurityFeatureProvider() 83 .getLockPatternUtils(context); 84 mUserHandle = PrivateSpaceMaintainer.getInstance(context).getPrivateProfileHandle(); 85 mProfileUserId = mUserHandle != null ? mUserHandle.getIdentifier() : -1; 86 mCurrentDevicePassword = LockscreenCredential.createNone(); 87 mCurrentProfilePassword = LockscreenCredential.createNone(); 88 this.mPreferenceKey = key; 89 } 90 91 @Override getPreferenceKey()92 public String getPreferenceKey() { 93 return mPreferenceKey; 94 } 95 96 @Override isAvailable()97 public boolean isAvailable() { 98 return android.os.Flags.allowPrivateProfile() 99 && android.multiuser.Flags.enablePrivateSpaceFeatures(); 100 } 101 102 @Override onPreferenceChange(Preference preference, Object value)103 public boolean onPreferenceChange(Preference preference, Object value) { 104 //Checks if the profile is in quiet mode and show a dialog to unpause the profile. 105 if (Utils.startQuietModeDialogIfNecessary(mContext, mUserManager, mProfileUserId)) { 106 return false; 107 } 108 final boolean useOneLock = (Boolean) value; 109 if (useOneLock) { 110 startUnification(); 111 } else { 112 showAlertDialog(); 113 } 114 return true; 115 } 116 117 @Override updateState(Preference preference)118 public void updateState(Preference preference) { 119 if (mUnifyProfile != null) { 120 final boolean separate = 121 mLockPatternUtils.isSeparateProfileChallengeEnabled(mProfileUserId); 122 mUnifyProfile.setChecked(!separate); 123 } 124 } 125 126 /** Method to handle onActivityResult */ handleActivityResult(int requestCode, int resultCode, @Nullable Intent data)127 public boolean handleActivityResult(int requestCode, int resultCode, @Nullable Intent data) { 128 if (requestCode == UNUNIFY_PRIVATE_LOCK_FROM_DEVICE_REQUEST 129 && resultCode == Activity.RESULT_OK && data != null) { 130 mCurrentDevicePassword = 131 data.getParcelableExtra(ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD); 132 separateLocks(); 133 return true; 134 } else if (requestCode == UNIFY_PRIVATE_LOCK_WITH_DEVICE_REQUEST 135 && resultCode == Activity.RESULT_OK && data != null) { 136 mCurrentProfilePassword = 137 data.getParcelableExtra(ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD); 138 unifyLocks(); 139 return true; 140 } 141 return false; 142 } 143 separateLocks()144 private void separateLocks() { 145 final Bundle extras = new Bundle(); 146 extras.putInt(Intent.EXTRA_USER_ID, mProfileUserId); 147 extras.putParcelable(ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD, mCurrentDevicePassword); 148 new SubSettingLauncher(mContext) 149 .setDestination(ChooseLockGeneric.ChooseLockGenericFragment.class.getName()) 150 .setSourceMetricsCategory(mHost.getMetricsCategory()) 151 .setArguments(extras) 152 .setTransitionType(SettingsTransitionHelper.TransitionType.TRANSITION_SLIDE) 153 .launch(); 154 } 155 156 /** Unify primary and profile locks. */ startUnification()157 public void startUnification() { 158 // Confirm profile lock 159 final ChooseLockSettingsHelper.Builder builder = 160 new ChooseLockSettingsHelper.Builder(mHost.getActivity(), mHost); 161 final boolean launched = builder.setRequestCode(UNIFY_PRIVATE_LOCK_WITH_DEVICE_REQUEST) 162 .setReturnCredentials(true) 163 .setUserId(mProfileUserId) 164 .show(); 165 if (!launched) { 166 // If profile has no lock, go straight to unification. 167 unifyLocks(); 168 } 169 } 170 unifyLocks()171 private void unifyLocks() { 172 unifyKeepingDeviceLock(); 173 if (mCurrentDevicePassword != null) { 174 mCurrentDevicePassword.zeroize(); 175 mCurrentDevicePassword = null; 176 } 177 if (mCurrentProfilePassword != null) { 178 mCurrentProfilePassword.zeroize(); 179 mCurrentProfilePassword = null; 180 } 181 } 182 unifyKeepingDeviceLock()183 private void unifyKeepingDeviceLock() { 184 mLockPatternUtils.setSeparateProfileChallengeEnabled(mProfileUserId, false, 185 mCurrentProfilePassword); 186 } 187 showAlertDialog()188 private void showAlertDialog() { 189 if (mUserHandle == null) { 190 Log.e(TAG, "Private profile user handle is not expected to be null"); 191 mUnifyProfile.setChecked(true); 192 return; 193 } 194 new AlertDialog.Builder(mContext) 195 .setTitle(R.string.private_space_new_lock_title) 196 .setMessage(R.string.private_space_new_lock_message) 197 .setPositiveButton( 198 R.string.private_space_set_lock_label, 199 (dialog, which) -> { 200 Intent intent = new Intent(mContext, 201 PrivateProfileContextHelperActivity.class); 202 intent.putExtra(EXTRA_ACTION_TYPE, SET_LOCK_ACTION); 203 ((Activity) mContext).startActivityForResultAsUser(intent, 204 UNUNIFY_PRIVATE_LOCK_FROM_DEVICE_REQUEST, 205 /*Options*/ null, mUserHandle); 206 }) 207 .setNegativeButton(R.string.private_space_cancel_label, 208 (DialogInterface dialog, int which) -> { 209 mUnifyProfile.setChecked(true); 210 dialog.dismiss(); 211 }) 212 .setOnCancelListener( 213 (DialogInterface dialog) -> { 214 mUnifyProfile.setChecked(true); 215 dialog.dismiss(); 216 }) 217 .show(); 218 } 219 } 220