Improve work profile unification flow

When unifying work profile challenge, keep the device lock
as long as it will still meet password requirement after unification.
If not, prompt the user to set a new device lock and only unify
work challenge after a compliant device lock is set.

Bug: 148630506
Fix: 149682344
Test: make RunSettingsRoboTests
ROBOTEST_FILTER='ChooseLockGenericTest|ChooseLockPasswordTest|ChooseLockPatternTest|LockUnificationPreferenceControllerTest'

Change-Id: I99cde2650902927f6a4cc7c0cc7c6016e0dc283f
This commit is contained in:
Rubin Xu
2020-04-02 16:29:36 +01:00
parent e1839d2955
commit f535e87e51
10 changed files with 279 additions and 93 deletions

View File

@@ -16,7 +16,6 @@
package com.android.settings.security;
import static com.android.settings.security.SecuritySettings.UNIFY_LOCK_CONFIRM_DEVICE_REQUEST;
import static com.android.settings.security.SecuritySettings.UNIFY_LOCK_CONFIRM_PROFILE_REQUEST;
import static com.android.settings.security.SecuritySettings.UNUNIFY_LOCK_CONFIRM_DEVICE_REQUEST;
@@ -48,12 +47,14 @@ import com.android.settingslib.core.AbstractPreferenceController;
* Controller for password unification/un-unification flows.
*
* When password is being unified, there may be two cases:
* 1. If work password is not empty and satisfies device-wide policies (if any), it will be made
* into device-wide password. To do that we need both current device and profile passwords
* because both of them will be changed as a result.
* 2. Otherwise device-wide password is preserved. In this case we only need current profile
* password, but after unifying the passwords we proceed to ask the user for a new device
* password.
* 1. If device password will satisfy device-wide policies post-unification (when password policy
* set on the work challenge will be enforced on device password), the device password is
* preserved while work challenge is unified. Only the current work challenge is required
* in this flow.
* 2. Otherwise the user will need to enroll a new compliant device password before unification
* takes place. In this case we first confirm the current work challenge, then guide the user
* through an enrollment flow for the new device password, and finally unify the work challenge
* at the very end.
*/
public class LockUnificationPreferenceController extends AbstractPreferenceController
implements PreferenceControllerMixin, Preference.OnPreferenceChangeListener {
@@ -73,7 +74,7 @@ public class LockUnificationPreferenceController extends AbstractPreferenceContr
private LockscreenCredential mCurrentDevicePassword;
private LockscreenCredential mCurrentProfilePassword;
private boolean mKeepDeviceLock;
private boolean mRequireNewDevicePassword;
@Override
public void displayPreference(PreferenceScreen screen) {
@@ -112,13 +113,9 @@ public class LockUnificationPreferenceController extends AbstractPreferenceContr
}
final boolean useOneLock = (Boolean) value;
if (useOneLock) {
// Keep current device (personal) lock if the profile lock is empty or is not compliant
// with the policy on personal side.
mKeepDeviceLock =
mLockPatternUtils.getKeyguardStoredPasswordQuality(mProfileUserId)
< DevicePolicyManager.PASSWORD_QUALITY_SOMETHING
|| !mDpm.isProfileActivePasswordSufficientForParent(mProfileUserId);
UnificationConfirmationDialog.newInstance(!mKeepDeviceLock).show(mHost);
mRequireNewDevicePassword = !mDpm.isPasswordSufficientAfterProfileUnification(
UserHandle.myUserId(), mProfileUserId);
startUnification();
} else {
final String title = mContext.getString(R.string.unlock_set_unlock_launch_picker_title);
final ChooseLockSettingsHelper helper =
@@ -149,13 +146,9 @@ public class LockUnificationPreferenceController extends AbstractPreferenceContr
public boolean handleActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == UNUNIFY_LOCK_CONFIRM_DEVICE_REQUEST
&& resultCode == Activity.RESULT_OK) {
ununifyLocks();
return true;
} else if (requestCode == UNIFY_LOCK_CONFIRM_DEVICE_REQUEST
&& resultCode == Activity.RESULT_OK) {
mCurrentDevicePassword =
data.getParcelableExtra(ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD);
launchConfirmProfileLock();
ununifyLocks();
return true;
} else if (requestCode == UNIFY_LOCK_CONFIRM_PROFILE_REQUEST
&& resultCode == Activity.RESULT_OK) {
@@ -170,67 +163,44 @@ public class LockUnificationPreferenceController extends AbstractPreferenceContr
private void ununifyLocks() {
final Bundle extras = new Bundle();
extras.putInt(Intent.EXTRA_USER_ID, mProfileUserId);
extras.putParcelable(ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD, mCurrentDevicePassword);
new SubSettingLauncher(mContext)
.setDestination(ChooseLockGeneric.ChooseLockGenericFragment.class.getName())
.setTitleRes(R.string.lock_settings_picker_title_profile)
.setTitleRes(R.string.lock_settings_picker_title_profile)
.setSourceMetricsCategory(mHost.getMetricsCategory())
.setArguments(extras)
.launch();
}
/** Asks the user to confirm device lock (if there is one) and proceeds to ask profile lock. */
private void launchConfirmDeviceAndProfileLock() {
final String title = mContext.getString(
R.string.unlock_set_unlock_launch_picker_title);
final ChooseLockSettingsHelper helper =
new ChooseLockSettingsHelper(mHost.getActivity(), mHost);
if (!helper.launchConfirmationActivity(
UNIFY_LOCK_CONFIRM_DEVICE_REQUEST, title, true, MY_USER_ID)) {
launchConfirmProfileLock();
}
}
private void launchConfirmProfileLock() {
void startUnification() {
// Confirm profile lock
final String title = mContext.getString(
R.string.unlock_set_unlock_launch_picker_title_profile);
final ChooseLockSettingsHelper helper =
new ChooseLockSettingsHelper(mHost.getActivity(), mHost);
if (!helper.launchConfirmationActivity(
UNIFY_LOCK_CONFIRM_PROFILE_REQUEST, title, true, mProfileUserId)) {
// If profile has no lock, go straight to unification.
unifyLocks();
// TODO: update relevant prefs.
// createPreferenceHierarchy();
}
}
void startUnification() {
// If the device lock stays the same, only confirm profile lock. Otherwise confirm both.
if (mKeepDeviceLock) {
launchConfirmProfileLock();
} else {
launchConfirmDeviceAndProfileLock();
}
}
private void unifyLocks() {
if (mKeepDeviceLock) {
unifyKeepingDeviceLock();
promptForNewDeviceLock();
if (mRequireNewDevicePassword) {
promptForNewDeviceLockAndThenUnify();
} else {
unifyKeepingWorkLock();
unifyKeepingDeviceLock();
}
if (mCurrentDevicePassword != null) {
mCurrentDevicePassword.zeroize();
mCurrentDevicePassword = null;
}
if (mCurrentProfilePassword != null) {
mCurrentProfilePassword.zeroize();
mCurrentProfilePassword = null;
}
mCurrentDevicePassword = null;
mCurrentProfilePassword = null;
}
private void unifyKeepingWorkLock() {
mLockPatternUtils.setLockCredential(
mCurrentProfilePassword, mCurrentDevicePassword, MY_USER_ID);
mLockPatternUtils.setSeparateProfileChallengeEnabled(mProfileUserId, false,
mCurrentProfilePassword);
final boolean profilePatternVisibility =
mLockPatternUtils.isVisiblePatternEnabled(mProfileUserId);
mLockPatternUtils.setVisiblePatternEnabled(profilePatternVisibility, MY_USER_ID);
}
private void unifyKeepingDeviceLock() {
@@ -238,11 +208,16 @@ public class LockUnificationPreferenceController extends AbstractPreferenceContr
mCurrentProfilePassword);
}
private void promptForNewDeviceLock() {
private void promptForNewDeviceLockAndThenUnify() {
final Bundle extras = new Bundle();
extras.putInt(ChooseLockSettingsHelper.EXTRA_KEY_UNIFICATION_PROFILE_ID, mProfileUserId);
extras.putParcelable(ChooseLockSettingsHelper.EXTRA_KEY_UNIFICATION_PROFILE_CREDENTIAL,
mCurrentProfilePassword);
new SubSettingLauncher(mContext)
.setDestination(ChooseLockGeneric.ChooseLockGenericFragment.class.getName())
.setTitleRes(R.string.lock_settings_picker_title)
.setSourceMetricsCategory(mHost.getMetricsCategory())
.setArguments(extras)
.launch();
}