Refactor ChooseLockGenericController
* Move all logics around aggregating password policies to the controller * Replace HIDE_DISABLED_PREFS and MINIMUM_QUALITY_KEY with HIDE_INSECURE_OPTIONS as all call sites are just using them to hide insecure screenlock options. * Remove password policy aggregation logic from ChooseLockPassword and make it use policies passed in. * Remove padlock from disabled screen lock options, per UX mock. * Increase char limit for some strings Bug: 177638284 Bug: 177641868 Bug: 182561862 Test: m RunSettingsRoboTests -j ROBOTEST_FILTER=com.android.settings.password Test: 1. set profile password quality/complexity and enroll device lock 2. set profile password quality/complexity and enroll work challenge 3. set parent password quality/complexity and enroll device lock 4. set parent password quality/complexity and enroll work challenge 5. set profile and parent password complexity, then enroll work challenge 6. set profile and parent password complexity, then unify work challenge 7. Enroll device lock during SUW Change-Id: Iba1d37e6f33eba7b7e8e1f805f8e37aaec108404
This commit is contained in:
@@ -1311,16 +1311,16 @@
|
|||||||
<!-- Title for security picker to choose the unlock method: None/Pattern/PIN/Password [CHAR LIMIT=22] -->
|
<!-- Title for security picker to choose the unlock method: None/Pattern/PIN/Password [CHAR LIMIT=22] -->
|
||||||
<string name="lock_settings_picker_title">Choose screen lock</string>
|
<string name="lock_settings_picker_title">Choose screen lock</string>
|
||||||
|
|
||||||
<!-- Screen title. This title is asking the user to choose a type of screen lock for their device, such as a pattern, PIN, or password. [CHAR LIMIT=27] -->
|
<!-- Screen title. This title is asking the user to choose a type of screen lock for their device, such as a pattern, PIN, or password. [CHAR LIMIT=55] -->
|
||||||
<string name="lock_settings_picker_new_lock_title">Choose a screen lock</string>
|
<string name="lock_settings_picker_new_lock_title">Choose a screen lock</string>
|
||||||
|
|
||||||
<!-- Screen title. This title is asking the user to choose a new screen lock for their device, such as a pattern, PIN, or password. [CHAR LIMIT=27] -->
|
<!-- Screen title. This title is asking the user to choose a new screen lock for their device, such as a pattern, PIN, or password. [CHAR LIMIT=55] -->
|
||||||
<string name="lock_settings_picker_update_lock_title">Choose a new screen lock</string>
|
<string name="lock_settings_picker_update_lock_title">Choose a new screen lock</string>
|
||||||
|
|
||||||
<!-- Screen title. This title is asking the user to choose a type of screen lock (such as a pattern, PIN, or password) that they need to enter to use their work apps. [CHAR LIMIT=27] -->
|
<!-- Screen title. This title is asking the user to choose a type of screen lock (such as a pattern, PIN, or password) that they need to enter to use their work apps. [CHAR LIMIT=56] -->
|
||||||
<string name="lock_settings_picker_new_profile_lock_title">Choose a lock for work apps</string>
|
<string name="lock_settings_picker_new_profile_lock_title">Choose a lock for work apps</string>
|
||||||
|
|
||||||
<!-- Screen title. This title is asking the user to choose a new screen lock (such as a pattern, PIN, or password) that they need to enter to use their work apps. [CHAR LIMIT=27] -->
|
<!-- Screen title. This title is asking the user to choose a new screen lock (such as a pattern, PIN, or password) that they need to enter to use their work apps. [CHAR LIMIT=55] -->
|
||||||
<string name="lock_settings_picker_update_profile_lock_title">Choose a new work lock</string>
|
<string name="lock_settings_picker_update_profile_lock_title">Choose a new work lock</string>
|
||||||
|
|
||||||
<!-- Title for security picker in setup wizard to choose the unlock method: None/Pattern/PIN/Password (tablet) [CHAR LIMIT=22] -->
|
<!-- Title for security picker in setup wizard to choose the unlock method: None/Pattern/PIN/Password (tablet) [CHAR LIMIT=22] -->
|
||||||
|
@@ -298,9 +298,7 @@ public class BiometricEnrollActivity extends InstrumentedActivity {
|
|||||||
private void launchChooseLock() {
|
private void launchChooseLock() {
|
||||||
Log.d(TAG, "launchChooseLock");
|
Log.d(TAG, "launchChooseLock");
|
||||||
Intent intent = BiometricUtils.getChooseLockIntent(this, getIntent());
|
Intent intent = BiometricUtils.getChooseLockIntent(this, getIntent());
|
||||||
intent.putExtra(ChooseLockGeneric.ChooseLockGenericFragment.MINIMUM_QUALITY_KEY,
|
intent.putExtra(ChooseLockGeneric.ChooseLockGenericFragment.HIDE_INSECURE_OPTIONS, true);
|
||||||
DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
|
|
||||||
intent.putExtra(ChooseLockGeneric.ChooseLockGenericFragment.HIDE_DISABLED_PREFS, true);
|
|
||||||
intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_REQUEST_GK_PW_HANDLE, true);
|
intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_REQUEST_GK_PW_HANDLE, true);
|
||||||
intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_FOR_BIOMETRICS, true);
|
intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_FOR_BIOMETRICS, true);
|
||||||
|
|
||||||
@@ -350,8 +348,7 @@ public class BiometricEnrollActivity extends InstrumentedActivity {
|
|||||||
final Intent intent;
|
final Intent intent;
|
||||||
// If only device credential was specified, ask the user to only set that up.
|
// If only device credential was specified, ask the user to only set that up.
|
||||||
intent = new Intent(this, ChooseLockGeneric.class);
|
intent = new Intent(this, ChooseLockGeneric.class);
|
||||||
intent.putExtra(ChooseLockGeneric.ChooseLockGenericFragment.MINIMUM_QUALITY_KEY,
|
intent.putExtra(ChooseLockGeneric.ChooseLockGenericFragment.HIDE_INSECURE_OPTIONS, true);
|
||||||
DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
|
|
||||||
launchEnrollActivity(intent);
|
launchEnrollActivity(intent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -222,9 +222,7 @@ public abstract class BiometricEnrollIntroduction extends BiometricEnrollBase
|
|||||||
|
|
||||||
private void launchChooseLock() {
|
private void launchChooseLock() {
|
||||||
Intent intent = BiometricUtils.getChooseLockIntent(this, getIntent());
|
Intent intent = BiometricUtils.getChooseLockIntent(this, getIntent());
|
||||||
intent.putExtra(ChooseLockGeneric.ChooseLockGenericFragment.MINIMUM_QUALITY_KEY,
|
intent.putExtra(ChooseLockGeneric.ChooseLockGenericFragment.HIDE_INSECURE_OPTIONS, true);
|
||||||
DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
|
|
||||||
intent.putExtra(ChooseLockGeneric.ChooseLockGenericFragment.HIDE_DISABLED_PREFS, true);
|
|
||||||
intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_REQUEST_GK_PW_HANDLE, true);
|
intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_REQUEST_GK_PW_HANDLE, true);
|
||||||
intent.putExtra(getExtraKeyForBiometric(), true);
|
intent.putExtra(getExtraKeyForBiometric(), true);
|
||||||
if (mUserId != UserHandle.USER_NULL) {
|
if (mUserId != UserHandle.USER_NULL) {
|
||||||
|
@@ -19,7 +19,6 @@ import static android.app.Activity.RESULT_OK;
|
|||||||
|
|
||||||
import static com.android.settings.password.ChooseLockPattern.RESULT_FINISHED;
|
import static com.android.settings.password.ChooseLockPattern.RESULT_FINISHED;
|
||||||
|
|
||||||
import android.app.admin.DevicePolicyManager;
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.hardware.face.FaceManager;
|
import android.hardware.face.FaceManager;
|
||||||
@@ -193,9 +192,8 @@ public abstract class BiometricsSettingsBase extends DashboardFragment {
|
|||||||
|
|
||||||
if (!launched) {
|
if (!launched) {
|
||||||
Intent intent = BiometricUtils.getChooseLockIntent(getActivity(), getIntent());
|
Intent intent = BiometricUtils.getChooseLockIntent(getActivity(), getIntent());
|
||||||
intent.putExtra(ChooseLockGeneric.ChooseLockGenericFragment.MINIMUM_QUALITY_KEY,
|
intent.putExtra(ChooseLockGeneric.ChooseLockGenericFragment.HIDE_INSECURE_OPTIONS,
|
||||||
DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
|
true);
|
||||||
intent.putExtra(ChooseLockGeneric.ChooseLockGenericFragment.HIDE_DISABLED_PREFS, true);
|
|
||||||
intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_REQUEST_GK_PW_HANDLE, true);
|
intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_REQUEST_GK_PW_HANDLE, true);
|
||||||
intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_FOR_BIOMETRICS, true);
|
intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_FOR_BIOMETRICS, true);
|
||||||
|
|
||||||
|
@@ -685,9 +685,7 @@ public class FingerprintSettings extends SubSettings {
|
|||||||
// TODO: This should be cleaned up. ChooseLockGeneric should provide a way of
|
// TODO: This should be cleaned up. ChooseLockGeneric should provide a way of
|
||||||
// specifying arguments/requests, instead of relying on callers setting extras.
|
// specifying arguments/requests, instead of relying on callers setting extras.
|
||||||
intent.setClassName(SETTINGS_PACKAGE_NAME, ChooseLockGeneric.class.getName());
|
intent.setClassName(SETTINGS_PACKAGE_NAME, ChooseLockGeneric.class.getName());
|
||||||
intent.putExtra(ChooseLockGeneric.ChooseLockGenericFragment.MINIMUM_QUALITY_KEY,
|
intent.putExtra(ChooseLockGeneric.ChooseLockGenericFragment.HIDE_INSECURE_OPTIONS,
|
||||||
DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
|
|
||||||
intent.putExtra(ChooseLockGeneric.ChooseLockGenericFragment.HIDE_DISABLED_PREFS,
|
|
||||||
true);
|
true);
|
||||||
intent.putExtra(Intent.EXTRA_USER_ID, mUserId);
|
intent.putExtra(Intent.EXTRA_USER_ID, mUserId);
|
||||||
intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_REQUEST_GK_PW_HANDLE, true);
|
intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_REQUEST_GK_PW_HANDLE, true);
|
||||||
|
@@ -75,8 +75,6 @@ import com.android.settings.biometrics.BiometricEnrollBase;
|
|||||||
import com.android.settings.core.SubSettingLauncher;
|
import com.android.settings.core.SubSettingLauncher;
|
||||||
import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
|
import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
|
||||||
import com.android.settings.search.SearchFeatureProvider;
|
import com.android.settings.search.SearchFeatureProvider;
|
||||||
import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
|
|
||||||
import com.android.settingslib.RestrictedLockUtilsInternal;
|
|
||||||
import com.android.settingslib.RestrictedPreference;
|
import com.android.settingslib.RestrictedPreference;
|
||||||
|
|
||||||
import com.google.android.setupcompat.util.WizardManagerHelper;
|
import com.google.android.setupcompat.util.WizardManagerHelper;
|
||||||
@@ -112,8 +110,7 @@ public class ChooseLockGeneric extends SettingsActivity {
|
|||||||
private static final String KEY_SKIP_BIOMETRICS = "unlock_skip_biometrics";
|
private static final String KEY_SKIP_BIOMETRICS = "unlock_skip_biometrics";
|
||||||
private static final String PASSWORD_CONFIRMED = "password_confirmed";
|
private static final String PASSWORD_CONFIRMED = "password_confirmed";
|
||||||
private static final String WAITING_FOR_CONFIRMATION = "waiting_for_confirmation";
|
private static final String WAITING_FOR_CONFIRMATION = "waiting_for_confirmation";
|
||||||
public static final String MINIMUM_QUALITY_KEY = "minimum_quality";
|
public static final String HIDE_INSECURE_OPTIONS = "hide_insecure_options";
|
||||||
public static final String HIDE_DISABLED_PREFS = "hide_disabled_prefs";
|
|
||||||
public static final String TAG_FRP_WARNING_DIALOG = "frp_warning_dialog";
|
public static final String TAG_FRP_WARNING_DIALOG = "frp_warning_dialog";
|
||||||
public static final String KEY_LOCK_SETTINGS_FOOTER ="lock_settings_footer";
|
public static final String KEY_LOCK_SETTINGS_FOOTER ="lock_settings_footer";
|
||||||
|
|
||||||
@@ -277,21 +274,20 @@ public class ChooseLockGeneric extends SettingsActivity {
|
|||||||
arguments,
|
arguments,
|
||||||
intent.getExtras()).getIdentifier();
|
intent.getExtras()).getIdentifier();
|
||||||
mIsManagedProfile = UserManager.get(getActivity()).isManagedProfile(mUserId);
|
mIsManagedProfile = UserManager.get(getActivity()).isManagedProfile(mUserId);
|
||||||
mController = new ChooseLockGenericController(
|
mController = new ChooseLockGenericController.Builder(
|
||||||
getContext(), mUserId, mRequestedMinComplexity,
|
getContext(), mUserId, mLockPatternUtils)
|
||||||
mOnlyEnforceDevicePasswordRequirement,
|
.setAppRequestedMinComplexity(mRequestedMinComplexity)
|
||||||
mLockPatternUtils);
|
.setEnforceDevicePasswordRequirementOnly(mOnlyEnforceDevicePasswordRequirement)
|
||||||
|
.setProfileToUnify(mUnificationProfileId)
|
||||||
final int aggregatedComplexity = mController.getAggregatedPasswordComplexity();
|
.setHideInsecureScreenLockTypes(alwaysHideInsecureScreenLockTypes()
|
||||||
final boolean isComplexityProvidedByAdmin =
|
|| intent.getBooleanExtra(HIDE_INSECURE_OPTIONS, false))
|
||||||
aggregatedComplexity > mRequestedMinComplexity
|
.build();
|
||||||
&& aggregatedComplexity > PASSWORD_COMPLEXITY_NONE;
|
|
||||||
|
|
||||||
// If the complexity is provided by the admin, do not get the caller app's name.
|
// If the complexity is provided by the admin, do not get the caller app's name.
|
||||||
// If the app requires, for example, low complexity, and the admin requires high
|
// If the app requires, for example, low complexity, and the admin requires high
|
||||||
// complexity, it does not make sense to show a footer telling the user it's the app
|
// complexity, it does not make sense to show a footer telling the user it's the app
|
||||||
// requesting a particular complexity because the admin-set complexity will override it.
|
// requesting a particular complexity because the admin-set complexity will override it.
|
||||||
mCallerAppName = isComplexityProvidedByAdmin ? null :
|
mCallerAppName = mController.isComplexityProvidedByAdmin() ? null :
|
||||||
intent.getStringExtra(EXTRA_KEY_CALLER_APP_NAME);
|
intent.getStringExtra(EXTRA_KEY_CALLER_APP_NAME);
|
||||||
|
|
||||||
mManagedPasswordProvider = ManagedLockPasswordProvider.get(activity, mUserId);
|
mManagedPasswordProvider = ManagedLockPasswordProvider.get(activity, mUserId);
|
||||||
@@ -330,6 +326,10 @@ public class ChooseLockGeneric extends SettingsActivity {
|
|||||||
return super.onCreateView(inflater, container, savedInstanceState);
|
return super.onCreateView(inflater, container, savedInstanceState);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected boolean alwaysHideInsecureScreenLockTypes() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
private void updateActivityTitle() {
|
private void updateActivityTitle() {
|
||||||
if (mLockPatternUtils == null) {
|
if (mLockPatternUtils == null) {
|
||||||
// mLockPatternUtils will be uninitialized if ChooseLockGenericFragment.onCreate()
|
// mLockPatternUtils will be uninitialized if ChooseLockGenericFragment.onCreate()
|
||||||
@@ -606,16 +606,12 @@ public class ChooseLockGeneric extends SettingsActivity {
|
|||||||
}
|
}
|
||||||
if (quality == -1) {
|
if (quality == -1) {
|
||||||
// If caller didn't specify password quality, show UI and allow the user to choose.
|
// If caller didn't specify password quality, show UI and allow the user to choose.
|
||||||
quality = intent.getIntExtra(MINIMUM_QUALITY_KEY, -1);
|
|
||||||
quality = mController.upgradeQuality(quality);
|
|
||||||
final boolean hideDisabledPrefs = intent.getBooleanExtra(
|
|
||||||
HIDE_DISABLED_PREFS, false);
|
|
||||||
final PreferenceScreen prefScreen = getPreferenceScreen();
|
final PreferenceScreen prefScreen = getPreferenceScreen();
|
||||||
if (prefScreen != null) {
|
if (prefScreen != null) {
|
||||||
prefScreen.removeAll();
|
prefScreen.removeAll();
|
||||||
}
|
}
|
||||||
addPreferences();
|
addPreferences();
|
||||||
disableUnusablePreferences(quality, hideDisabledPrefs);
|
disableUnusablePreferences();
|
||||||
updatePreferenceText();
|
updatePreferenceText();
|
||||||
updateCurrentPreference();
|
updateCurrentPreference();
|
||||||
updatePreferenceSummaryIfNeeded();
|
updatePreferenceSummaryIfNeeded();
|
||||||
@@ -746,71 +742,23 @@ public class ChooseLockGeneric extends SettingsActivity {
|
|||||||
return lock != null ? lock.preferenceKey : null;
|
return lock != null ? lock.preferenceKey : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/***
|
|
||||||
* Disables preferences that are less secure than required quality. The actual
|
|
||||||
* implementation is in disableUnusablePreferenceImpl.
|
|
||||||
*
|
|
||||||
* @param quality the requested quality.
|
|
||||||
* @param hideDisabledPrefs if false preferences show why they were disabled; otherwise
|
|
||||||
* they're not shown at all.
|
|
||||||
*/
|
|
||||||
protected void disableUnusablePreferences(final int quality, boolean hideDisabledPrefs) {
|
|
||||||
disableUnusablePreferencesImpl(quality, hideDisabledPrefs);
|
|
||||||
}
|
|
||||||
|
|
||||||
/***
|
/***
|
||||||
* Disables preferences that are less secure than required quality.
|
* Disables preferences that are less secure than required quality.
|
||||||
*
|
*
|
||||||
* @param quality the requested quality.
|
|
||||||
* @param hideDisabled whether to hide disable screen lock options.
|
|
||||||
*/
|
*/
|
||||||
protected void disableUnusablePreferencesImpl(final int quality,
|
private void disableUnusablePreferences() {
|
||||||
boolean hideDisabled) {
|
|
||||||
final PreferenceScreen entries = getPreferenceScreen();
|
final PreferenceScreen entries = getPreferenceScreen();
|
||||||
|
|
||||||
int adminEnforcedQuality = LockPatternUtils.credentialTypeToPasswordQuality(
|
|
||||||
mLockPatternUtils.getRequestedPasswordMetrics(
|
|
||||||
mUserId, mOnlyEnforceDevicePasswordRequirement).credType);
|
|
||||||
EnforcedAdmin enforcedAdmin =
|
|
||||||
RestrictedLockUtilsInternal.checkIfPasswordQualityIsSet(getActivity(),
|
|
||||||
mUserId);
|
|
||||||
// If we are to unify a work challenge at the end of the credential enrollment, manually
|
|
||||||
// merge any password policy from that profile here, so we are enrolling a compliant
|
|
||||||
// password. This is because once unified, the profile's password policy will
|
|
||||||
// be enforced on the new credential.
|
|
||||||
if (mUnificationProfileId != UserHandle.USER_NULL) {
|
|
||||||
int profileEnforceQuality = mDpm.getPasswordQuality(null, mUnificationProfileId);
|
|
||||||
if (profileEnforceQuality > adminEnforcedQuality) {
|
|
||||||
adminEnforcedQuality = profileEnforceQuality;
|
|
||||||
enforcedAdmin = EnforcedAdmin.combine(enforcedAdmin,
|
|
||||||
RestrictedLockUtilsInternal.checkIfPasswordQualityIsSet(
|
|
||||||
getActivity(), mUnificationProfileId));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (ScreenLockType lock : ScreenLockType.values()) {
|
for (ScreenLockType lock : ScreenLockType.values()) {
|
||||||
String key = lock.preferenceKey;
|
String key = lock.preferenceKey;
|
||||||
Preference pref = findPreference(key);
|
Preference pref = findPreference(key);
|
||||||
if (pref instanceof RestrictedPreference) {
|
if (pref instanceof RestrictedPreference) {
|
||||||
boolean visible = mController.isScreenLockVisible(lock);
|
boolean visible = mController.isScreenLockVisible(lock);
|
||||||
boolean enabled = mController.isScreenLockEnabled(lock, quality);
|
boolean enabled = mController.isScreenLockEnabled(lock);
|
||||||
boolean disabledByAdmin =
|
|
||||||
mController.isScreenLockDisabledByAdmin(lock, adminEnforcedQuality);
|
|
||||||
if (hideDisabled) {
|
|
||||||
visible = visible && enabled;
|
|
||||||
}
|
|
||||||
if (!visible) {
|
if (!visible) {
|
||||||
entries.removePreference(pref);
|
entries.removePreference(pref);
|
||||||
} else if (disabledByAdmin && enforcedAdmin != null) {
|
|
||||||
((RestrictedPreference) pref).setDisabledByAdmin(enforcedAdmin);
|
|
||||||
} else if (!enabled) {
|
} else if (!enabled) {
|
||||||
// we need to setDisabledByAdmin to null first to disable the padlock
|
|
||||||
// in case it was set earlier.
|
|
||||||
((RestrictedPreference) pref).setDisabledByAdmin(null);
|
|
||||||
pref.setSummary(R.string.unlock_set_unlock_disabled_summary);
|
|
||||||
pref.setEnabled(false);
|
pref.setEnabled(false);
|
||||||
} else {
|
|
||||||
((RestrictedPreference) pref).setDisabledByAdmin(null);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -17,6 +17,7 @@
|
|||||||
package com.android.settings.password;
|
package com.android.settings.password;
|
||||||
|
|
||||||
import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_NONE;
|
import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_NONE;
|
||||||
|
import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
|
||||||
|
|
||||||
import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_NONE;
|
import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_NONE;
|
||||||
|
|
||||||
@@ -24,6 +25,7 @@ import android.app.admin.DevicePolicyManager.PasswordComplexity;
|
|||||||
import android.app.admin.PasswordMetrics;
|
import android.app.admin.PasswordMetrics;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.os.UserHandle;
|
import android.os.UserHandle;
|
||||||
|
import android.os.UserManager;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.VisibleForTesting;
|
import androidx.annotation.VisibleForTesting;
|
||||||
@@ -36,84 +38,140 @@ import java.util.List;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* A controller for ChooseLockGeneric, and other similar classes which shows a list of possible
|
* A controller for ChooseLockGeneric, and other similar classes which shows a list of possible
|
||||||
* screen locks for the user to choose from.
|
* screen lock types for the user to choose from. This is the main place where different
|
||||||
|
* restrictions on allowed screen lock types are aggregated in Settings.
|
||||||
|
*
|
||||||
|
* Each screen lock type has two states: whether it is visible and whether it is enabled.
|
||||||
|
* Visibility is affected by things like resource configs, whether it's for a managed profile,
|
||||||
|
* or whether the caller allows it or not. This is determined by
|
||||||
|
* {@link #isScreenLockVisible(ScreenLockType)}. For visible screen lock types, they can be disabled
|
||||||
|
* by a combination of admin policies and request from the calling app, which is determined by
|
||||||
|
* {@link #isScreenLockEnabled(ScreenLockType}.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public class ChooseLockGenericController {
|
public class ChooseLockGenericController {
|
||||||
|
|
||||||
private final Context mContext;
|
private final Context mContext;
|
||||||
private final int mUserId;
|
private final int mUserId;
|
||||||
@PasswordComplexity private final int mRequestedMinComplexity;
|
private final boolean mHideInsecureScreenLockTypes;
|
||||||
|
@PasswordComplexity private final int mAppRequestedMinComplexity;
|
||||||
private final boolean mDevicePasswordRequirementOnly;
|
private final boolean mDevicePasswordRequirementOnly;
|
||||||
private ManagedLockPasswordProvider mManagedPasswordProvider;
|
private final int mUnificationProfileId;
|
||||||
|
private final ManagedLockPasswordProvider mManagedPasswordProvider;
|
||||||
private final LockPatternUtils mLockPatternUtils;
|
private final LockPatternUtils mLockPatternUtils;
|
||||||
|
|
||||||
public ChooseLockGenericController(Context context, int userId) {
|
public ChooseLockGenericController(Context context, int userId,
|
||||||
this(
|
ManagedLockPasswordProvider managedPasswordProvider, LockPatternUtils lockPatternUtils,
|
||||||
context,
|
boolean hideInsecureScreenLockTypes, int appRequestedMinComplexity,
|
||||||
userId,
|
boolean devicePasswordRequirementOnly, int unificationProfileId) {
|
||||||
PASSWORD_COMPLEXITY_NONE,
|
mContext = context;
|
||||||
/* mOnlyEnforceDevicePasswordRequirement */ false,
|
mUserId = userId;
|
||||||
new LockPatternUtils(context));
|
mManagedPasswordProvider = managedPasswordProvider;
|
||||||
|
mLockPatternUtils = lockPatternUtils;
|
||||||
|
mHideInsecureScreenLockTypes = hideInsecureScreenLockTypes;
|
||||||
|
mAppRequestedMinComplexity = appRequestedMinComplexity;
|
||||||
|
mDevicePasswordRequirementOnly = devicePasswordRequirementOnly;
|
||||||
|
mUnificationProfileId = unificationProfileId;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Builder class for {@link ChooseLockGenericController} */
|
||||||
* @param requestedMinComplexity specifies the min password complexity to be taken into account
|
public static class Builder {
|
||||||
* when determining the available screen lock types
|
private final Context mContext;
|
||||||
*/
|
private final int mUserId;
|
||||||
public ChooseLockGenericController(Context context, int userId,
|
private final ManagedLockPasswordProvider mManagedPasswordProvider;
|
||||||
@PasswordComplexity int requestedMinComplexity,
|
private final LockPatternUtils mLockPatternUtils;
|
||||||
boolean devicePasswordRequirementOnly,
|
|
||||||
|
private boolean mHideInsecureScreenLockTypes = false;
|
||||||
|
@PasswordComplexity private int mAppRequestedMinComplexity = PASSWORD_COMPLEXITY_NONE;
|
||||||
|
private boolean mDevicePasswordRequirementOnly = false;
|
||||||
|
private int mUnificationProfileId = UserHandle.USER_NULL;
|
||||||
|
|
||||||
|
public Builder(Context context, int userId) {
|
||||||
|
this(context, userId, new LockPatternUtils(context));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder(Context context, int userId,
|
||||||
LockPatternUtils lockPatternUtils) {
|
LockPatternUtils lockPatternUtils) {
|
||||||
this(
|
this(
|
||||||
context,
|
context,
|
||||||
userId,
|
userId,
|
||||||
requestedMinComplexity,
|
|
||||||
devicePasswordRequirementOnly,
|
|
||||||
ManagedLockPasswordProvider.get(context, userId),
|
ManagedLockPasswordProvider.get(context, userId),
|
||||||
lockPatternUtils);
|
lockPatternUtils);
|
||||||
}
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
ChooseLockGenericController(
|
Builder(
|
||||||
Context context,
|
Context context,
|
||||||
int userId,
|
int userId,
|
||||||
@PasswordComplexity int requestedMinComplexity,
|
|
||||||
boolean devicePasswordRequirementOnly,
|
|
||||||
ManagedLockPasswordProvider managedLockPasswordProvider,
|
ManagedLockPasswordProvider managedLockPasswordProvider,
|
||||||
LockPatternUtils lockPatternUtils) {
|
LockPatternUtils lockPatternUtils) {
|
||||||
mContext = context;
|
mContext = context;
|
||||||
mUserId = userId;
|
mUserId = userId;
|
||||||
mRequestedMinComplexity = requestedMinComplexity;
|
|
||||||
mDevicePasswordRequirementOnly = devicePasswordRequirementOnly;
|
|
||||||
mManagedPasswordProvider = managedLockPasswordProvider;
|
mManagedPasswordProvider = managedLockPasswordProvider;
|
||||||
mLockPatternUtils = lockPatternUtils;
|
mLockPatternUtils = lockPatternUtils;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the highest quality among the specified {@code quality}, the password requirement
|
* Sets the password complexity requested by the calling app via
|
||||||
* set by device admins (legacy password quality metrics and password complexity), and the
|
* {@link android.app.admin.DevicePolicyManager#EXTRA_PASSWORD_COMPLEXITY}.
|
||||||
* min password complexity requested by the calling app.
|
|
||||||
*/
|
*/
|
||||||
public int upgradeQuality(int quality) {
|
public Builder setAppRequestedMinComplexity(int complexity) {
|
||||||
// Compare specified quality and dpm quality
|
mAppRequestedMinComplexity = complexity;
|
||||||
// TODO(b/142781408): convert from quality to credential type once PIN is supported.
|
return this;
|
||||||
int dpmUpgradedQuality = Math.max(quality, LockPatternUtils.credentialTypeToPasswordQuality(
|
|
||||||
getAggregatedPasswordMetrics().credType));
|
|
||||||
return Math.max(dpmUpgradedQuality,
|
|
||||||
PasswordMetrics.complexityLevelToMinQuality(getAggregatedPasswordComplexity()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether the given screen lock type should be visible in the given context.
|
* Sets whether the enrolment flow should discard any password policies originating from the
|
||||||
|
* work profile, even if the work profile currently has unified challenge. This can be
|
||||||
|
* requested by the calling app via
|
||||||
|
* {@link android.app.admin.DevicePolicyManager#EXTRA_DEVICE_PASSWORD_REQUIREMENT_ONLY}.
|
||||||
|
*/
|
||||||
|
public Builder setEnforceDevicePasswordRequirementOnly(boolean deviceOnly) {
|
||||||
|
mDevicePasswordRequirementOnly = deviceOnly;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the user ID of any profile whose work challenge should be unified at the end of this
|
||||||
|
* enrolment flow. This will lead to all password policies from that profile to be taken
|
||||||
|
* into consideration by this class, so that we are enrolling a compliant password. This is
|
||||||
|
* because once unified, the profile's password policy will be enforced on the new
|
||||||
|
* credential.
|
||||||
|
*/
|
||||||
|
public Builder setProfileToUnify(int profileId) {
|
||||||
|
mUnificationProfileId = profileId;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets whether insecure screen lock types (NONE and SWIPE) should be hidden in the UI.
|
||||||
|
*/
|
||||||
|
public Builder setHideInsecureScreenLockTypes(boolean hide) {
|
||||||
|
mHideInsecureScreenLockTypes = hide;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Creates {@link ChooseLockGenericController} instance. */
|
||||||
|
public ChooseLockGenericController build() {
|
||||||
|
return new ChooseLockGenericController(mContext, mUserId, mManagedPasswordProvider,
|
||||||
|
mLockPatternUtils, mHideInsecureScreenLockTypes, mAppRequestedMinComplexity,
|
||||||
|
mDevicePasswordRequirementOnly, mUnificationProfileId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether the given screen lock type should be visible in the given context.
|
||||||
*/
|
*/
|
||||||
public boolean isScreenLockVisible(ScreenLockType type) {
|
public boolean isScreenLockVisible(ScreenLockType type) {
|
||||||
final boolean managedProfile = mUserId != UserHandle.myUserId();
|
final boolean managedProfile = mContext.getSystemService(UserManager.class)
|
||||||
|
.isManagedProfile(mUserId);
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case NONE:
|
case NONE:
|
||||||
return !mContext.getResources().getBoolean(R.bool.config_hide_none_security_option)
|
return !mHideInsecureScreenLockTypes
|
||||||
|
&& !mContext.getResources().getBoolean(R.bool.config_hide_none_security_option)
|
||||||
&& !managedProfile; // Profiles should use unified challenge instead.
|
&& !managedProfile; // Profiles should use unified challenge instead.
|
||||||
case SWIPE:
|
case SWIPE:
|
||||||
return !mContext.getResources().getBoolean(R.bool.config_hide_swipe_security_option)
|
return !mHideInsecureScreenLockTypes
|
||||||
|
&& !mContext.getResources().getBoolean(R.bool.config_hide_swipe_security_option)
|
||||||
&& !managedProfile; // Swipe doesn't make sense for profiles.
|
&& !managedProfile; // Swipe doesn't make sense for profiles.
|
||||||
case MANAGED:
|
case MANAGED:
|
||||||
return mManagedPasswordProvider.isManagedPasswordChoosable();
|
return mManagedPasswordProvider.isManagedPasswordChoosable();
|
||||||
@@ -128,29 +186,27 @@ public class ChooseLockGenericController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether screen lock with {@code type} should be enabled.
|
* Whether screen lock with {@code type} should be enabled assuming all relevant password
|
||||||
*
|
* requirements. The lock's visibility ({@link #isScreenLockVisible}) is not considered here.
|
||||||
* @param type The screen lock type.
|
|
||||||
* @param quality The minimum required quality. This can either be requirement by device policy
|
|
||||||
* manager or because some flow only makes sense with secure lock screens.
|
|
||||||
*/
|
*/
|
||||||
public boolean isScreenLockEnabled(ScreenLockType type, int quality) {
|
public boolean isScreenLockEnabled(ScreenLockType type) {
|
||||||
return type.maxQuality >= quality;
|
return type.maxQuality >= upgradeQuality(PASSWORD_QUALITY_UNSPECIFIED);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether screen lock with {@code type} is disabled by device policy admin.
|
* Increases the given quality to be as high as the combined quality from all relevant
|
||||||
*
|
* password requirements.
|
||||||
* @param type The screen lock type.
|
|
||||||
* @param adminEnforcedQuality The minimum quality that the admin enforces.
|
|
||||||
*/
|
*/
|
||||||
public boolean isScreenLockDisabledByAdmin(ScreenLockType type, int adminEnforcedQuality) {
|
// TODO(b/142781408): convert from quality to credential type once PIN is supported.
|
||||||
boolean disabledByAdmin = type.maxQuality < adminEnforcedQuality;
|
public int upgradeQuality(int quality) {
|
||||||
if (type == ScreenLockType.MANAGED) {
|
return Math.max(quality,
|
||||||
disabledByAdmin = disabledByAdmin
|
Math.max(
|
||||||
|| !mManagedPasswordProvider.isManagedPasswordChoosable();
|
LockPatternUtils.credentialTypeToPasswordQuality(
|
||||||
}
|
getAggregatedPasswordMetrics().credType),
|
||||||
return disabledByAdmin;
|
PasswordMetrics.complexityLevelToMinQuality(
|
||||||
|
getAggregatedPasswordComplexity())
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -175,43 +231,72 @@ public class ChooseLockGenericController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets a list of screen locks that should be visible for the given quality. The returned list
|
* Gets a list of screen lock types that should be visible for the given quality. The returned
|
||||||
* is ordered in the natural order of the enum (the order those enums were defined).
|
* list is ordered in the natural order of the enum (the order those enums were defined). Screen
|
||||||
*
|
* locks disabled by password policy will not be returned.
|
||||||
* @param quality The minimum quality required in the context of the current flow. This should
|
|
||||||
* be one of the constants defined in
|
|
||||||
* {@code DevicePolicyManager#PASSWORD_QUALITY_*}.
|
|
||||||
* @param includeDisabled Whether to include screen locks disabled by {@code quality}
|
|
||||||
* requirements in the returned list.
|
|
||||||
*/
|
*/
|
||||||
@NonNull
|
@NonNull
|
||||||
public List<ScreenLockType> getVisibleScreenLockTypes(int quality, boolean includeDisabled) {
|
public List<ScreenLockType> getVisibleAndEnabledScreenLockTypes() {
|
||||||
int upgradedQuality = upgradeQuality(quality);
|
|
||||||
List<ScreenLockType> locks = new ArrayList<>();
|
List<ScreenLockType> locks = new ArrayList<>();
|
||||||
// EnumSet's iterator guarantees the natural order of the enums
|
// EnumSet's iterator guarantees the natural order of the enums
|
||||||
for (ScreenLockType lock : ScreenLockType.values()) {
|
for (ScreenLockType lock : ScreenLockType.values()) {
|
||||||
if (isScreenLockVisible(lock)) {
|
if (isScreenLockVisible(lock) && isScreenLockEnabled(lock)) {
|
||||||
if (includeDisabled || isScreenLockEnabled(lock, upgradedQuality)) {
|
|
||||||
locks.add(lock);
|
locks.add(lock);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return locks;
|
return locks;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the combined password metrics from all relevant policies which affects the current
|
||||||
|
* user. Normally password policies set on the current user's work profile instance will be
|
||||||
|
* taken into consideration here iff the work profile doesn't have its own work challenge.
|
||||||
|
* By setting {@link #mUnificationProfileId}, the work profile's password policy will always
|
||||||
|
* be combined here. Alternatively, by setting {@link #mDevicePasswordRequirementOnly}, its
|
||||||
|
* password policy will always be disregarded here.
|
||||||
|
*/
|
||||||
public PasswordMetrics getAggregatedPasswordMetrics() {
|
public PasswordMetrics getAggregatedPasswordMetrics() {
|
||||||
return mLockPatternUtils.getRequestedPasswordMetrics(mUserId,
|
PasswordMetrics metrics = mLockPatternUtils.getRequestedPasswordMetrics(mUserId,
|
||||||
mDevicePasswordRequirementOnly);
|
mDevicePasswordRequirementOnly);
|
||||||
|
if (mUnificationProfileId != UserHandle.USER_NULL) {
|
||||||
|
metrics.maxWith(mLockPatternUtils.getRequestedPasswordMetrics(mUnificationProfileId));
|
||||||
|
}
|
||||||
|
return metrics;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the combined password complexity from all relevant policies which affects the current
|
||||||
|
* user. The same logic of handling work profile password policies as
|
||||||
|
* {@link #getAggregatedPasswordMetrics} applies here.
|
||||||
|
*/
|
||||||
public int getAggregatedPasswordComplexity() {
|
public int getAggregatedPasswordComplexity() {
|
||||||
return Math.max(mRequestedMinComplexity,
|
int complexity = Math.max(mAppRequestedMinComplexity,
|
||||||
mLockPatternUtils.getRequestedPasswordComplexity(
|
mLockPatternUtils.getRequestedPasswordComplexity(
|
||||||
mUserId, mDevicePasswordRequirementOnly));
|
mUserId, mDevicePasswordRequirementOnly));
|
||||||
|
if (mUnificationProfileId != UserHandle.USER_NULL) {
|
||||||
|
complexity = Math.max(complexity,
|
||||||
|
mLockPatternUtils.getRequestedPasswordComplexity(mUnificationProfileId));
|
||||||
|
}
|
||||||
|
return complexity;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether any screen lock type has been disabled only due to password policy
|
||||||
|
* from the admin. Will return {@code false} if the restriction is purely due to calling
|
||||||
|
* app's request.
|
||||||
|
*/
|
||||||
public boolean isScreenLockRestrictedByAdmin() {
|
public boolean isScreenLockRestrictedByAdmin() {
|
||||||
return getAggregatedPasswordMetrics().credType != CREDENTIAL_TYPE_NONE
|
return getAggregatedPasswordMetrics().credType != CREDENTIAL_TYPE_NONE
|
||||||
|| getAggregatedPasswordComplexity() != PASSWORD_COMPLEXITY_NONE;
|
|| isComplexityProvidedByAdmin();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether the aggregated password complexity is non-zero and comes from
|
||||||
|
* admin policy.
|
||||||
|
*/
|
||||||
|
public boolean isComplexityProvidedByAdmin() {
|
||||||
|
final int aggregatedComplexity = getAggregatedPasswordComplexity();
|
||||||
|
return aggregatedComplexity > mAppRequestedMinComplexity
|
||||||
|
&& aggregatedComplexity > PASSWORD_COMPLEXITY_NONE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -416,19 +416,6 @@ public class ChooseLockPassword extends SettingsActivity {
|
|||||||
mMinComplexity = intent.getIntExtra(EXTRA_KEY_MIN_COMPLEXITY, PASSWORD_COMPLEXITY_NONE);
|
mMinComplexity = intent.getIntExtra(EXTRA_KEY_MIN_COMPLEXITY, PASSWORD_COMPLEXITY_NONE);
|
||||||
mMinMetrics = intent.getParcelableExtra(EXTRA_KEY_MIN_METRICS);
|
mMinMetrics = intent.getParcelableExtra(EXTRA_KEY_MIN_METRICS);
|
||||||
if (mMinMetrics == null) mMinMetrics = new PasswordMetrics(CREDENTIAL_TYPE_NONE);
|
if (mMinMetrics == null) mMinMetrics = new PasswordMetrics(CREDENTIAL_TYPE_NONE);
|
||||||
// If we are to unify a work challenge at the end of the credential enrollment, manually
|
|
||||||
// merge any password policy from that profile here, so we are enrolling a compliant
|
|
||||||
// password. This is because once unified, the profile's password policy will
|
|
||||||
// be enforced on the new credential.
|
|
||||||
//TODO: Move this logic to ChooseLockGeneric; let ChooseLockGeneric be the only place
|
|
||||||
//where password requirement mixing happens. ChooseLockPassword simply enforces what's
|
|
||||||
//set via IntentBuilder.setPasswordRequirement()
|
|
||||||
if (mUnificationProfileId != UserHandle.USER_NULL) {
|
|
||||||
mMinMetrics.maxWith(
|
|
||||||
mLockPatternUtils.getRequestedPasswordMetrics(mUnificationProfileId));
|
|
||||||
mMinComplexity = Math.max(mMinComplexity,
|
|
||||||
mLockPatternUtils.getRequestedPasswordComplexity(mUnificationProfileId));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (intent.getBooleanExtra(
|
if (intent.getBooleanExtra(
|
||||||
ChooseLockSettingsHelper.EXTRA_KEY_FOR_CHANGE_CRED_REQUIRED_FOR_BOOT, false)) {
|
ChooseLockSettingsHelper.EXTRA_KEY_FOR_CHANGE_CRED_REQUIRED_FOR_BOOT, false)) {
|
||||||
|
@@ -18,7 +18,6 @@ package com.android.settings.password;
|
|||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.app.Dialog;
|
import android.app.Dialog;
|
||||||
import android.app.admin.DevicePolicyManager;
|
|
||||||
import android.app.settings.SettingsEnums;
|
import android.app.settings.SettingsEnums;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.DialogInterface;
|
import android.content.DialogInterface;
|
||||||
@@ -100,7 +99,9 @@ public class ChooseLockTypeDialogFragment extends InstrumentedDialogFragment
|
|||||||
public void onCreate(Bundle savedInstanceState) {
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
final int userId = getArguments().getInt(ARG_USER_ID);
|
final int userId = getArguments().getInt(ARG_USER_ID);
|
||||||
mController = new ChooseLockGenericController(getContext(), userId);
|
mController = new ChooseLockGenericController.Builder(getContext(), userId)
|
||||||
|
.setHideInsecureScreenLockTypes(true)
|
||||||
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -124,10 +125,7 @@ public class ChooseLockTypeDialogFragment extends InstrumentedDialogFragment
|
|||||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||||
Context context = getContext();
|
Context context = getContext();
|
||||||
Builder builder = new Builder(context);
|
Builder builder = new Builder(context);
|
||||||
List<ScreenLockType> locks =
|
List<ScreenLockType> locks = mController.getVisibleAndEnabledScreenLockTypes();
|
||||||
mController.getVisibleScreenLockTypes(
|
|
||||||
DevicePolicyManager.PASSWORD_QUALITY_SOMETHING,
|
|
||||||
false /* includeDisabled */);
|
|
||||||
mAdapter = new ScreenLockAdapter(context, locks, mController);
|
mAdapter = new ScreenLockAdapter(context, locks, mController);
|
||||||
builder.setAdapter(mAdapter, this);
|
builder.setAdapter(mAdapter, this);
|
||||||
builder.setTitle(R.string.setup_lock_settings_options_dialog_title);
|
builder.setTitle(R.string.setup_lock_settings_options_dialog_title);
|
||||||
|
@@ -19,7 +19,6 @@ package com.android.settings.password;
|
|||||||
import static android.app.admin.DevicePolicyManager.ACTION_SET_NEW_PASSWORD;
|
import static android.app.admin.DevicePolicyManager.ACTION_SET_NEW_PASSWORD;
|
||||||
import static android.app.admin.DevicePolicyManager.KEYGUARD_DISABLE_FACE;
|
import static android.app.admin.DevicePolicyManager.KEYGUARD_DISABLE_FACE;
|
||||||
import static android.app.admin.DevicePolicyManager.KEYGUARD_DISABLE_FINGERPRINT;
|
import static android.app.admin.DevicePolicyManager.KEYGUARD_DISABLE_FINGERPRINT;
|
||||||
import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_SOMETHING;
|
|
||||||
|
|
||||||
import static com.android.internal.util.Preconditions.checkNotNull;
|
import static com.android.internal.util.Preconditions.checkNotNull;
|
||||||
|
|
||||||
@@ -145,10 +144,8 @@ final class SetNewPasswordController {
|
|||||||
|
|
||||||
private Bundle getBiometricChooseLockExtras() {
|
private Bundle getBiometricChooseLockExtras() {
|
||||||
Bundle chooseLockExtras = new Bundle();
|
Bundle chooseLockExtras = new Bundle();
|
||||||
chooseLockExtras.putInt(ChooseLockGeneric.ChooseLockGenericFragment.MINIMUM_QUALITY_KEY,
|
|
||||||
PASSWORD_QUALITY_SOMETHING);
|
|
||||||
chooseLockExtras.putBoolean(
|
chooseLockExtras.putBoolean(
|
||||||
ChooseLockGeneric.ChooseLockGenericFragment.HIDE_DISABLED_PREFS, true);
|
ChooseLockGeneric.ChooseLockGenericFragment.HIDE_INSECURE_OPTIONS, true);
|
||||||
chooseLockExtras.putBoolean(ChooseLockSettingsHelper.EXTRA_KEY_REQUEST_GK_PW_HANDLE, true);
|
chooseLockExtras.putBoolean(ChooseLockSettingsHelper.EXTRA_KEY_REQUEST_GK_PW_HANDLE, true);
|
||||||
chooseLockExtras.putBoolean(ChooseLockSettingsHelper.EXTRA_KEY_FOR_BIOMETRICS, true);
|
chooseLockExtras.putBoolean(ChooseLockSettingsHelper.EXTRA_KEY_FOR_BIOMETRICS, true);
|
||||||
return chooseLockExtras;
|
return chooseLockExtras;
|
||||||
@@ -156,10 +153,8 @@ final class SetNewPasswordController {
|
|||||||
|
|
||||||
private Bundle getFingerprintChooseLockExtras() {
|
private Bundle getFingerprintChooseLockExtras() {
|
||||||
Bundle chooseLockExtras = new Bundle();
|
Bundle chooseLockExtras = new Bundle();
|
||||||
chooseLockExtras.putInt(ChooseLockGeneric.ChooseLockGenericFragment.MINIMUM_QUALITY_KEY,
|
|
||||||
PASSWORD_QUALITY_SOMETHING);
|
|
||||||
chooseLockExtras.putBoolean(
|
chooseLockExtras.putBoolean(
|
||||||
ChooseLockGeneric.ChooseLockGenericFragment.HIDE_DISABLED_PREFS, true);
|
ChooseLockGeneric.ChooseLockGenericFragment.HIDE_INSECURE_OPTIONS, true);
|
||||||
chooseLockExtras.putBoolean(ChooseLockSettingsHelper.EXTRA_KEY_REQUEST_GK_PW_HANDLE, true);
|
chooseLockExtras.putBoolean(ChooseLockSettingsHelper.EXTRA_KEY_REQUEST_GK_PW_HANDLE, true);
|
||||||
chooseLockExtras.putBoolean(ChooseLockSettingsHelper.EXTRA_KEY_FOR_FINGERPRINT, true);
|
chooseLockExtras.putBoolean(ChooseLockSettingsHelper.EXTRA_KEY_FOR_FINGERPRINT, true);
|
||||||
return chooseLockExtras;
|
return chooseLockExtras;
|
||||||
@@ -167,10 +162,8 @@ final class SetNewPasswordController {
|
|||||||
|
|
||||||
private Bundle getFaceChooseLockExtras() {
|
private Bundle getFaceChooseLockExtras() {
|
||||||
Bundle chooseLockExtras = new Bundle();
|
Bundle chooseLockExtras = new Bundle();
|
||||||
chooseLockExtras.putInt(ChooseLockGeneric.ChooseLockGenericFragment.MINIMUM_QUALITY_KEY,
|
|
||||||
PASSWORD_QUALITY_SOMETHING);
|
|
||||||
chooseLockExtras.putBoolean(
|
chooseLockExtras.putBoolean(
|
||||||
ChooseLockGeneric.ChooseLockGenericFragment.HIDE_DISABLED_PREFS, true);
|
ChooseLockGeneric.ChooseLockGenericFragment.HIDE_INSECURE_OPTIONS, true);
|
||||||
chooseLockExtras.putBoolean(ChooseLockSettingsHelper.EXTRA_KEY_REQUEST_GK_PW_HANDLE, true);
|
chooseLockExtras.putBoolean(ChooseLockSettingsHelper.EXTRA_KEY_REQUEST_GK_PW_HANDLE, true);
|
||||||
chooseLockExtras.putBoolean(ChooseLockSettingsHelper.EXTRA_KEY_FOR_FACE, true);
|
chooseLockExtras.putBoolean(ChooseLockSettingsHelper.EXTRA_KEY_FOR_FACE, true);
|
||||||
return chooseLockExtras;
|
return chooseLockExtras;
|
||||||
|
@@ -21,7 +21,6 @@ import static android.app.admin.DevicePolicyManager.EXTRA_PASSWORD_COMPLEXITY;
|
|||||||
|
|
||||||
import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_REQUESTED_MIN_COMPLEXITY;
|
import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_REQUESTED_MIN_COMPLEXITY;
|
||||||
|
|
||||||
import android.app.admin.DevicePolicyManager;
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.res.Resources;
|
import android.content.res.Resources;
|
||||||
@@ -160,22 +159,12 @@ public class SetupChooseLockGeneric extends ChooseLockGeneric {
|
|||||||
return SetupChooseLockGeneric.InternalActivity.class;
|
return SetupChooseLockGeneric.InternalActivity.class;
|
||||||
}
|
}
|
||||||
|
|
||||||
/***
|
|
||||||
* Disables preferences that are less secure than required quality and shows only secure
|
|
||||||
* screen lock options here.
|
|
||||||
*
|
|
||||||
* @param quality the requested quality.
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
protected void disableUnusablePreferences(final int quality, boolean hideDisabled) {
|
protected boolean alwaysHideInsecureScreenLockTypes() {
|
||||||
// At this part of the flow, the user has already indicated they want to add a pin,
|
// At this part of the flow, the user has already indicated they want to add a pin,
|
||||||
// pattern or password, so don't show "None" or "Slide". We disable them here and set
|
// pattern or password, so don't show "None" or "Slide". We disable them here.
|
||||||
// the HIDE_DISABLED flag to true to hide them. This only happens for setup wizard.
|
// This only happens for setup wizard.
|
||||||
// We do the following max check here since the device may already have a Device Admin
|
return true;
|
||||||
// installed with a policy we need to honor.
|
|
||||||
final int newQuality = Math.max(quality,
|
|
||||||
DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
|
|
||||||
super.disableUnusablePreferencesImpl(newQuality, true /* hideDisabled */);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@@ -17,7 +17,6 @@
|
|||||||
package com.android.settings.password;
|
package com.android.settings.password;
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.app.admin.DevicePolicyManager;
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
@@ -81,9 +80,11 @@ public class SetupChooseLockPassword extends ChooseLockPassword {
|
|||||||
super.onViewCreated(view, savedInstanceState);
|
super.onViewCreated(view, savedInstanceState);
|
||||||
final Activity activity = getActivity();
|
final Activity activity = getActivity();
|
||||||
ChooseLockGenericController chooseLockGenericController =
|
ChooseLockGenericController chooseLockGenericController =
|
||||||
new ChooseLockGenericController(activity, mUserId);
|
new ChooseLockGenericController.Builder(activity, mUserId)
|
||||||
boolean anyOptionsShown = chooseLockGenericController.getVisibleScreenLockTypes(
|
.setHideInsecureScreenLockTypes(true)
|
||||||
DevicePolicyManager.PASSWORD_QUALITY_SOMETHING, false).size() > 0;
|
.build();
|
||||||
|
boolean anyOptionsShown = chooseLockGenericController
|
||||||
|
.getVisibleAndEnabledScreenLockTypes().size() > 0;
|
||||||
boolean showOptionsButton = activity.getIntent().getBooleanExtra(
|
boolean showOptionsButton = activity.getIntent().getBooleanExtra(
|
||||||
ChooseLockGeneric.ChooseLockGenericFragment.EXTRA_SHOW_OPTIONS_BUTTON, false);
|
ChooseLockGeneric.ChooseLockGenericFragment.EXTRA_SHOW_OPTIONS_BUTTON, false);
|
||||||
if (!anyOptionsShown) {
|
if (!anyOptionsShown) {
|
||||||
|
@@ -136,8 +136,8 @@ public class ScreenPinningSettings extends SettingsPreferenceFragment
|
|||||||
if (passwordQuality == DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
|
if (passwordQuality == DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
|
||||||
Intent chooseLockIntent = new Intent(DevicePolicyManager.ACTION_SET_NEW_PASSWORD);
|
Intent chooseLockIntent = new Intent(DevicePolicyManager.ACTION_SET_NEW_PASSWORD);
|
||||||
chooseLockIntent.putExtra(
|
chooseLockIntent.putExtra(
|
||||||
ChooseLockGeneric.ChooseLockGenericFragment.MINIMUM_QUALITY_KEY,
|
ChooseLockGeneric.ChooseLockGenericFragment.HIDE_INSECURE_OPTIONS,
|
||||||
DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
|
true);
|
||||||
startActivityForResult(chooseLockIntent, CHANGE_LOCK_METHOD_REQUEST);
|
startActivityForResult(chooseLockIntent, CHANGE_LOCK_METHOD_REQUEST);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@@ -432,8 +432,8 @@ public class UserSettings extends SettingsPreferenceFragment
|
|||||||
|
|
||||||
private void launchChooseLockscreen() {
|
private void launchChooseLockscreen() {
|
||||||
Intent chooseLockIntent = new Intent(DevicePolicyManager.ACTION_SET_NEW_PASSWORD);
|
Intent chooseLockIntent = new Intent(DevicePolicyManager.ACTION_SET_NEW_PASSWORD);
|
||||||
chooseLockIntent.putExtra(ChooseLockGeneric.ChooseLockGenericFragment.MINIMUM_QUALITY_KEY,
|
chooseLockIntent.putExtra(ChooseLockGeneric.ChooseLockGenericFragment.HIDE_INSECURE_OPTIONS,
|
||||||
DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
|
true);
|
||||||
startActivityForResult(chooseLockIntent, REQUEST_CHOOSE_LOCK);
|
startActivityForResult(chooseLockIntent, REQUEST_CHOOSE_LOCK);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -20,23 +20,31 @@ import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_HIGH;
|
|||||||
import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_LOW;
|
import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_LOW;
|
||||||
import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_MEDIUM;
|
import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_MEDIUM;
|
||||||
import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_NONE;
|
import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_NONE;
|
||||||
|
import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC;
|
||||||
|
import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_COMPLEX;
|
||||||
|
import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_NUMERIC;
|
||||||
|
import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX;
|
||||||
|
import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_SOMETHING;
|
||||||
|
import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
|
||||||
|
|
||||||
import static com.google.common.truth.Truth.assertThat;
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
import static com.google.common.truth.Truth.assertWithMessage;
|
import static com.google.common.truth.Truth.assertWithMessage;
|
||||||
|
|
||||||
import static org.mockito.ArgumentMatchers.anyBoolean;
|
import static org.mockito.ArgumentMatchers.anyBoolean;
|
||||||
import static org.mockito.ArgumentMatchers.anyInt;
|
import static org.mockito.ArgumentMatchers.anyInt;
|
||||||
|
import static org.mockito.ArgumentMatchers.eq;
|
||||||
import static org.mockito.Mockito.doReturn;
|
import static org.mockito.Mockito.doReturn;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
import static org.robolectric.RuntimeEnvironment.application;
|
import static org.robolectric.RuntimeEnvironment.application;
|
||||||
|
|
||||||
import android.app.admin.DevicePolicyManager;
|
import android.app.admin.DevicePolicyManager;
|
||||||
import android.app.admin.DevicePolicyManager.PasswordComplexity;
|
|
||||||
import android.app.admin.PasswordPolicy;
|
import android.app.admin.PasswordPolicy;
|
||||||
|
import android.os.UserHandle;
|
||||||
|
|
||||||
import com.android.internal.widget.LockPatternUtils;
|
import com.android.internal.widget.LockPatternUtils;
|
||||||
import com.android.settings.R;
|
import com.android.settings.R;
|
||||||
import com.android.settings.testutils.shadow.SettingsShadowResources;
|
import com.android.settings.testutils.shadow.SettingsShadowResources;
|
||||||
|
import com.android.settings.testutils.shadow.ShadowUserManager;
|
||||||
|
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
@@ -48,10 +56,11 @@ import org.robolectric.RobolectricTestRunner;
|
|||||||
import org.robolectric.annotation.Config;
|
import org.robolectric.annotation.Config;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
@RunWith(RobolectricTestRunner.class)
|
@RunWith(RobolectricTestRunner.class)
|
||||||
@Config(shadows = SettingsShadowResources.class)
|
@Config(shadows = {ShadowUserManager.class, SettingsShadowResources.class})
|
||||||
public class ChooseLockGenericControllerTest {
|
public class ChooseLockGenericControllerTest {
|
||||||
|
|
||||||
private ChooseLockGenericController mController;
|
private ChooseLockGenericController mController;
|
||||||
@@ -68,7 +77,7 @@ public class ChooseLockGenericControllerTest {
|
|||||||
|
|
||||||
when(mLockPatternUtils.hasSecureLockScreen()).thenReturn(true);
|
when(mLockPatternUtils.hasSecureLockScreen()).thenReturn(true);
|
||||||
setDevicePolicyPasswordQuality(DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED);
|
setDevicePolicyPasswordQuality(DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED);
|
||||||
mController = createController(PASSWORD_COMPLEXITY_NONE);
|
mController = createBuilder().build();
|
||||||
SettingsShadowResources.overrideResource(R.bool.config_hide_none_security_option, false);
|
SettingsShadowResources.overrideResource(R.bool.config_hide_none_security_option, false);
|
||||||
SettingsShadowResources.overrideResource(R.bool.config_hide_swipe_security_option, false);
|
SettingsShadowResources.overrideResource(R.bool.config_hide_swipe_security_option, false);
|
||||||
}
|
}
|
||||||
@@ -95,8 +104,8 @@ public class ChooseLockGenericControllerTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void isScreenLockVisible_notCurrentUser_shouldHideInsecure() {
|
public void isScreenLockVisible_ManagedProfile_shouldHideInsecure() {
|
||||||
mController = new ChooseLockGenericController(application, 1 /* userId */);
|
ShadowUserManager.getShadow().setManagedProfiles(Set.of(0));
|
||||||
assertWithMessage("SWIPE visible").that(
|
assertWithMessage("SWIPE visible").that(
|
||||||
mController.isScreenLockVisible(ScreenLockType.SWIPE)).isFalse();
|
mController.isScreenLockVisible(ScreenLockType.SWIPE)).isFalse();
|
||||||
assertWithMessage("NONE visible").that(mController.isScreenLockVisible(ScreenLockType.NONE))
|
assertWithMessage("NONE visible").that(mController.isScreenLockVisible(ScreenLockType.NONE))
|
||||||
@@ -112,62 +121,116 @@ public class ChooseLockGenericControllerTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void isScreenLockEnabled_lowerQuality_shouldReturnFalse() {
|
public void isScreenLockEnabled_Default() {
|
||||||
for (ScreenLockType lock : ScreenLockType.values()) {
|
assertThat(mController.isScreenLockEnabled(ScreenLockType.NONE)).isTrue();
|
||||||
assertWithMessage(lock + " enabled").that(
|
assertThat(mController.isScreenLockEnabled(ScreenLockType.SWIPE)).isTrue();
|
||||||
mController.isScreenLockEnabled(lock, lock.maxQuality + 1)).isFalse();
|
assertThat(mController.isScreenLockEnabled(ScreenLockType.PATTERN)).isTrue();
|
||||||
}
|
assertThat(mController.isScreenLockEnabled(ScreenLockType.PIN)).isTrue();
|
||||||
|
assertThat(mController.isScreenLockEnabled(ScreenLockType.PASSWORD)).isTrue();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void isScreenLockEnabled_equalQuality_shouldReturnTrue() {
|
public void isScreenLockEnabled_QualityUnspecified() {
|
||||||
for (ScreenLockType lock : ScreenLockType.values()) {
|
setDevicePolicyPasswordQuality(PASSWORD_QUALITY_UNSPECIFIED);
|
||||||
assertWithMessage(lock + " enabled").that(
|
assertThat(mController.isScreenLockEnabled(ScreenLockType.NONE)).isTrue();
|
||||||
mController.isScreenLockEnabled(lock, lock.defaultQuality)).isTrue();
|
assertThat(mController.isScreenLockEnabled(ScreenLockType.SWIPE)).isTrue();
|
||||||
}
|
assertThat(mController.isScreenLockEnabled(ScreenLockType.PATTERN)).isTrue();
|
||||||
|
assertThat(mController.isScreenLockEnabled(ScreenLockType.PIN)).isTrue();
|
||||||
|
assertThat(mController.isScreenLockEnabled(ScreenLockType.PASSWORD)).isTrue();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void isScreenLockEnabled_higherQuality_shouldReturnTrue() {
|
public void isScreenLockEnabled_QualitySomething() {
|
||||||
for (ScreenLockType lock : ScreenLockType.values()) {
|
setDevicePolicyPasswordQuality(PASSWORD_QUALITY_SOMETHING);
|
||||||
assertWithMessage(lock + " enabled").that(
|
assertThat(mController.isScreenLockEnabled(ScreenLockType.NONE)).isFalse();
|
||||||
mController.isScreenLockEnabled(lock, lock.maxQuality - 1)).isTrue();
|
assertThat(mController.isScreenLockEnabled(ScreenLockType.SWIPE)).isFalse();
|
||||||
}
|
assertThat(mController.isScreenLockEnabled(ScreenLockType.PATTERN)).isTrue();
|
||||||
|
assertThat(mController.isScreenLockEnabled(ScreenLockType.PIN)).isTrue();
|
||||||
|
assertThat(mController.isScreenLockEnabled(ScreenLockType.PASSWORD)).isTrue();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void isScreenLockDisabledByAdmin_lowerQuality_shouldReturnTrue() {
|
public void isScreenLockEnabled_QualityNumeric() {
|
||||||
doReturn(true).when(mManagedLockPasswordProvider).isManagedPasswordChoosable();
|
setDevicePolicyPasswordQuality(PASSWORD_QUALITY_NUMERIC);
|
||||||
for (ScreenLockType lock : ScreenLockType.values()) {
|
assertThat(mController.isScreenLockEnabled(ScreenLockType.NONE)).isFalse();
|
||||||
assertWithMessage(lock + " disabledByAdmin").that(
|
assertThat(mController.isScreenLockEnabled(ScreenLockType.SWIPE)).isFalse();
|
||||||
mController.isScreenLockDisabledByAdmin(lock, lock.maxQuality + 1)).isTrue();
|
assertThat(mController.isScreenLockEnabled(ScreenLockType.PATTERN)).isFalse();
|
||||||
}
|
assertThat(mController.isScreenLockEnabled(ScreenLockType.PIN)).isTrue();
|
||||||
|
assertThat(mController.isScreenLockEnabled(ScreenLockType.PASSWORD)).isTrue();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void isScreenLockDisabledByAdmin_equalQuality_shouldReturnFalse() {
|
public void isScreenLockEnabled_QualityNumericComplex() {
|
||||||
doReturn(true).when(mManagedLockPasswordProvider).isManagedPasswordChoosable();
|
setDevicePolicyPasswordQuality(PASSWORD_QUALITY_NUMERIC_COMPLEX);
|
||||||
for (ScreenLockType lock : ScreenLockType.values()) {
|
assertThat(mController.isScreenLockEnabled(ScreenLockType.NONE)).isFalse();
|
||||||
assertWithMessage(lock + " disabledByAdmin").that(
|
assertThat(mController.isScreenLockEnabled(ScreenLockType.SWIPE)).isFalse();
|
||||||
mController.isScreenLockDisabledByAdmin(lock, lock.maxQuality)).isFalse();
|
assertThat(mController.isScreenLockEnabled(ScreenLockType.PATTERN)).isFalse();
|
||||||
}
|
assertThat(mController.isScreenLockEnabled(ScreenLockType.PIN)).isTrue();
|
||||||
|
assertThat(mController.isScreenLockEnabled(ScreenLockType.PASSWORD)).isTrue();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void isScreenLockDisabledByAdmin_higherQuality_shouldReturnFalse() {
|
public void isScreenLockEnabled_QualityAlphabetic() {
|
||||||
doReturn(true).when(mManagedLockPasswordProvider).isManagedPasswordChoosable();
|
setDevicePolicyPasswordQuality(PASSWORD_QUALITY_ALPHABETIC);
|
||||||
for (ScreenLockType lock : ScreenLockType.values()) {
|
assertThat(mController.isScreenLockEnabled(ScreenLockType.NONE)).isFalse();
|
||||||
assertWithMessage(lock + " disabledByAdmin").that(
|
assertThat(mController.isScreenLockEnabled(ScreenLockType.SWIPE)).isFalse();
|
||||||
mController.isScreenLockDisabledByAdmin(lock, lock.maxQuality - 1)).isFalse();
|
assertThat(mController.isScreenLockEnabled(ScreenLockType.PATTERN)).isFalse();
|
||||||
}
|
assertThat(mController.isScreenLockEnabled(ScreenLockType.PIN)).isFalse();
|
||||||
|
assertThat(mController.isScreenLockEnabled(ScreenLockType.PASSWORD)).isTrue();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void isScreenLockDisabledByAdmin_managedNotChoosable_shouldReturnTrue() {
|
public void isScreenLockEnabled_QualityComplex() {
|
||||||
doReturn(false).when(mManagedLockPasswordProvider).isManagedPasswordChoosable();
|
setDevicePolicyPasswordQuality(PASSWORD_QUALITY_COMPLEX);
|
||||||
assertWithMessage("MANANGED disabledByAdmin").that(mController.isScreenLockDisabledByAdmin(
|
assertThat(mController.isScreenLockEnabled(ScreenLockType.NONE)).isFalse();
|
||||||
ScreenLockType.MANAGED, DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED))
|
assertThat(mController.isScreenLockEnabled(ScreenLockType.SWIPE)).isFalse();
|
||||||
.isTrue();
|
assertThat(mController.isScreenLockEnabled(ScreenLockType.PATTERN)).isFalse();
|
||||||
|
assertThat(mController.isScreenLockEnabled(ScreenLockType.PIN)).isFalse();
|
||||||
|
assertThat(mController.isScreenLockEnabled(ScreenLockType.PASSWORD)).isTrue();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void isScreenLockEnabled_NoneComplexity() {
|
||||||
|
when(mLockPatternUtils.getRequestedPasswordComplexity(anyInt(), anyBoolean()))
|
||||||
|
.thenReturn(PASSWORD_COMPLEXITY_NONE);
|
||||||
|
assertThat(mController.isScreenLockEnabled(ScreenLockType.NONE)).isTrue();
|
||||||
|
assertThat(mController.isScreenLockEnabled(ScreenLockType.SWIPE)).isTrue();
|
||||||
|
assertThat(mController.isScreenLockEnabled(ScreenLockType.PATTERN)).isTrue();
|
||||||
|
assertThat(mController.isScreenLockEnabled(ScreenLockType.PIN)).isTrue();
|
||||||
|
assertThat(mController.isScreenLockEnabled(ScreenLockType.PASSWORD)).isTrue();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void isScreenLockEnabled_lowComplexity() {
|
||||||
|
when(mLockPatternUtils.getRequestedPasswordComplexity(anyInt(), anyBoolean()))
|
||||||
|
.thenReturn(PASSWORD_COMPLEXITY_LOW);
|
||||||
|
assertThat(mController.isScreenLockEnabled(ScreenLockType.NONE)).isFalse();
|
||||||
|
assertThat(mController.isScreenLockEnabled(ScreenLockType.SWIPE)).isFalse();
|
||||||
|
assertThat(mController.isScreenLockEnabled(ScreenLockType.PATTERN)).isTrue();
|
||||||
|
assertThat(mController.isScreenLockEnabled(ScreenLockType.PIN)).isTrue();
|
||||||
|
assertThat(mController.isScreenLockEnabled(ScreenLockType.PASSWORD)).isTrue();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void isScreenLockEnabled_mediumComplexity() {
|
||||||
|
when(mLockPatternUtils.getRequestedPasswordComplexity(anyInt(), anyBoolean()))
|
||||||
|
.thenReturn(PASSWORD_COMPLEXITY_MEDIUM);
|
||||||
|
assertThat(mController.isScreenLockEnabled(ScreenLockType.NONE)).isFalse();
|
||||||
|
assertThat(mController.isScreenLockEnabled(ScreenLockType.SWIPE)).isFalse();
|
||||||
|
assertThat(mController.isScreenLockEnabled(ScreenLockType.PATTERN)).isFalse();
|
||||||
|
assertThat(mController.isScreenLockEnabled(ScreenLockType.PIN)).isTrue();
|
||||||
|
assertThat(mController.isScreenLockEnabled(ScreenLockType.PASSWORD)).isTrue();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void isScreenLockEnabled_highComplexity() {
|
||||||
|
when(mLockPatternUtils.getRequestedPasswordComplexity(anyInt(), anyBoolean()))
|
||||||
|
.thenReturn(PASSWORD_COMPLEXITY_HIGH);
|
||||||
|
assertThat(mController.isScreenLockEnabled(ScreenLockType.NONE)).isFalse();
|
||||||
|
assertThat(mController.isScreenLockEnabled(ScreenLockType.SWIPE)).isFalse();
|
||||||
|
assertThat(mController.isScreenLockEnabled(ScreenLockType.PATTERN)).isFalse();
|
||||||
|
assertThat(mController.isScreenLockEnabled(ScreenLockType.PIN)).isTrue();
|
||||||
|
assertThat(mController.isScreenLockEnabled(ScreenLockType.PASSWORD)).isTrue();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -181,8 +244,8 @@ public class ChooseLockGenericControllerTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getVisibleScreenLockTypes_qualitySomething_shouldReturnPatterPinPassword() {
|
public void getVisibleScreenLockTypes_qualitySomething_shouldReturnPatterPinPassword() {
|
||||||
assertThat(mController.getVisibleScreenLockTypes(
|
mController = createBuilder().setHideInsecureScreenLockTypes(true).build();
|
||||||
DevicePolicyManager.PASSWORD_QUALITY_SOMETHING, false))
|
assertThat(mController.getVisibleAndEnabledScreenLockTypes())
|
||||||
.isEqualTo(Arrays.asList(
|
.isEqualTo(Arrays.asList(
|
||||||
ScreenLockType.PATTERN,
|
ScreenLockType.PATTERN,
|
||||||
ScreenLockType.PIN,
|
ScreenLockType.PIN,
|
||||||
@@ -191,8 +254,7 @@ public class ChooseLockGenericControllerTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getVisibleScreenLockTypes_showDisabled_shouldReturnAllButManaged() {
|
public void getVisibleScreenLockTypes_showDisabled_shouldReturnAllButManaged() {
|
||||||
assertThat(mController.getVisibleScreenLockTypes(
|
assertThat(mController.getVisibleAndEnabledScreenLockTypes())
|
||||||
DevicePolicyManager.PASSWORD_QUALITY_SOMETHING, true))
|
|
||||||
.isEqualTo(Arrays.asList(
|
.isEqualTo(Arrays.asList(
|
||||||
ScreenLockType.NONE,
|
ScreenLockType.NONE,
|
||||||
ScreenLockType.SWIPE,
|
ScreenLockType.SWIPE,
|
||||||
@@ -223,31 +285,68 @@ public class ChooseLockGenericControllerTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void upgradeQuality_complexityHigh_minQualityNumericComplex() {
|
public void upgradeQuality_complexityHigh_minQualityNumericComplex() {
|
||||||
|
mController = createBuilder().setAppRequestedMinComplexity(PASSWORD_COMPLEXITY_HIGH)
|
||||||
|
.build();
|
||||||
setDevicePolicyPasswordQuality(DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED);
|
setDevicePolicyPasswordQuality(DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED);
|
||||||
ChooseLockGenericController controller = createController(PASSWORD_COMPLEXITY_HIGH);
|
|
||||||
|
|
||||||
assertThat(controller.upgradeQuality(DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED))
|
assertThat(mController.upgradeQuality(DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED))
|
||||||
.isEqualTo(DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX);
|
.isEqualTo(DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void upgradeQuality_complexityMedium_minQualityNumericComplex() {
|
public void upgradeQuality_complexityMedium_minQualityNumericComplex() {
|
||||||
|
mController = createBuilder().setAppRequestedMinComplexity(PASSWORD_COMPLEXITY_MEDIUM)
|
||||||
|
.build();
|
||||||
setDevicePolicyPasswordQuality(DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED);
|
setDevicePolicyPasswordQuality(DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED);
|
||||||
ChooseLockGenericController controller = createController(PASSWORD_COMPLEXITY_MEDIUM);
|
|
||||||
|
|
||||||
assertThat(controller.upgradeQuality(DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED))
|
assertThat(mController.upgradeQuality(DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED))
|
||||||
.isEqualTo(DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX);
|
.isEqualTo(DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void upgradeQuality_complexityLow_minQualitySomething() {
|
public void upgradeQuality_complexityLow_minQualitySomething() {
|
||||||
|
mController = createBuilder().setAppRequestedMinComplexity(PASSWORD_COMPLEXITY_LOW)
|
||||||
|
.build();
|
||||||
setDevicePolicyPasswordQuality(DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED);
|
setDevicePolicyPasswordQuality(DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED);
|
||||||
ChooseLockGenericController controller = createController(PASSWORD_COMPLEXITY_LOW);
|
|
||||||
|
|
||||||
assertThat(controller.upgradeQuality(DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED))
|
assertThat(mController.upgradeQuality(DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED))
|
||||||
.isEqualTo(DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
|
.isEqualTo(DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getAggregatedPasswordComplexity_AppRequest() {
|
||||||
|
mController = createBuilder().setAppRequestedMinComplexity(PASSWORD_COMPLEXITY_HIGH)
|
||||||
|
.build();
|
||||||
|
assertThat(mController.getAggregatedPasswordComplexity())
|
||||||
|
.isEqualTo(PASSWORD_COMPLEXITY_HIGH);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getAggregatedPasswordComplexity_DevicePolicy() {
|
||||||
|
mController = createBuilder().setAppRequestedMinComplexity(PASSWORD_COMPLEXITY_LOW)
|
||||||
|
.build();
|
||||||
|
when(mLockPatternUtils.getRequestedPasswordComplexity(eq(UserHandle.myUserId()), eq(false)))
|
||||||
|
.thenReturn(PASSWORD_COMPLEXITY_MEDIUM);
|
||||||
|
|
||||||
|
assertThat(mController.getAggregatedPasswordComplexity())
|
||||||
|
.isEqualTo(PASSWORD_COMPLEXITY_MEDIUM);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getAggregatedPasswordComplexity_ProfileUnification() {
|
||||||
|
mController = createBuilder()
|
||||||
|
.setProfileToUnify(123)
|
||||||
|
.setAppRequestedMinComplexity(PASSWORD_COMPLEXITY_LOW)
|
||||||
|
.build();
|
||||||
|
when(mLockPatternUtils.getRequestedPasswordComplexity(eq(UserHandle.myUserId()), eq(false)))
|
||||||
|
.thenReturn(PASSWORD_COMPLEXITY_MEDIUM);
|
||||||
|
when(mLockPatternUtils.getRequestedPasswordComplexity(eq(123)))
|
||||||
|
.thenReturn(PASSWORD_COMPLEXITY_HIGH);
|
||||||
|
|
||||||
|
assertThat(mController.getAggregatedPasswordComplexity())
|
||||||
|
.isEqualTo(PASSWORD_COMPLEXITY_HIGH);
|
||||||
|
}
|
||||||
|
|
||||||
private void setDevicePolicyPasswordQuality(int quality) {
|
private void setDevicePolicyPasswordQuality(int quality) {
|
||||||
PasswordPolicy policy = new PasswordPolicy();
|
PasswordPolicy policy = new PasswordPolicy();
|
||||||
policy.quality = quality;
|
policy.quality = quality;
|
||||||
@@ -256,13 +355,10 @@ public class ChooseLockGenericControllerTest {
|
|||||||
.thenReturn(policy.getMinMetrics());
|
.thenReturn(policy.getMinMetrics());
|
||||||
}
|
}
|
||||||
|
|
||||||
private ChooseLockGenericController createController(
|
private ChooseLockGenericController.Builder createBuilder() {
|
||||||
@PasswordComplexity int minPasswordComplexity) {
|
return new ChooseLockGenericController.Builder(
|
||||||
return new ChooseLockGenericController(
|
|
||||||
application,
|
application,
|
||||||
0 /* userId */,
|
0 /* userId */,
|
||||||
minPasswordComplexity,
|
|
||||||
false,
|
|
||||||
mManagedLockPasswordProvider,
|
mManagedLockPasswordProvider,
|
||||||
mLockPatternUtils);
|
mLockPatternUtils);
|
||||||
}
|
}
|
||||||
|
@@ -30,7 +30,6 @@ import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED
|
|||||||
|
|
||||||
import static com.android.internal.widget.LockPatternUtils.PASSWORD_TYPE_KEY;
|
import static com.android.internal.widget.LockPatternUtils.PASSWORD_TYPE_KEY;
|
||||||
import static com.android.settings.password.ChooseLockGeneric.CONFIRM_CREDENTIALS;
|
import static com.android.settings.password.ChooseLockGeneric.CONFIRM_CREDENTIALS;
|
||||||
import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_UNIFICATION_PROFILE_ID;
|
|
||||||
|
|
||||||
import static com.google.common.truth.Truth.assertThat;
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
import static com.google.common.truth.Truth.assertWithMessage;
|
import static com.google.common.truth.Truth.assertWithMessage;
|
||||||
@@ -429,18 +428,6 @@ public class ChooseLockPasswordTest {
|
|||||||
"PIN must be at least 8 digits");
|
"PIN must be at least 8 digits");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void validateComplexityMergedFromUnificationUserOnCreate() {
|
|
||||||
ShadowLockPatternUtils.setRequiredPasswordComplexity(PASSWORD_COMPLEXITY_LOW);
|
|
||||||
ShadowLockPatternUtils.setRequiredPasswordComplexity(123, PASSWORD_COMPLEXITY_HIGH);
|
|
||||||
|
|
||||||
Intent intent = createIntentForPasswordValidation(null, PASSWORD_COMPLEXITY_NONE,
|
|
||||||
PASSWORD_QUALITY_NUMERIC);
|
|
||||||
intent.putExtra(EXTRA_KEY_UNIFICATION_PROFILE_ID, 123);
|
|
||||||
assertPasswordValidationResultForIntent(LockscreenCredential.createNone(), intent,
|
|
||||||
"PIN must be at least 8 digits");
|
|
||||||
}
|
|
||||||
|
|
||||||
private ChooseLockPassword buildChooseLockPasswordActivity(Intent intent) {
|
private ChooseLockPassword buildChooseLockPasswordActivity(Intent intent) {
|
||||||
return Robolectric.buildActivity(ChooseLockPassword.class, intent).setup().get();
|
return Robolectric.buildActivity(ChooseLockPassword.class, intent).setup().get();
|
||||||
}
|
}
|
||||||
|
@@ -19,8 +19,7 @@ package com.android.settings.password;
|
|||||||
import static android.content.pm.PackageManager.FEATURE_FACE;
|
import static android.content.pm.PackageManager.FEATURE_FACE;
|
||||||
import static android.content.pm.PackageManager.FEATURE_FINGERPRINT;
|
import static android.content.pm.PackageManager.FEATURE_FINGERPRINT;
|
||||||
|
|
||||||
import static com.android.settings.password.ChooseLockGeneric.ChooseLockGenericFragment.HIDE_DISABLED_PREFS;
|
import static com.android.settings.password.ChooseLockGeneric.ChooseLockGenericFragment.HIDE_INSECURE_OPTIONS;
|
||||||
import static com.android.settings.password.ChooseLockGeneric.ChooseLockGenericFragment.MINIMUM_QUALITY_KEY;
|
|
||||||
import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_FOR_FACE;
|
import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_FOR_FACE;
|
||||||
import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_FOR_FINGERPRINT;
|
import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_FOR_FINGERPRINT;
|
||||||
import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_REQUEST_GK_PW_HANDLE;
|
import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_REQUEST_GK_PW_HANDLE;
|
||||||
@@ -262,12 +261,9 @@ public final class SetNewPasswordControllerTest {
|
|||||||
|
|
||||||
private void compareFingerprintExtras(Bundle actualBundle) {
|
private void compareFingerprintExtras(Bundle actualBundle) {
|
||||||
assertEquals(
|
assertEquals(
|
||||||
"Password quality must be something in order to config fingerprint.",
|
"Insecure options must be disabled in order to config fingerprint.",
|
||||||
DevicePolicyManager.PASSWORD_QUALITY_SOMETHING,
|
true,
|
||||||
actualBundle.getInt(MINIMUM_QUALITY_KEY));
|
actualBundle.getBoolean(HIDE_INSECURE_OPTIONS));
|
||||||
assertTrue(
|
|
||||||
"All disabled preference should be removed.",
|
|
||||||
actualBundle.getBoolean(HIDE_DISABLED_PREFS));
|
|
||||||
assertTrue(
|
assertTrue(
|
||||||
"Fingerprint enroll must request Gatekeeper Password.",
|
"Fingerprint enroll must request Gatekeeper Password.",
|
||||||
actualBundle.getBoolean(EXTRA_KEY_REQUEST_GK_PW_HANDLE));
|
actualBundle.getBoolean(EXTRA_KEY_REQUEST_GK_PW_HANDLE));
|
||||||
@@ -282,12 +278,9 @@ public final class SetNewPasswordControllerTest {
|
|||||||
|
|
||||||
private void compareFaceExtras(Bundle actualBundle) {
|
private void compareFaceExtras(Bundle actualBundle) {
|
||||||
assertEquals(
|
assertEquals(
|
||||||
"Password quality must be something in order to config face.",
|
"Insecure options must be disabled in order to config face.",
|
||||||
DevicePolicyManager.PASSWORD_QUALITY_SOMETHING,
|
true,
|
||||||
actualBundle.getInt(MINIMUM_QUALITY_KEY));
|
actualBundle.getBoolean(HIDE_INSECURE_OPTIONS));
|
||||||
assertTrue(
|
|
||||||
"All disabled preference should be removed.",
|
|
||||||
actualBundle.getBoolean(HIDE_DISABLED_PREFS));
|
|
||||||
assertTrue(
|
assertTrue(
|
||||||
"Face enroll must request Gatekeeper Password",
|
"Face enroll must request Gatekeeper Password",
|
||||||
actualBundle.getBoolean(EXTRA_KEY_REQUEST_GK_PW_HANDLE));
|
actualBundle.getBoolean(EXTRA_KEY_REQUEST_GK_PW_HANDLE));
|
||||||
|
@@ -198,8 +198,7 @@ public class SetupChooseLockPasswordTest {
|
|||||||
@Implements(ChooseLockGenericController.class)
|
@Implements(ChooseLockGenericController.class)
|
||||||
public static class ShadowChooseLockGenericController {
|
public static class ShadowChooseLockGenericController {
|
||||||
@Implementation
|
@Implementation
|
||||||
protected List<ScreenLockType> getVisibleScreenLockTypes(int quality,
|
protected List<ScreenLockType> getVisibleScreenLockTypes() {
|
||||||
boolean includeDisabled) {
|
|
||||||
return Collections.emptyList();
|
return Collections.emptyList();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user