Merge "New extra for ACTION_SET_NEW_PASSWORD to specify the min complexity"
This commit is contained in:
committed by
Android (Google) Code Review
commit
a3750617db
@@ -1430,6 +1430,16 @@
|
|||||||
<!-- Title shown on security settings to allow the user to change their lockscreen password [CHAR LIMIT=22]-->
|
<!-- Title shown on security settings to allow the user to change their lockscreen password [CHAR LIMIT=22]-->
|
||||||
<string name="unlock_change_lock_password_title">Change unlock password</string>
|
<string name="unlock_change_lock_password_title">Change unlock password</string>
|
||||||
|
|
||||||
|
<!-- Footer preference text in the screen lock type picker to indicate which app is requesting a new screen lock and that it requests for a strong PIN or password [CHAR LIMIT=NONE] -->
|
||||||
|
<string name="unlock_footer_high_complexity_requested"><xliff:g id="app_name" example="Gmail">%1$s</xliff:g> requests a strong PIN or password.</string>
|
||||||
|
<!-- Footer preference text in the screen lock type picker to indicate which app is requesting a new screen lock and that it requests for a medium strength PIN or password [CHAR LIMIT=NONE] -->
|
||||||
|
<string name="unlock_footer_medium_complexity_requested"><xliff:g id="app_name" example="Gmail">%1$s</xliff:g> requests a new PIN or password.</string>
|
||||||
|
<!-- Footer preference text in the screen lock type picker to indicate which app is requesting a new screen lock and it requests for any screen lock [CHAR LIMIT=NONE] -->
|
||||||
|
<string name="unlock_footer_low_complexity_requested"><xliff:g id="app_name" example="Gmail">%1$s</xliff:g> requests a new pattern, PIN or password.</string>
|
||||||
|
<!-- Footer preference text in the screen lock type picker to indicate which app is requesting a new screen lock [CHAR LIMIT=NONE] -->
|
||||||
|
<string name="unlock_footer_none_complexity_requested"><xliff:g id="app_name" example="Gmail">%1$s</xliff:g> requests a new screen lock.</string>
|
||||||
|
|
||||||
|
|
||||||
<!-- Message shown on the lock screen when the user incorrectly enters their lock and it counts towards the max attempts before their data on the device is wiped. [CHAR LIMIT=NONE] -->
|
<!-- Message shown on the lock screen when the user incorrectly enters their lock and it counts towards the max attempts before their data on the device is wiped. [CHAR LIMIT=NONE] -->
|
||||||
<string name="lock_failed_attempts_before_wipe">Try again. Attempt <xliff:g id="current_attempts">%1$d</xliff:g> of <xliff:g id="total_attempts">%2$d</xliff:g>.</string>
|
<string name="lock_failed_attempts_before_wipe">Try again. Attempt <xliff:g id="current_attempts">%1$d</xliff:g> of <xliff:g id="total_attempts">%2$d</xliff:g>.</string>
|
||||||
|
|
||||||
|
@@ -18,13 +18,20 @@ package com.android.settings.password;
|
|||||||
|
|
||||||
import static android.app.admin.DevicePolicyManager.ACTION_SET_NEW_PARENT_PROFILE_PASSWORD;
|
import static android.app.admin.DevicePolicyManager.ACTION_SET_NEW_PARENT_PROFILE_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.PASSWORD_COMPLEXITY_HIGH;
|
||||||
|
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_NONE;
|
||||||
|
|
||||||
import static com.android.settings.password.ChooseLockPassword.ChooseLockPasswordFragment.RESULT_FINISHED;
|
import static com.android.settings.password.ChooseLockPassword.ChooseLockPasswordFragment.RESULT_FINISHED;
|
||||||
|
import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_CALLER_APP_NAME;
|
||||||
|
import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_REQUESTED_MIN_COMPLEXITY;
|
||||||
|
|
||||||
import android.accessibilityservice.AccessibilityServiceInfo;
|
import android.accessibilityservice.AccessibilityServiceInfo;
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.app.Dialog;
|
import android.app.Dialog;
|
||||||
import android.app.admin.DevicePolicyManager;
|
import android.app.admin.DevicePolicyManager;
|
||||||
|
import android.app.admin.DevicePolicyManager.PasswordComplexity;
|
||||||
import android.app.settings.SettingsEnums;
|
import android.app.settings.SettingsEnums;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
@@ -66,6 +73,8 @@ import com.android.settings.search.SearchFeatureProvider;
|
|||||||
import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
|
import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
|
||||||
import com.android.settingslib.RestrictedLockUtilsInternal;
|
import com.android.settingslib.RestrictedLockUtilsInternal;
|
||||||
import com.android.settingslib.RestrictedPreference;
|
import com.android.settingslib.RestrictedPreference;
|
||||||
|
import com.android.settingslib.widget.FooterPreference;
|
||||||
|
import com.android.settingslib.widget.FooterPreferenceMixinCompat;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@@ -152,6 +161,14 @@ public class ChooseLockGeneric extends SettingsActivity {
|
|||||||
private UserManager mUserManager;
|
private UserManager mUserManager;
|
||||||
private ChooseLockGenericController mController;
|
private ChooseLockGenericController mController;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* From intent extra {@link ChooseLockSettingsHelper#EXTRA_KEY_REQUESTED_MIN_COMPLEXITY}.
|
||||||
|
*/
|
||||||
|
@PasswordComplexity private int mRequestedMinComplexity;
|
||||||
|
|
||||||
|
/** From intent extra {@link ChooseLockSettingsHelper#EXTRA_KEY_CALLER_APP_NAME}. */
|
||||||
|
private String mCallerAppName = null;
|
||||||
|
|
||||||
protected boolean mForFingerprint = false;
|
protected boolean mForFingerprint = false;
|
||||||
protected boolean mForFace = false;
|
protected boolean mForFace = false;
|
||||||
|
|
||||||
@@ -195,6 +212,10 @@ public class ChooseLockGeneric extends SettingsActivity {
|
|||||||
ChooseLockSettingsHelper.EXTRA_KEY_FOR_FINGERPRINT, false);
|
ChooseLockSettingsHelper.EXTRA_KEY_FOR_FINGERPRINT, false);
|
||||||
mForFace = getActivity().getIntent().getBooleanExtra(
|
mForFace = getActivity().getIntent().getBooleanExtra(
|
||||||
ChooseLockSettingsHelper.EXTRA_KEY_FOR_FACE, false);
|
ChooseLockSettingsHelper.EXTRA_KEY_FOR_FACE, false);
|
||||||
|
mRequestedMinComplexity = getActivity().getIntent()
|
||||||
|
.getIntExtra(EXTRA_KEY_REQUESTED_MIN_COMPLEXITY, PASSWORD_COMPLEXITY_NONE);
|
||||||
|
mCallerAppName =
|
||||||
|
getActivity().getIntent().getStringExtra(EXTRA_KEY_CALLER_APP_NAME);
|
||||||
mForChangeCredRequiredForBoot = getArguments() != null && getArguments().getBoolean(
|
mForChangeCredRequiredForBoot = getArguments() != null && getArguments().getBoolean(
|
||||||
ChooseLockSettingsHelper.EXTRA_KEY_FOR_CHANGE_CRED_REQUIRED_FOR_BOOT);
|
ChooseLockSettingsHelper.EXTRA_KEY_FOR_CHANGE_CRED_REQUIRED_FOR_BOOT);
|
||||||
mUserManager = UserManager.get(getActivity());
|
mUserManager = UserManager.get(getActivity());
|
||||||
@@ -217,7 +238,8 @@ public class ChooseLockGeneric extends SettingsActivity {
|
|||||||
UserManager.get(getActivity()),
|
UserManager.get(getActivity()),
|
||||||
getArguments(),
|
getArguments(),
|
||||||
getActivity().getIntent().getExtras()).getIdentifier();
|
getActivity().getIntent().getExtras()).getIdentifier();
|
||||||
mController = new ChooseLockGenericController(getContext(), mUserId);
|
mController =
|
||||||
|
new ChooseLockGenericController(getContext(), mUserId, mRequestedMinComplexity);
|
||||||
if (ACTION_SET_NEW_PASSWORD.equals(chooseLockAction)
|
if (ACTION_SET_NEW_PASSWORD.equals(chooseLockAction)
|
||||||
&& UserManager.get(getActivity()).isManagedProfile(mUserId)
|
&& UserManager.get(getActivity()).isManagedProfile(mUserId)
|
||||||
&& mLockPatternUtils.isSeparateProfileChallengeEnabled(mUserId)) {
|
&& mLockPatternUtils.isSeparateProfileChallengeEnabled(mUserId)) {
|
||||||
@@ -291,6 +313,9 @@ public class ChooseLockGeneric extends SettingsActivity {
|
|||||||
// Forward the target user id to ChooseLockGeneric.
|
// Forward the target user id to ChooseLockGeneric.
|
||||||
chooseLockGenericIntent.putExtra(Intent.EXTRA_USER_ID, mUserId);
|
chooseLockGenericIntent.putExtra(Intent.EXTRA_USER_ID, mUserId);
|
||||||
chooseLockGenericIntent.putExtra(CONFIRM_CREDENTIALS, !mPasswordConfirmed);
|
chooseLockGenericIntent.putExtra(CONFIRM_CREDENTIALS, !mPasswordConfirmed);
|
||||||
|
chooseLockGenericIntent.putExtra(EXTRA_KEY_REQUESTED_MIN_COMPLEXITY,
|
||||||
|
mRequestedMinComplexity);
|
||||||
|
chooseLockGenericIntent.putExtra(EXTRA_KEY_CALLER_APP_NAME, mCallerAppName);
|
||||||
if (mUserPassword != null) {
|
if (mUserPassword != null) {
|
||||||
chooseLockGenericIntent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD,
|
chooseLockGenericIntent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD,
|
||||||
mUserPassword);
|
mUserPassword);
|
||||||
@@ -461,6 +486,13 @@ public class ChooseLockGeneric extends SettingsActivity {
|
|||||||
protected void addPreferences() {
|
protected void addPreferences() {
|
||||||
addPreferencesFromResource(R.xml.security_settings_picker);
|
addPreferencesFromResource(R.xml.security_settings_picker);
|
||||||
|
|
||||||
|
if (!TextUtils.isEmpty(mCallerAppName)) {
|
||||||
|
FooterPreferenceMixinCompat footerMixin =
|
||||||
|
new FooterPreferenceMixinCompat(this, getSettingsLifecycle());
|
||||||
|
FooterPreference footer = footerMixin.createFooterPreference();
|
||||||
|
footer.setTitle(getFooterString());
|
||||||
|
}
|
||||||
|
|
||||||
// Used for testing purposes
|
// Used for testing purposes
|
||||||
findPreference(ScreenLockType.NONE.preferenceKey).setViewId(R.id.lock_none);
|
findPreference(ScreenLockType.NONE.preferenceKey).setViewId(R.id.lock_none);
|
||||||
findPreference(KEY_SKIP_FINGERPRINT).setViewId(R.id.lock_none);
|
findPreference(KEY_SKIP_FINGERPRINT).setViewId(R.id.lock_none);
|
||||||
@@ -469,6 +501,27 @@ public class ChooseLockGeneric extends SettingsActivity {
|
|||||||
findPreference(ScreenLockType.PASSWORD.preferenceKey).setViewId(R.id.lock_password);
|
findPreference(ScreenLockType.PASSWORD.preferenceKey).setViewId(R.id.lock_password);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String getFooterString() {
|
||||||
|
@StringRes int stringId;
|
||||||
|
switch (mRequestedMinComplexity) {
|
||||||
|
case PASSWORD_COMPLEXITY_HIGH:
|
||||||
|
stringId = R.string.unlock_footer_high_complexity_requested;
|
||||||
|
break;
|
||||||
|
case PASSWORD_COMPLEXITY_MEDIUM:
|
||||||
|
stringId = R.string.unlock_footer_medium_complexity_requested;
|
||||||
|
break;
|
||||||
|
case PASSWORD_COMPLEXITY_LOW:
|
||||||
|
stringId = R.string.unlock_footer_low_complexity_requested;
|
||||||
|
break;
|
||||||
|
case PASSWORD_COMPLEXITY_NONE:
|
||||||
|
default:
|
||||||
|
stringId = R.string.unlock_footer_none_complexity_requested;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return getResources().getString(stringId, mCallerAppName);
|
||||||
|
}
|
||||||
|
|
||||||
private void updatePreferenceText() {
|
private void updatePreferenceText() {
|
||||||
if (mForFingerprint) {
|
if (mForFingerprint) {
|
||||||
setPreferenceTitle(ScreenLockType.PATTERN,
|
setPreferenceTitle(ScreenLockType.PATTERN,
|
||||||
@@ -624,6 +677,7 @@ public class ChooseLockGeneric extends SettingsActivity {
|
|||||||
ChooseLockPassword.IntentBuilder builder =
|
ChooseLockPassword.IntentBuilder builder =
|
||||||
new ChooseLockPassword.IntentBuilder(getContext())
|
new ChooseLockPassword.IntentBuilder(getContext())
|
||||||
.setPasswordQuality(quality)
|
.setPasswordQuality(quality)
|
||||||
|
.setRequestedMinComplexity(mRequestedMinComplexity)
|
||||||
.setForFingerprint(mForFingerprint)
|
.setForFingerprint(mForFingerprint)
|
||||||
.setForFace(mForFace)
|
.setForFace(mForFace)
|
||||||
.setUserId(mUserId);
|
.setUserId(mUserId);
|
||||||
|
@@ -16,7 +16,11 @@
|
|||||||
|
|
||||||
package com.android.settings.password;
|
package com.android.settings.password;
|
||||||
|
|
||||||
|
import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_NONE;
|
||||||
|
|
||||||
import android.app.admin.DevicePolicyManager;
|
import android.app.admin.DevicePolicyManager;
|
||||||
|
import android.app.admin.DevicePolicyManager.PasswordComplexity;
|
||||||
|
import android.app.admin.PasswordMetrics;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.os.UserHandle;
|
import android.os.UserHandle;
|
||||||
|
|
||||||
@@ -36,6 +40,7 @@ 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 ManagedLockPasswordProvider mManagedPasswordProvider;
|
private ManagedLockPasswordProvider mManagedPasswordProvider;
|
||||||
private DevicePolicyManager mDpm;
|
private DevicePolicyManager mDpm;
|
||||||
|
|
||||||
@@ -43,6 +48,19 @@ public class ChooseLockGenericController {
|
|||||||
this(
|
this(
|
||||||
context,
|
context,
|
||||||
userId,
|
userId,
|
||||||
|
PASSWORD_COMPLEXITY_NONE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param requestedMinComplexity specifies the min password complexity to be taken into account
|
||||||
|
* when determining the available screen lock types
|
||||||
|
*/
|
||||||
|
public ChooseLockGenericController(Context context, int userId,
|
||||||
|
@PasswordComplexity int requestedMinComplexity) {
|
||||||
|
this(
|
||||||
|
context,
|
||||||
|
userId,
|
||||||
|
requestedMinComplexity,
|
||||||
context.getSystemService(DevicePolicyManager.class),
|
context.getSystemService(DevicePolicyManager.class),
|
||||||
ManagedLockPasswordProvider.get(context, userId));
|
ManagedLockPasswordProvider.get(context, userId));
|
||||||
}
|
}
|
||||||
@@ -51,21 +69,26 @@ public class ChooseLockGenericController {
|
|||||||
ChooseLockGenericController(
|
ChooseLockGenericController(
|
||||||
Context context,
|
Context context,
|
||||||
int userId,
|
int userId,
|
||||||
|
@PasswordComplexity int requestedMinComplexity,
|
||||||
DevicePolicyManager dpm,
|
DevicePolicyManager dpm,
|
||||||
ManagedLockPasswordProvider managedLockPasswordProvider) {
|
ManagedLockPasswordProvider managedLockPasswordProvider) {
|
||||||
mContext = context;
|
mContext = context;
|
||||||
mUserId = userId;
|
mUserId = userId;
|
||||||
|
mRequestedMinComplexity = requestedMinComplexity;
|
||||||
mManagedPasswordProvider = managedLockPasswordProvider;
|
mManagedPasswordProvider = managedLockPasswordProvider;
|
||||||
mDpm = dpm;
|
mDpm = dpm;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return The higher quality of either the specified {@code quality} or the quality required
|
* Returns the highest quality among the specified {@code quality}, the quality required by
|
||||||
* by {@link DevicePolicyManager#getPasswordQuality}.
|
* {@link DevicePolicyManager#getPasswordQuality}, and the quality required by min password
|
||||||
|
* complexity.
|
||||||
*/
|
*/
|
||||||
public int upgradeQuality(int quality) {
|
public int upgradeQuality(int quality) {
|
||||||
// Compare min allowed password quality
|
// Compare specified quality and dpm quality
|
||||||
return Math.max(quality, mDpm.getPasswordQuality(null, mUserId));
|
int dpmUpgradedQuality = Math.max(quality, mDpm.getPasswordQuality(null, mUserId));
|
||||||
|
return Math.max(dpmUpgradedQuality,
|
||||||
|
PasswordMetrics.complexityLevelToMinQuality(mRequestedMinComplexity));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -16,14 +16,18 @@
|
|||||||
|
|
||||||
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_QUALITY_ALPHABETIC;
|
import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC;
|
||||||
import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC;
|
import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC;
|
||||||
import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_COMPLEX;
|
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;
|
||||||
import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX;
|
import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX;
|
||||||
|
|
||||||
|
import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_REQUESTED_MIN_COMPLEXITY;
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.app.admin.DevicePolicyManager;
|
import android.app.admin.DevicePolicyManager;
|
||||||
|
import android.app.admin.DevicePolicyManager.PasswordComplexity;
|
||||||
import android.app.admin.PasswordMetrics;
|
import android.app.admin.PasswordMetrics;
|
||||||
import android.app.settings.SettingsEnums;
|
import android.app.settings.SettingsEnums;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
@@ -56,6 +60,7 @@ import androidx.fragment.app.Fragment;
|
|||||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
|
import com.android.internal.annotations.VisibleForTesting;
|
||||||
import com.android.internal.widget.LockPatternUtils;
|
import com.android.internal.widget.LockPatternUtils;
|
||||||
import com.android.internal.widget.LockPatternUtils.RequestThrottledException;
|
import com.android.internal.widget.LockPatternUtils.RequestThrottledException;
|
||||||
import com.android.internal.widget.TextViewInputDisabler;
|
import com.android.internal.widget.TextViewInputDisabler;
|
||||||
@@ -133,6 +138,11 @@ public class ChooseLockPassword extends SettingsActivity {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public IntentBuilder setRequestedMinComplexity(@PasswordComplexity int level) {
|
||||||
|
mIntent.putExtra(EXTRA_KEY_REQUESTED_MIN_COMPLEXITY, level);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
public Intent build() {
|
public Intent build() {
|
||||||
return mIntent;
|
return mIntent;
|
||||||
}
|
}
|
||||||
@@ -190,12 +200,10 @@ public class ChooseLockPassword extends SettingsActivity {
|
|||||||
private int mPasswordMinNumeric = 0;
|
private int mPasswordMinNumeric = 0;
|
||||||
private int mPasswordMinNonLetter = 0;
|
private int mPasswordMinNonLetter = 0;
|
||||||
private int mPasswordMinLengthToFulfillAllPolicies = 0;
|
private int mPasswordMinLengthToFulfillAllPolicies = 0;
|
||||||
|
private boolean mPasswordNumSequenceAllowed = true;
|
||||||
|
@PasswordComplexity private int mRequestedMinComplexity = PASSWORD_COMPLEXITY_NONE;
|
||||||
protected int mUserId;
|
protected int mUserId;
|
||||||
private byte[] mPasswordHistoryHashFactor;
|
private byte[] mPasswordHistoryHashFactor;
|
||||||
/**
|
|
||||||
* Password requirements that we need to verify.
|
|
||||||
*/
|
|
||||||
private int[] mPasswordRequirements;
|
|
||||||
|
|
||||||
private LockPatternUtils mLockPatternUtils;
|
private LockPatternUtils mLockPatternUtils;
|
||||||
private SaveAndFinishWorker mSaveAndFinishWorker;
|
private SaveAndFinishWorker mSaveAndFinishWorker;
|
||||||
@@ -372,7 +380,13 @@ public class ChooseLockPassword extends SettingsActivity {
|
|||||||
mForFingerprint = intent.getBooleanExtra(
|
mForFingerprint = intent.getBooleanExtra(
|
||||||
ChooseLockSettingsHelper.EXTRA_KEY_FOR_FINGERPRINT, false);
|
ChooseLockSettingsHelper.EXTRA_KEY_FOR_FINGERPRINT, false);
|
||||||
mForFace = intent.getBooleanExtra(ChooseLockSettingsHelper.EXTRA_KEY_FOR_FACE, false);
|
mForFace = intent.getBooleanExtra(ChooseLockSettingsHelper.EXTRA_KEY_FOR_FACE, false);
|
||||||
processPasswordRequirements(intent);
|
mRequestedMinComplexity = intent.getIntExtra(
|
||||||
|
EXTRA_KEY_REQUESTED_MIN_COMPLEXITY, PASSWORD_COMPLEXITY_NONE);
|
||||||
|
mRequestedQuality = Math.max(
|
||||||
|
intent.getIntExtra(LockPatternUtils.PASSWORD_TYPE_KEY, mRequestedQuality),
|
||||||
|
mLockPatternUtils.getRequestedPasswordQuality(mUserId));
|
||||||
|
|
||||||
|
loadDpmPasswordRequirements();
|
||||||
mChooseLockSettingsHelper = new ChooseLockSettingsHelper(getActivity());
|
mChooseLockSettingsHelper = new ChooseLockSettingsHelper(getActivity());
|
||||||
|
|
||||||
if (intent.getBooleanExtra(
|
if (intent.getBooleanExtra(
|
||||||
@@ -504,31 +518,6 @@ public class ChooseLockPassword extends SettingsActivity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void setupPasswordRequirementsView(View view) {
|
private void setupPasswordRequirementsView(View view) {
|
||||||
final List<Integer> passwordRequirements = new ArrayList<>();
|
|
||||||
if (mPasswordMinUpperCase > 0) {
|
|
||||||
passwordRequirements.add(MIN_UPPER_LETTERS_IN_PASSWORD);
|
|
||||||
}
|
|
||||||
if (mPasswordMinLowerCase > 0) {
|
|
||||||
passwordRequirements.add(MIN_LOWER_LETTERS_IN_PASSWORD);
|
|
||||||
}
|
|
||||||
if (mPasswordMinLetters > 0) {
|
|
||||||
if (mPasswordMinLetters > mPasswordMinUpperCase + mPasswordMinLowerCase) {
|
|
||||||
passwordRequirements.add(MIN_LETTER_IN_PASSWORD);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (mPasswordMinNumeric > 0) {
|
|
||||||
passwordRequirements.add(MIN_NUMBER_IN_PASSWORD);
|
|
||||||
}
|
|
||||||
if (mPasswordMinSymbols > 0) {
|
|
||||||
passwordRequirements.add(MIN_SYMBOLS_IN_PASSWORD);
|
|
||||||
}
|
|
||||||
if (mPasswordMinNonLetter > 0) {
|
|
||||||
if (mPasswordMinNonLetter > mPasswordMinNumeric + mPasswordMinSymbols) {
|
|
||||||
passwordRequirements.add(MIN_NON_LETTER_IN_PASSWORD);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Convert list to array.
|
|
||||||
mPasswordRequirements = passwordRequirements.stream().mapToInt(i -> i).toArray();
|
|
||||||
mPasswordRestrictionView = view.findViewById(R.id.password_requirements_view);
|
mPasswordRestrictionView = view.findViewById(R.id.password_requirements_view);
|
||||||
mPasswordRestrictionView.setLayoutManager(new LinearLayoutManager(getActivity()));
|
mPasswordRestrictionView.setLayoutManager(new LinearLayoutManager(getActivity()));
|
||||||
mPasswordRequirementAdapter = new PasswordRequirementAdapter();
|
mPasswordRequirementAdapter = new PasswordRequirementAdapter();
|
||||||
@@ -603,13 +592,12 @@ public class ChooseLockPassword extends SettingsActivity {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Read the requirements from {@link DevicePolicyManager} and intent and aggregate them.
|
* Read the requirements from {@link DevicePolicyManager} and intent and aggregate them.
|
||||||
*
|
|
||||||
* @param intent the incoming intent
|
|
||||||
*/
|
*/
|
||||||
private void processPasswordRequirements(Intent intent) {
|
private void loadDpmPasswordRequirements() {
|
||||||
final int dpmPasswordQuality = mLockPatternUtils.getRequestedPasswordQuality(mUserId);
|
final int dpmPasswordQuality = mLockPatternUtils.getRequestedPasswordQuality(mUserId);
|
||||||
mRequestedQuality = Math.max(intent.getIntExtra(LockPatternUtils.PASSWORD_TYPE_KEY,
|
if (dpmPasswordQuality == PASSWORD_QUALITY_NUMERIC_COMPLEX) {
|
||||||
mRequestedQuality), dpmPasswordQuality);
|
mPasswordNumSequenceAllowed = false;
|
||||||
|
}
|
||||||
mPasswordMinLength = Math.max(LockPatternUtils.MIN_LOCK_PASSWORD_SIZE,
|
mPasswordMinLength = Math.max(LockPatternUtils.MIN_LOCK_PASSWORD_SIZE,
|
||||||
mLockPatternUtils.getRequestedMinimumPasswordLength(mUserId));
|
mLockPatternUtils.getRequestedMinimumPasswordLength(mUserId));
|
||||||
mPasswordMaxLength = mLockPatternUtils.getMaximumPasswordLength(mRequestedQuality);
|
mPasswordMaxLength = mLockPatternUtils.getMaximumPasswordLength(mRequestedQuality);
|
||||||
@@ -620,7 +608,7 @@ public class ChooseLockPassword extends SettingsActivity {
|
|||||||
mPasswordMinSymbols = mLockPatternUtils.getRequestedPasswordMinimumSymbols(mUserId);
|
mPasswordMinSymbols = mLockPatternUtils.getRequestedPasswordMinimumSymbols(mUserId);
|
||||||
mPasswordMinNonLetter = mLockPatternUtils.getRequestedPasswordMinimumNonLetter(mUserId);
|
mPasswordMinNonLetter = mLockPatternUtils.getRequestedPasswordMinimumNonLetter(mUserId);
|
||||||
|
|
||||||
// Modify the value based on dpm policy.
|
// Modify the value based on dpm policy
|
||||||
switch (dpmPasswordQuality) {
|
switch (dpmPasswordQuality) {
|
||||||
case PASSWORD_QUALITY_ALPHABETIC:
|
case PASSWORD_QUALITY_ALPHABETIC:
|
||||||
if (mPasswordMinLetters == 0) {
|
if (mPasswordMinLetters == 0) {
|
||||||
@@ -646,19 +634,88 @@ public class ChooseLockPassword extends SettingsActivity {
|
|||||||
mPasswordMinSymbols = 0;
|
mPasswordMinSymbols = 0;
|
||||||
mPasswordMinNonLetter = 0;
|
mPasswordMinNonLetter = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
mPasswordMinLengthToFulfillAllPolicies = getMinLengthToFulfillAllPolicies();
|
mPasswordMinLengthToFulfillAllPolicies = getMinLengthToFulfillAllPolicies();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Merges the dpm requirements and the min complexity requirements.
|
||||||
|
*
|
||||||
|
* <p>Since there are more than one set of metrics to meet the min complexity requirement,
|
||||||
|
* and we are not hard-coding any one of them to be the requirements the user must fulfil,
|
||||||
|
* we are taking what the user has already entered into account when compiling the list of
|
||||||
|
* requirements from min complexity. Then we merge this list with the DPM requirements, and
|
||||||
|
* present the merged set as validation results to the user on the UI.
|
||||||
|
*
|
||||||
|
* <p>For example, suppose min complexity requires either ALPHABETIC(8+), or
|
||||||
|
* ALPHANUMERIC(6+). If the user has entered "a", the length requirement displayed on the UI
|
||||||
|
* would be 8. Then the user appends "1" to make it "a1". We now know the user is entering
|
||||||
|
* an alphanumeric password so we would update the min complexity required min length to 6.
|
||||||
|
* This might result in a little confusion for the user but the UI does not support showing
|
||||||
|
* multiple sets of requirements / validation results as options to users, this is the best
|
||||||
|
* we can do now.
|
||||||
|
*/
|
||||||
|
private void mergeMinComplexityAndDpmRequirements(int userEnteredPasswordQuality) {
|
||||||
|
if (mRequestedMinComplexity == PASSWORD_COMPLEXITY_NONE) {
|
||||||
|
// dpm requirements are dominant if min complexity is none
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// reset dpm requirements
|
||||||
|
loadDpmPasswordRequirements();
|
||||||
|
|
||||||
|
PasswordMetrics minMetrics = PasswordMetrics.getMinimumMetrics(
|
||||||
|
mRequestedMinComplexity, userEnteredPasswordQuality, mRequestedQuality,
|
||||||
|
requiresNumeric(), requiresLettersOrSymbols());
|
||||||
|
mPasswordNumSequenceAllowed = mPasswordNumSequenceAllowed
|
||||||
|
&& minMetrics.quality != PASSWORD_QUALITY_NUMERIC_COMPLEX;
|
||||||
|
mPasswordMinLength = Math.max(mPasswordMinLength, minMetrics.length);
|
||||||
|
mPasswordMinLetters = Math.max(mPasswordMinLetters, minMetrics.letters);
|
||||||
|
mPasswordMinUpperCase = Math.max(mPasswordMinUpperCase, minMetrics.upperCase);
|
||||||
|
mPasswordMinLowerCase = Math.max(mPasswordMinLowerCase, minMetrics.lowerCase);
|
||||||
|
mPasswordMinNumeric = Math.max(mPasswordMinNumeric, minMetrics.numeric);
|
||||||
|
mPasswordMinSymbols = Math.max(mPasswordMinSymbols, minMetrics.symbols);
|
||||||
|
mPasswordMinNonLetter = Math.max(mPasswordMinNonLetter, minMetrics.nonLetter);
|
||||||
|
|
||||||
|
if (minMetrics.quality == PASSWORD_QUALITY_ALPHABETIC) {
|
||||||
|
if (!requiresLettersOrSymbols()) {
|
||||||
|
mPasswordMinLetters = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (minMetrics.quality == PASSWORD_QUALITY_ALPHANUMERIC) {
|
||||||
|
if (!requiresLettersOrSymbols()) {
|
||||||
|
mPasswordMinLetters = 1;
|
||||||
|
}
|
||||||
|
if (!requiresNumeric()) {
|
||||||
|
mPasswordMinNumeric = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mPasswordMinLengthToFulfillAllPolicies = getMinLengthToFulfillAllPolicies();
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean requiresLettersOrSymbols() {
|
||||||
|
// This is the condition for the password to be considered ALPHABETIC according to
|
||||||
|
// PasswordMetrics.computeForPassword()
|
||||||
|
return mPasswordMinLetters + mPasswordMinUpperCase
|
||||||
|
+ mPasswordMinLowerCase + mPasswordMinSymbols + mPasswordMinNonLetter > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean requiresNumeric() {
|
||||||
|
return mPasswordMinNumeric > 0;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Validates PIN/Password and returns the validation result.
|
* Validates PIN/Password and returns the validation result.
|
||||||
*
|
*
|
||||||
* @param password the raw password the user typed in
|
* @param password the raw password the user typed in
|
||||||
* @return the validation result.
|
* @return the validation result.
|
||||||
*/
|
*/
|
||||||
private int validatePassword(String password) {
|
@VisibleForTesting
|
||||||
|
int validatePassword(String password) {
|
||||||
int errorCode = NO_ERROR;
|
int errorCode = NO_ERROR;
|
||||||
final PasswordMetrics metrics = PasswordMetrics.computeForPassword(password);
|
final PasswordMetrics metrics = PasswordMetrics.computeForPassword(password);
|
||||||
|
mergeMinComplexityAndDpmRequirements(metrics.quality);
|
||||||
|
|
||||||
if (password.length() < mPasswordMinLength) {
|
if (password.length() < mPasswordMinLength) {
|
||||||
if (mPasswordMinLength > mPasswordMinLengthToFulfillAllPolicies) {
|
if (mPasswordMinLength > mPasswordMinLengthToFulfillAllPolicies) {
|
||||||
@@ -668,14 +725,25 @@ public class ChooseLockPassword extends SettingsActivity {
|
|||||||
errorCode |= TOO_LONG;
|
errorCode |= TOO_LONG;
|
||||||
} else {
|
} else {
|
||||||
// The length requirements are fulfilled.
|
// The length requirements are fulfilled.
|
||||||
final int dpmQuality = mLockPatternUtils.getRequestedPasswordQuality(mUserId);
|
if (!mPasswordNumSequenceAllowed
|
||||||
if (dpmQuality == PASSWORD_QUALITY_NUMERIC_COMPLEX &&
|
&& !requiresLettersOrSymbols()
|
||||||
metrics.numeric == password.length()) {
|
&& metrics.numeric == password.length()) {
|
||||||
// Check for repeated characters or sequences (e.g. '1234', '0000', '2468')
|
// Check for repeated characters or sequences (e.g. '1234', '0000', '2468')
|
||||||
// if DevicePolicyManager requires a complex numeric password. There can be
|
// if DevicePolicyManager or min password complexity requires a complex numeric
|
||||||
// two cases in the UI: 1. User chooses to enroll a PIN, 2. User chooses to
|
// password. There can be two cases in the UI: 1. User chooses to enroll a
|
||||||
// enroll a password but enters a numeric-only pin. We should carry out the
|
// PIN, 2. User chooses to enroll a password but enters a numeric-only pin. We
|
||||||
// sequence check in both cases.
|
// should carry out the sequence check in both cases.
|
||||||
|
//
|
||||||
|
// Conditions for the !requiresLettersOrSymbols() to be necessary:
|
||||||
|
// - DPM requires NUMERIC_COMPLEX
|
||||||
|
// - min complexity not NONE, user picks PASSWORD type so ALPHABETIC or
|
||||||
|
// ALPHANUMERIC is required
|
||||||
|
// Imagine user has entered "12345678", if we don't skip the sequence check, the
|
||||||
|
// validation result would show both "requires a letter" and "sequence not
|
||||||
|
// allowed", while the only requirement the user needs to know is "requires a
|
||||||
|
// letter" because once the user has fulfilled the alphabetic requirement, the
|
||||||
|
// password would not be containing only digits so this check would not be
|
||||||
|
// performed anyway.
|
||||||
final int sequence = PasswordMetrics.maxLengthSequence(password);
|
final int sequence = PasswordMetrics.maxLengthSequence(password);
|
||||||
if (sequence > PasswordMetrics.MAX_ALLOWED_SEQUENCE) {
|
if (sequence > PasswordMetrics.MAX_ALLOWED_SEQUENCE) {
|
||||||
errorCode |= CONTAIN_SEQUENTIAL_DIGITS;
|
errorCode |= CONTAIN_SEQUENTIAL_DIGITS;
|
||||||
@@ -706,43 +774,24 @@ public class ChooseLockPassword extends SettingsActivity {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check the requirements one by one.
|
if (metrics.letters < mPasswordMinLetters) {
|
||||||
for (int i = 0; i < mPasswordRequirements.length; i++) {
|
errorCode |= NOT_ENOUGH_LETTER;
|
||||||
int passwordRestriction = mPasswordRequirements[i];
|
}
|
||||||
switch (passwordRestriction) {
|
if (metrics.upperCase < mPasswordMinUpperCase) {
|
||||||
case MIN_LETTER_IN_PASSWORD:
|
errorCode |= NOT_ENOUGH_UPPER_CASE;
|
||||||
if (metrics.letters < mPasswordMinLetters) {
|
}
|
||||||
errorCode |= NOT_ENOUGH_LETTER;
|
if (metrics.lowerCase < mPasswordMinLowerCase) {
|
||||||
}
|
errorCode |= NOT_ENOUGH_LOWER_CASE;
|
||||||
break;
|
}
|
||||||
case MIN_UPPER_LETTERS_IN_PASSWORD:
|
if (metrics.symbols < mPasswordMinSymbols) {
|
||||||
if (metrics.upperCase < mPasswordMinUpperCase) {
|
errorCode |= NOT_ENOUGH_SYMBOLS;
|
||||||
errorCode |= NOT_ENOUGH_UPPER_CASE;
|
}
|
||||||
}
|
if (metrics.numeric < mPasswordMinNumeric) {
|
||||||
break;
|
errorCode |= NOT_ENOUGH_DIGITS;
|
||||||
case MIN_LOWER_LETTERS_IN_PASSWORD:
|
}
|
||||||
if (metrics.lowerCase < mPasswordMinLowerCase) {
|
if (metrics.nonLetter < mPasswordMinNonLetter) {
|
||||||
errorCode |= NOT_ENOUGH_LOWER_CASE;
|
errorCode |= NOT_ENOUGH_NON_LETTER;
|
||||||
}
|
|
||||||
break;
|
|
||||||
case MIN_SYMBOLS_IN_PASSWORD:
|
|
||||||
if (metrics.symbols < mPasswordMinSymbols) {
|
|
||||||
errorCode |= NOT_ENOUGH_SYMBOLS;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case MIN_NUMBER_IN_PASSWORD:
|
|
||||||
if (metrics.numeric < mPasswordMinNumeric) {
|
|
||||||
errorCode |= NOT_ENOUGH_DIGITS;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case MIN_NON_LETTER_IN_PASSWORD:
|
|
||||||
if (metrics.nonLetter < mPasswordMinNonLetter) {
|
|
||||||
errorCode |= NOT_ENOUGH_NON_LETTER;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return errorCode;
|
return errorCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -45,6 +45,18 @@ public final class ChooseLockSettingsHelper {
|
|||||||
public static final String EXTRA_KEY_FOR_FACE = "for_face";
|
public static final String EXTRA_KEY_FOR_FACE = "for_face";
|
||||||
public static final String EXTRA_KEY_FOR_CHANGE_CRED_REQUIRED_FOR_BOOT = "for_cred_req_boot";
|
public static final String EXTRA_KEY_FOR_CHANGE_CRED_REQUIRED_FOR_BOOT = "for_cred_req_boot";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Intent extra for passing the requested min password complexity to later steps in the set new
|
||||||
|
* screen lock flow.
|
||||||
|
*/
|
||||||
|
public static final String EXTRA_KEY_REQUESTED_MIN_COMPLEXITY = "requested_min_complexity";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Intent extra for passing the label of the calling app to later steps in the set new screen
|
||||||
|
* lock flow.
|
||||||
|
*/
|
||||||
|
public static final String EXTRA_KEY_CALLER_APP_NAME = "caller_app_name";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* When invoked via {@link ConfirmLockPassword.InternalActivity}, this flag
|
* When invoked via {@link ConfirmLockPassword.InternalActivity}, this flag
|
||||||
* controls if we relax the enforcement of
|
* controls if we relax the enforcement of
|
||||||
|
97
src/com/android/settings/password/PasswordUtils.java
Normal file
97
src/com/android/settings/password/PasswordUtils.java
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2019 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.android.settings.password;
|
||||||
|
|
||||||
|
import android.annotation.Nullable;
|
||||||
|
import android.app.ActivityManager;
|
||||||
|
import android.app.IActivityManager;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
|
import android.os.IBinder;
|
||||||
|
import android.os.RemoteException;
|
||||||
|
import android.os.UserHandle;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import com.android.settings.Utils;
|
||||||
|
|
||||||
|
public final class PasswordUtils extends com.android.settingslib.Utils {
|
||||||
|
|
||||||
|
private static final String TAG = "Settings";
|
||||||
|
|
||||||
|
private static final String SETTINGS_PACKAGE_NAME = "com.android.settings";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether the uid which the activity with {@code activityToken} is launched from has
|
||||||
|
* been granted the {@code permission}.
|
||||||
|
*/
|
||||||
|
public static boolean isCallingAppPermitted(Context context, IBinder activityToken,
|
||||||
|
String permission) {
|
||||||
|
try {
|
||||||
|
return context.checkPermission(permission, /* pid= */ -1,
|
||||||
|
ActivityManager.getService().getLaunchedFromUid(activityToken))
|
||||||
|
== PackageManager.PERMISSION_GRANTED;
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
Log.v(TAG, "Could not talk to activity manager.", e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the label of the package which the activity with {@code activityToken} is launched
|
||||||
|
* from or {@code null} if it is launched from the settings app itself.
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
public static CharSequence getCallingAppLabel(Context context, IBinder activityToken) {
|
||||||
|
String pkg = getCallingAppPackageName(activityToken);
|
||||||
|
if (pkg == null || pkg.equals(SETTINGS_PACKAGE_NAME)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Utils.getApplicationLabel(context, pkg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the package name which the activity with {@code activityToken} is launched from.
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
private static String getCallingAppPackageName(IBinder activityToken) {
|
||||||
|
String pkg = null;
|
||||||
|
try {
|
||||||
|
pkg = ActivityManager.getService().getLaunchedFromPackage(activityToken);
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
Log.v(TAG, "Could not talk to activity manager.", e);
|
||||||
|
}
|
||||||
|
return pkg;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Crashes the calling application and provides it with {@code message}. */
|
||||||
|
public static void crashCallingApplication(IBinder activityToken, String message) {
|
||||||
|
IActivityManager am = ActivityManager.getService();
|
||||||
|
try {
|
||||||
|
int uid = am.getLaunchedFromUid(activityToken);
|
||||||
|
int userId = UserHandle.getUserId(uid);
|
||||||
|
am.crashApplication(
|
||||||
|
uid,
|
||||||
|
/* initialPid= */ -1,
|
||||||
|
getCallingAppPackageName(activityToken),
|
||||||
|
userId,
|
||||||
|
message);
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
Log.v(TAG, "Could not talk to activity manager.", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -16,13 +16,22 @@
|
|||||||
|
|
||||||
package com.android.settings.password;
|
package com.android.settings.password;
|
||||||
|
|
||||||
|
import static android.Manifest.permission.GET_AND_REQUEST_SCREEN_LOCK_COMPLEXITY;
|
||||||
import static android.app.admin.DevicePolicyManager.ACTION_SET_NEW_PARENT_PROFILE_PASSWORD;
|
import static android.app.admin.DevicePolicyManager.ACTION_SET_NEW_PARENT_PROFILE_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.EXTRA_PASSWORD_COMPLEXITY;
|
||||||
|
import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_NONE;
|
||||||
|
|
||||||
|
import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_CALLER_APP_NAME;
|
||||||
|
import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_REQUESTED_MIN_COMPLEXITY;
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.app.admin.DevicePolicyManager;
|
import android.app.admin.DevicePolicyManager;
|
||||||
|
import android.app.admin.DevicePolicyManager.PasswordComplexity;
|
||||||
|
import android.app.admin.PasswordMetrics;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.os.IBinder;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import com.android.settings.Utils;
|
import com.android.settings.Utils;
|
||||||
@@ -37,6 +46,21 @@ public class SetNewPasswordActivity extends Activity implements SetNewPasswordCo
|
|||||||
private String mNewPasswordAction;
|
private String mNewPasswordAction;
|
||||||
private SetNewPasswordController mSetNewPasswordController;
|
private SetNewPasswordController mSetNewPasswordController;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* From intent extra {@link DevicePolicyManager#EXTRA_PASSWORD_COMPLEXITY}.
|
||||||
|
*
|
||||||
|
* <p>This is used only if caller has the required permission and activity is launched by
|
||||||
|
* {@link DevicePolicyManager#ACTION_SET_NEW_PASSWORD}.
|
||||||
|
*/
|
||||||
|
private @PasswordComplexity int mRequestedMinComplexity = PASSWORD_COMPLEXITY_NONE;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Label of the app which launches this activity.
|
||||||
|
*
|
||||||
|
* <p>Value would be {@code null} if launched from settings app.
|
||||||
|
*/
|
||||||
|
private String mCallerAppName = null;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedState) {
|
protected void onCreate(Bundle savedState) {
|
||||||
super.onCreate(savedState);
|
super.onCreate(savedState);
|
||||||
@@ -48,6 +72,25 @@ public class SetNewPasswordActivity extends Activity implements SetNewPasswordCo
|
|||||||
finish();
|
finish();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
IBinder activityToken = getActivityToken();
|
||||||
|
mCallerAppName = (String) PasswordUtils.getCallingAppLabel(this, activityToken);
|
||||||
|
if (ACTION_SET_NEW_PASSWORD.equals(mNewPasswordAction)
|
||||||
|
&& getIntent().hasExtra(EXTRA_PASSWORD_COMPLEXITY)) {
|
||||||
|
boolean hasPermission = PasswordUtils.isCallingAppPermitted(
|
||||||
|
this, activityToken, GET_AND_REQUEST_SCREEN_LOCK_COMPLEXITY);
|
||||||
|
if (hasPermission) {
|
||||||
|
mRequestedMinComplexity = PasswordMetrics.sanitizeComplexityLevel(getIntent()
|
||||||
|
.getIntExtra(EXTRA_PASSWORD_COMPLEXITY, PASSWORD_COMPLEXITY_NONE));
|
||||||
|
} else {
|
||||||
|
PasswordUtils.crashCallingApplication(activityToken,
|
||||||
|
"Must have permission " + GET_AND_REQUEST_SCREEN_LOCK_COMPLEXITY
|
||||||
|
+ " to use extra " + EXTRA_PASSWORD_COMPLEXITY);
|
||||||
|
finish();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
mSetNewPasswordController = SetNewPasswordController.create(
|
mSetNewPasswordController = SetNewPasswordController.create(
|
||||||
this, this, getIntent(), getActivityToken());
|
this, this, getIntent(), getActivityToken());
|
||||||
mSetNewPasswordController.dispatchSetNewPasswordIntent();
|
mSetNewPasswordController.dispatchSetNewPasswordIntent();
|
||||||
@@ -60,6 +103,12 @@ public class SetNewPasswordActivity extends Activity implements SetNewPasswordCo
|
|||||||
: new Intent(this, ChooseLockGeneric.class);
|
: new Intent(this, ChooseLockGeneric.class);
|
||||||
intent.setAction(mNewPasswordAction);
|
intent.setAction(mNewPasswordAction);
|
||||||
intent.putExtras(chooseLockFingerprintExtras);
|
intent.putExtras(chooseLockFingerprintExtras);
|
||||||
|
if (mCallerAppName != null) {
|
||||||
|
intent.putExtra(EXTRA_KEY_CALLER_APP_NAME, mCallerAppName);
|
||||||
|
}
|
||||||
|
if (mRequestedMinComplexity != PASSWORD_COMPLEXITY_NONE) {
|
||||||
|
intent.putExtra(EXTRA_KEY_REQUESTED_MIN_COMPLEXITY, mRequestedMinComplexity);
|
||||||
|
}
|
||||||
startActivity(intent);
|
startActivity(intent);
|
||||||
finish();
|
finish();
|
||||||
}
|
}
|
||||||
|
@@ -16,11 +16,17 @@
|
|||||||
|
|
||||||
package com.android.settings.password;
|
package com.android.settings.password;
|
||||||
|
|
||||||
|
import static android.Manifest.permission.GET_AND_REQUEST_SCREEN_LOCK_COMPLEXITY;
|
||||||
|
import static android.app.admin.DevicePolicyManager.EXTRA_PASSWORD_COMPLEXITY;
|
||||||
|
|
||||||
|
import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_REQUESTED_MIN_COMPLEXITY;
|
||||||
|
|
||||||
import android.app.admin.DevicePolicyManager;
|
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;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.os.IBinder;
|
||||||
import android.os.UserHandle;
|
import android.os.UserHandle;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
@@ -48,6 +54,7 @@ import com.google.android.setupdesign.GlifPreferenceLayout;
|
|||||||
* Other changes should be done to ChooseLockGeneric class instead and let this class inherit
|
* Other changes should be done to ChooseLockGeneric class instead and let this class inherit
|
||||||
* those changes.
|
* those changes.
|
||||||
*/
|
*/
|
||||||
|
// TODO(b/123225425): Restrict SetupChooseLockGeneric to be accessible by SUW only
|
||||||
public class SetupChooseLockGeneric extends ChooseLockGeneric {
|
public class SetupChooseLockGeneric extends ChooseLockGeneric {
|
||||||
|
|
||||||
private static final String KEY_UNLOCK_SET_DO_LATER = "unlock_set_do_later";
|
private static final String KEY_UNLOCK_SET_DO_LATER = "unlock_set_do_later";
|
||||||
@@ -71,6 +78,20 @@ public class SetupChooseLockGeneric extends ChooseLockGeneric {
|
|||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstance) {
|
protected void onCreate(Bundle savedInstance) {
|
||||||
super.onCreate(savedInstance);
|
super.onCreate(savedInstance);
|
||||||
|
|
||||||
|
if(getIntent().hasExtra(EXTRA_KEY_REQUESTED_MIN_COMPLEXITY)) {
|
||||||
|
IBinder activityToken = getActivityToken();
|
||||||
|
boolean hasPermission = PasswordUtils.isCallingAppPermitted(
|
||||||
|
this, activityToken, GET_AND_REQUEST_SCREEN_LOCK_COMPLEXITY);
|
||||||
|
if (!hasPermission) {
|
||||||
|
PasswordUtils.crashCallingApplication(activityToken,
|
||||||
|
"Must have permission " + GET_AND_REQUEST_SCREEN_LOCK_COMPLEXITY
|
||||||
|
+ " to use extra " + EXTRA_PASSWORD_COMPLEXITY);
|
||||||
|
finish();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
LinearLayout layout = (LinearLayout) findViewById(R.id.content_parent);
|
LinearLayout layout = (LinearLayout) findViewById(R.id.content_parent);
|
||||||
layout.setFitsSystemWindows(false);
|
layout.setFitsSystemWindows(false);
|
||||||
}
|
}
|
||||||
|
@@ -16,15 +16,22 @@
|
|||||||
|
|
||||||
package com.android.settings.password;
|
package com.android.settings.password;
|
||||||
|
|
||||||
|
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_MEDIUM;
|
||||||
|
import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_NONE;
|
||||||
|
|
||||||
import static com.google.common.truth.Truth.assertThat;
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
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.nullable;
|
import static org.mockito.ArgumentMatchers.nullable;
|
||||||
import static org.mockito.Mockito.doReturn;
|
import static org.mockito.Mockito.doReturn;
|
||||||
|
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.content.ComponentName;
|
import android.content.ComponentName;
|
||||||
|
|
||||||
import com.android.settings.R;
|
import com.android.settings.R;
|
||||||
@@ -58,11 +65,7 @@ public class ChooseLockGenericControllerTest {
|
|||||||
public void setUp() {
|
public void setUp() {
|
||||||
MockitoAnnotations.initMocks(this);
|
MockitoAnnotations.initMocks(this);
|
||||||
|
|
||||||
mController = new ChooseLockGenericController(
|
mController = createController(PASSWORD_COMPLEXITY_NONE);
|
||||||
application,
|
|
||||||
0 /* userId */,
|
|
||||||
mDevicePolicyManager,
|
|
||||||
mManagedLockPasswordProvider);
|
|
||||||
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);
|
||||||
}
|
}
|
||||||
@@ -225,4 +228,44 @@ public class ChooseLockGenericControllerTest {
|
|||||||
assertThat(upgradedQuality).named("upgradedQuality")
|
assertThat(upgradedQuality).named("upgradedQuality")
|
||||||
.isEqualTo(DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC);
|
.isEqualTo(DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void upgradeQuality_complexityHigh_minQualityNumericComplex() {
|
||||||
|
when(mDevicePolicyManager.getPasswordQuality(nullable(ComponentName.class), anyInt()))
|
||||||
|
.thenReturn(DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED);
|
||||||
|
ChooseLockGenericController controller = createController(PASSWORD_COMPLEXITY_HIGH);
|
||||||
|
|
||||||
|
assertThat(controller.upgradeQuality(DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED))
|
||||||
|
.isEqualTo(DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void upgradeQuality_complexityMedium_minQualityNumericComplex() {
|
||||||
|
when(mDevicePolicyManager.getPasswordQuality(nullable(ComponentName.class), anyInt()))
|
||||||
|
.thenReturn(DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED);
|
||||||
|
ChooseLockGenericController controller = createController(PASSWORD_COMPLEXITY_MEDIUM);
|
||||||
|
|
||||||
|
assertThat(controller.upgradeQuality(DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED))
|
||||||
|
.isEqualTo(DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void upgradeQuality_complexityLow_minQualitySomething() {
|
||||||
|
when(mDevicePolicyManager.getPasswordQuality(nullable(ComponentName.class), anyInt()))
|
||||||
|
.thenReturn(DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED);
|
||||||
|
ChooseLockGenericController controller = createController(PASSWORD_COMPLEXITY_LOW);
|
||||||
|
|
||||||
|
assertThat(controller.upgradeQuality(DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED))
|
||||||
|
.isEqualTo(DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ChooseLockGenericController createController(
|
||||||
|
@PasswordComplexity int minPasswordComplexity) {
|
||||||
|
return new ChooseLockGenericController(
|
||||||
|
application,
|
||||||
|
0 /* userId */,
|
||||||
|
minPasswordComplexity,
|
||||||
|
mDevicePolicyManager,
|
||||||
|
mManagedLockPasswordProvider);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -16,6 +16,15 @@
|
|||||||
|
|
||||||
package com.android.settings.password;
|
package com.android.settings.password;
|
||||||
|
|
||||||
|
import static android.app.admin.DevicePolicyManager.ACTION_SET_NEW_PASSWORD;
|
||||||
|
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_MEDIUM;
|
||||||
|
import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_NONE;
|
||||||
|
|
||||||
|
import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_CALLER_APP_NAME;
|
||||||
|
import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_REQUESTED_MIN_COMPLEXITY;
|
||||||
|
|
||||||
import static com.google.common.truth.Truth.assertThat;
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
import static org.robolectric.RuntimeEnvironment.application;
|
import static org.robolectric.RuntimeEnvironment.application;
|
||||||
@@ -27,8 +36,10 @@ import android.content.Intent;
|
|||||||
import android.provider.Settings.Global;
|
import android.provider.Settings.Global;
|
||||||
|
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.preference.Preference;
|
||||||
|
|
||||||
import com.android.internal.widget.LockPatternUtils;
|
import com.android.internal.widget.LockPatternUtils;
|
||||||
|
import com.android.settings.R;
|
||||||
import com.android.settings.biometrics.BiometricEnrollBase;
|
import com.android.settings.biometrics.BiometricEnrollBase;
|
||||||
import com.android.settings.password.ChooseLockGeneric.ChooseLockGenericFragment;
|
import com.android.settings.password.ChooseLockGeneric.ChooseLockGenericFragment;
|
||||||
import com.android.settings.search.SearchFeatureProvider;
|
import com.android.settings.search.SearchFeatureProvider;
|
||||||
@@ -36,6 +47,7 @@ import com.android.settings.testutils.shadow.ShadowLockPatternUtils;
|
|||||||
import com.android.settings.testutils.shadow.ShadowStorageManager;
|
import com.android.settings.testutils.shadow.ShadowStorageManager;
|
||||||
import com.android.settings.testutils.shadow.ShadowUserManager;
|
import com.android.settings.testutils.shadow.ShadowUserManager;
|
||||||
import com.android.settings.testutils.shadow.ShadowUtils;
|
import com.android.settings.testutils.shadow.ShadowUtils;
|
||||||
|
import com.android.settingslib.widget.FooterPreference;
|
||||||
|
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
@@ -112,6 +124,70 @@ public class ChooseLockGenericTest {
|
|||||||
assertThat(shadowOf(mActivity).getNextStartedActivity()).isNull();
|
assertThat(shadowOf(mActivity).getNextStartedActivity()).isNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void updatePreferencesOrFinish_footerPreferenceAddedHighComplexityText() {
|
||||||
|
ShadowStorageManager.setIsFileEncryptedNativeOrEmulated(false);
|
||||||
|
Intent intent = new Intent()
|
||||||
|
.putExtra(EXTRA_KEY_CALLER_APP_NAME, "app name")
|
||||||
|
.putExtra(EXTRA_KEY_REQUESTED_MIN_COMPLEXITY, PASSWORD_COMPLEXITY_HIGH);
|
||||||
|
initActivity(intent);
|
||||||
|
CharSequence expectedTitle =
|
||||||
|
mActivity.getString(R.string.unlock_footer_high_complexity_requested, "app name");
|
||||||
|
|
||||||
|
mFragment.updatePreferencesOrFinish(false /* isRecreatingActivity */);
|
||||||
|
FooterPreference footer = mFragment.findPreference(FooterPreference.KEY_FOOTER);
|
||||||
|
|
||||||
|
assertThat(footer.getTitle()).isEqualTo(expectedTitle);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void updatePreferencesOrFinish_footerPreferenceAddedMediumComplexityText() {
|
||||||
|
ShadowStorageManager.setIsFileEncryptedNativeOrEmulated(false);
|
||||||
|
Intent intent = new Intent()
|
||||||
|
.putExtra(EXTRA_KEY_CALLER_APP_NAME, "app name")
|
||||||
|
.putExtra(EXTRA_KEY_REQUESTED_MIN_COMPLEXITY, PASSWORD_COMPLEXITY_MEDIUM);
|
||||||
|
initActivity(intent);
|
||||||
|
CharSequence expectedTitle =
|
||||||
|
mActivity.getString(R.string.unlock_footer_medium_complexity_requested, "app name");
|
||||||
|
|
||||||
|
mFragment.updatePreferencesOrFinish(false /* isRecreatingActivity */);
|
||||||
|
FooterPreference footer = mFragment.findPreference(FooterPreference.KEY_FOOTER);
|
||||||
|
|
||||||
|
assertThat(footer.getTitle()).isEqualTo(expectedTitle);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void updatePreferencesOrFinish_footerPreferenceAddedLowComplexityText() {
|
||||||
|
ShadowStorageManager.setIsFileEncryptedNativeOrEmulated(false);
|
||||||
|
Intent intent = new Intent()
|
||||||
|
.putExtra(EXTRA_KEY_CALLER_APP_NAME, "app name")
|
||||||
|
.putExtra(EXTRA_KEY_REQUESTED_MIN_COMPLEXITY, PASSWORD_COMPLEXITY_LOW);
|
||||||
|
initActivity(intent);
|
||||||
|
CharSequence expectedTitle =
|
||||||
|
mActivity.getString(R.string.unlock_footer_low_complexity_requested, "app name");
|
||||||
|
|
||||||
|
mFragment.updatePreferencesOrFinish(false /* isRecreatingActivity */);
|
||||||
|
FooterPreference footer = mFragment.findPreference(FooterPreference.KEY_FOOTER);
|
||||||
|
|
||||||
|
assertThat(footer.getTitle()).isEqualTo(expectedTitle);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void updatePreferencesOrFinish_footerPreferenceAddedNoneComplexityText() {
|
||||||
|
ShadowStorageManager.setIsFileEncryptedNativeOrEmulated(false);
|
||||||
|
Intent intent = new Intent()
|
||||||
|
.putExtra(EXTRA_KEY_CALLER_APP_NAME, "app name")
|
||||||
|
.putExtra(EXTRA_KEY_REQUESTED_MIN_COMPLEXITY, PASSWORD_COMPLEXITY_NONE);
|
||||||
|
initActivity(intent);
|
||||||
|
CharSequence expectedTitle =
|
||||||
|
mActivity.getString(R.string.unlock_footer_none_complexity_requested, "app name");
|
||||||
|
|
||||||
|
mFragment.updatePreferencesOrFinish(false /* isRecreatingActivity */);
|
||||||
|
FooterPreference footer = mFragment.findPreference(FooterPreference.KEY_FOOTER);
|
||||||
|
|
||||||
|
assertThat(footer.getTitle()).isEqualTo(expectedTitle);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void onActivityResult_requestcode0_shouldNotFinish() {
|
public void onActivityResult_requestcode0_shouldNotFinish() {
|
||||||
initActivity(null);
|
initActivity(null);
|
||||||
@@ -165,6 +241,48 @@ public class ChooseLockGenericTest {
|
|||||||
assertThat(mActivity.isFinishing()).isTrue();
|
assertThat(mActivity.isFinishing()).isTrue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void onPreferenceTreeClick_fingerprintPassesMinComplexityInfoOntoNextActivity() {
|
||||||
|
Intent intent = new Intent(ACTION_SET_NEW_PASSWORD)
|
||||||
|
.putExtra(EXTRA_KEY_REQUESTED_MIN_COMPLEXITY, PASSWORD_COMPLEXITY_HIGH)
|
||||||
|
.putExtra(EXTRA_KEY_CALLER_APP_NAME, "app name");
|
||||||
|
initActivity(intent);
|
||||||
|
|
||||||
|
Preference fingerprintPref = new Preference(application);
|
||||||
|
fingerprintPref.setKey("unlock_skip_fingerprint");
|
||||||
|
boolean result = mFragment.onPreferenceTreeClick(fingerprintPref);
|
||||||
|
|
||||||
|
assertThat(result).isTrue();
|
||||||
|
Intent actualIntent = shadowOf(mActivity).getNextStartedActivityForResult().intent;
|
||||||
|
assertThat(actualIntent.hasExtra(EXTRA_KEY_REQUESTED_MIN_COMPLEXITY)).isTrue();
|
||||||
|
assertThat(actualIntent.getIntExtra(EXTRA_KEY_REQUESTED_MIN_COMPLEXITY, PASSWORD_COMPLEXITY_NONE))
|
||||||
|
.isEqualTo(PASSWORD_COMPLEXITY_HIGH);
|
||||||
|
assertThat(actualIntent.hasExtra(EXTRA_KEY_CALLER_APP_NAME)).isTrue();
|
||||||
|
assertThat(actualIntent.getStringExtra(EXTRA_KEY_CALLER_APP_NAME))
|
||||||
|
.isEqualTo("app name");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void onPreferenceTreeClick_facePassesMinComplexityInfoOntoNextActivity() {
|
||||||
|
Intent intent = new Intent(ACTION_SET_NEW_PASSWORD)
|
||||||
|
.putExtra(EXTRA_KEY_REQUESTED_MIN_COMPLEXITY, PASSWORD_COMPLEXITY_HIGH)
|
||||||
|
.putExtra(EXTRA_KEY_CALLER_APP_NAME, "app name");
|
||||||
|
initActivity(intent);
|
||||||
|
|
||||||
|
Preference facePref = new Preference(application);
|
||||||
|
facePref.setKey("unlock_skip_face");
|
||||||
|
boolean result = mFragment.onPreferenceTreeClick(facePref);
|
||||||
|
|
||||||
|
assertThat(result).isTrue();
|
||||||
|
Intent actualIntent = shadowOf(mActivity).getNextStartedActivityForResult().intent;
|
||||||
|
assertThat(actualIntent.hasExtra(EXTRA_KEY_REQUESTED_MIN_COMPLEXITY)).isTrue();
|
||||||
|
assertThat(actualIntent.getIntExtra(EXTRA_KEY_REQUESTED_MIN_COMPLEXITY, PASSWORD_COMPLEXITY_NONE))
|
||||||
|
.isEqualTo(PASSWORD_COMPLEXITY_HIGH);
|
||||||
|
assertThat(actualIntent.hasExtra(EXTRA_KEY_CALLER_APP_NAME)).isTrue();
|
||||||
|
assertThat(actualIntent.getStringExtra(EXTRA_KEY_CALLER_APP_NAME))
|
||||||
|
.isEqualTo("app name");
|
||||||
|
}
|
||||||
|
|
||||||
private void initActivity(@Nullable Intent intent) {
|
private void initActivity(@Nullable Intent intent) {
|
||||||
if (intent == null) {
|
if (intent == null) {
|
||||||
intent = new Intent();
|
intent = new Intent();
|
||||||
|
@@ -16,19 +16,37 @@
|
|||||||
|
|
||||||
package com.android.settings.password;
|
package com.android.settings.password;
|
||||||
|
|
||||||
|
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_MEDIUM;
|
||||||
|
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_ALPHANUMERIC;
|
||||||
|
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.android.internal.widget.LockPatternUtils.PASSWORD_TYPE_KEY;
|
||||||
|
import static com.android.settings.password.ChooseLockGeneric.CONFIRM_CREDENTIALS;
|
||||||
|
import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_REQUESTED_MIN_COMPLEXITY;
|
||||||
|
|
||||||
import static com.google.common.truth.Truth.assertThat;
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
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.content.Intent;
|
import android.content.Intent;
|
||||||
import android.os.UserHandle;
|
import android.os.UserHandle;
|
||||||
|
|
||||||
import com.android.internal.widget.LockPatternUtils;
|
|
||||||
import com.android.settings.R;
|
import com.android.settings.R;
|
||||||
import com.android.settings.password.ChooseLockPassword.ChooseLockPasswordFragment;
|
import com.android.settings.password.ChooseLockPassword.ChooseLockPasswordFragment;
|
||||||
import com.android.settings.password.ChooseLockPassword.IntentBuilder;
|
import com.android.settings.password.ChooseLockPassword.IntentBuilder;
|
||||||
import com.android.settings.testutils.shadow.SettingsShadowResources;
|
import com.android.settings.testutils.shadow.SettingsShadowResources;
|
||||||
|
import com.android.settings.testutils.shadow.ShadowDevicePolicyManager;
|
||||||
|
import com.android.settings.testutils.shadow.ShadowLockPatternUtils;
|
||||||
import com.android.settings.testutils.shadow.ShadowUtils;
|
import com.android.settings.testutils.shadow.ShadowUtils;
|
||||||
|
|
||||||
import com.google.android.setupdesign.GlifLayout;
|
import com.google.android.setupdesign.GlifLayout;
|
||||||
@@ -44,13 +62,21 @@ import org.robolectric.annotation.Config;
|
|||||||
import org.robolectric.shadows.ShadowDrawable;
|
import org.robolectric.shadows.ShadowDrawable;
|
||||||
|
|
||||||
@RunWith(RobolectricTestRunner.class)
|
@RunWith(RobolectricTestRunner.class)
|
||||||
@Config(shadows = {SettingsShadowResources.class, ShadowUtils.class})
|
@Config(shadows = {
|
||||||
|
SettingsShadowResources.class,
|
||||||
|
ShadowUtils.class,
|
||||||
|
ShadowDevicePolicyManager.class,
|
||||||
|
})
|
||||||
public class ChooseLockPasswordTest {
|
public class ChooseLockPasswordTest {
|
||||||
|
|
||||||
|
private ShadowDevicePolicyManager mShadowDpm;
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() {
|
public void setUp() {
|
||||||
SettingsShadowResources.overrideResource(
|
SettingsShadowResources.overrideResource(
|
||||||
com.android.internal.R.string.config_headlineFontFamily, "");
|
com.android.internal.R.string.config_headlineFontFamily, "");
|
||||||
|
mShadowDpm = ShadowDevicePolicyManager.getShadow();
|
||||||
|
mShadowDpm.setPasswordMaximumLength(16);
|
||||||
}
|
}
|
||||||
|
|
||||||
@After
|
@After
|
||||||
@@ -72,7 +98,7 @@ public class ChooseLockPasswordTest {
|
|||||||
assertThat(intent.getStringExtra(ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD))
|
assertThat(intent.getStringExtra(ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD))
|
||||||
.named("EXTRA_KEY_PASSWORD")
|
.named("EXTRA_KEY_PASSWORD")
|
||||||
.isEqualTo("password");
|
.isEqualTo("password");
|
||||||
assertThat(intent.getIntExtra(LockPatternUtils.PASSWORD_TYPE_KEY, 0))
|
assertThat(intent.getIntExtra(PASSWORD_TYPE_KEY, 0))
|
||||||
.named("PASSWORD_TYPE_KEY")
|
.named("PASSWORD_TYPE_KEY")
|
||||||
.isEqualTo(DevicePolicyManager.PASSWORD_QUALITY_NUMERIC);
|
.isEqualTo(DevicePolicyManager.PASSWORD_QUALITY_NUMERIC);
|
||||||
assertThat(intent.getIntExtra(Intent.EXTRA_USER_ID, 0))
|
assertThat(intent.getIntExtra(Intent.EXTRA_USER_ID, 0))
|
||||||
@@ -84,7 +110,7 @@ public class ChooseLockPasswordTest {
|
|||||||
public void intentBuilder_setChallenge_shouldAddExtras() {
|
public void intentBuilder_setChallenge_shouldAddExtras() {
|
||||||
Intent intent = new IntentBuilder(application)
|
Intent intent = new IntentBuilder(application)
|
||||||
.setChallenge(12345L)
|
.setChallenge(12345L)
|
||||||
.setPasswordQuality(DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC)
|
.setPasswordQuality(PASSWORD_QUALITY_ALPHANUMERIC)
|
||||||
.setUserId(123)
|
.setUserId(123)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
@@ -94,14 +120,213 @@ public class ChooseLockPasswordTest {
|
|||||||
assertThat(intent.getLongExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE, 0L))
|
assertThat(intent.getLongExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE, 0L))
|
||||||
.named("EXTRA_KEY_CHALLENGE")
|
.named("EXTRA_KEY_CHALLENGE")
|
||||||
.isEqualTo(12345L);
|
.isEqualTo(12345L);
|
||||||
assertThat(intent.getIntExtra(LockPatternUtils.PASSWORD_TYPE_KEY, 0))
|
assertThat(intent.getIntExtra(PASSWORD_TYPE_KEY, 0))
|
||||||
.named("PASSWORD_TYPE_KEY")
|
.named("PASSWORD_TYPE_KEY")
|
||||||
.isEqualTo(DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC);
|
.isEqualTo(PASSWORD_QUALITY_ALPHANUMERIC);
|
||||||
assertThat(intent.getIntExtra(Intent.EXTRA_USER_ID, 0))
|
assertThat(intent.getIntExtra(Intent.EXTRA_USER_ID, 0))
|
||||||
.named("EXTRA_USER_ID")
|
.named("EXTRA_USER_ID")
|
||||||
.isEqualTo(123);
|
.isEqualTo(123);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void intentBuilder_setMinComplexityMedium_hasMinComplexityExtraMedium() {
|
||||||
|
Intent intent = new IntentBuilder(application)
|
||||||
|
.setRequestedMinComplexity(PASSWORD_COMPLEXITY_MEDIUM)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
assertThat(intent.hasExtra(EXTRA_KEY_REQUESTED_MIN_COMPLEXITY)).isTrue();
|
||||||
|
assertThat(intent.getIntExtra(EXTRA_KEY_REQUESTED_MIN_COMPLEXITY, PASSWORD_COMPLEXITY_NONE))
|
||||||
|
.isEqualTo(PASSWORD_COMPLEXITY_MEDIUM);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void intentBuilder_setMinComplexityNotCalled() {
|
||||||
|
Intent intent = new IntentBuilder(application).build();
|
||||||
|
|
||||||
|
assertThat(intent.hasExtra(EXTRA_KEY_REQUESTED_MIN_COMPLEXITY)).isFalse();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void processAndValidatePasswordRequirements_noMinPasswordComplexity() {
|
||||||
|
mShadowDpm.setPasswordQuality(PASSWORD_QUALITY_ALPHABETIC);
|
||||||
|
mShadowDpm.setPasswordMinimumLength(10);
|
||||||
|
|
||||||
|
assertPasswordValidationResult(
|
||||||
|
/* minComplexity= */ PASSWORD_COMPLEXITY_NONE,
|
||||||
|
/* passwordType= */ PASSWORD_QUALITY_ALPHABETIC,
|
||||||
|
/* userEnteredPassword= */ "",
|
||||||
|
"Must contain at least 1 letter",
|
||||||
|
"Must be at least 10 characters");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void processAndValidatePasswordRequirements_minPasswordComplexityStricter_pin() {
|
||||||
|
mShadowDpm.setPasswordQuality(PASSWORD_QUALITY_SOMETHING);
|
||||||
|
|
||||||
|
assertPasswordValidationResult(
|
||||||
|
/* minComplexity= */ PASSWORD_COMPLEXITY_HIGH,
|
||||||
|
/* passwordType= */ PASSWORD_QUALITY_NUMERIC,
|
||||||
|
/* userEnteredPassword= */ "",
|
||||||
|
"PIN must be at least 8 digits");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void processAndValidatePasswordRequirements_minPasswordComplexityStricter_password() {
|
||||||
|
mShadowDpm.setPasswordQuality(PASSWORD_QUALITY_SOMETHING);
|
||||||
|
|
||||||
|
assertPasswordValidationResult(
|
||||||
|
/* minComplexity= */ PASSWORD_COMPLEXITY_MEDIUM,
|
||||||
|
/* passwordType= */ PASSWORD_QUALITY_ALPHABETIC,
|
||||||
|
/* userEnteredPassword= */ "",
|
||||||
|
"Must contain at least 1 letter",
|
||||||
|
"Must be at least 4 characters");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void processAndValidatePasswordRequirements_dpmRestrictionsStricter_password() {
|
||||||
|
mShadowDpm.setPasswordQuality(PASSWORD_QUALITY_ALPHANUMERIC);
|
||||||
|
mShadowDpm.setPasswordMinimumLength(9);
|
||||||
|
|
||||||
|
assertPasswordValidationResult(
|
||||||
|
/* minComplexity= */ PASSWORD_COMPLEXITY_LOW,
|
||||||
|
/* passwordType= */ PASSWORD_QUALITY_ALPHABETIC,
|
||||||
|
/* userEnteredPassword= */ "",
|
||||||
|
"Must contain at least 1 letter",
|
||||||
|
"Must contain at least 1 numerical digit",
|
||||||
|
"Must be at least 9 characters");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void processAndValidatePasswordRequirements_dpmLengthLonger_pin() {
|
||||||
|
mShadowDpm.setPasswordQuality(PASSWORD_QUALITY_NUMERIC);
|
||||||
|
mShadowDpm.setPasswordMinimumLength(11);
|
||||||
|
|
||||||
|
assertPasswordValidationResult(
|
||||||
|
/* minComplexity= */ PASSWORD_COMPLEXITY_MEDIUM,
|
||||||
|
/* passwordType= */ PASSWORD_QUALITY_NUMERIC,
|
||||||
|
/* userEnteredPassword= */ "",
|
||||||
|
"PIN must be at least 11 digits");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void processAndValidatePasswordRequirements_dpmQualityComplex() {
|
||||||
|
mShadowDpm.setPasswordQuality(PASSWORD_QUALITY_COMPLEX);
|
||||||
|
mShadowDpm.setPasswordMinimumSymbols(2);
|
||||||
|
|
||||||
|
assertPasswordValidationResult(
|
||||||
|
/* minComplexity= */ PASSWORD_COMPLEXITY_HIGH,
|
||||||
|
/* passwordType= */ PASSWORD_QUALITY_ALPHABETIC,
|
||||||
|
/* userEnteredPassword= */ "",
|
||||||
|
"Must contain at least 2 special symbols",
|
||||||
|
"Must be at least 6 characters");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Config(shadows = ShadowLockPatternUtils.class)
|
||||||
|
public void processAndValidatePasswordRequirements_numericComplexNoMinComplexity_pinRequested() {
|
||||||
|
mShadowDpm.setPasswordQuality(PASSWORD_QUALITY_NUMERIC_COMPLEX);
|
||||||
|
|
||||||
|
assertPasswordValidationResult(
|
||||||
|
/* minComplexity= */ PASSWORD_COMPLEXITY_NONE,
|
||||||
|
/* passwordType= */ PASSWORD_QUALITY_NUMERIC,
|
||||||
|
/* userEnteredPassword= */ "12345678",
|
||||||
|
"Ascending, descending, or repeated sequence of digits isn't allowed");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Config(shadows = ShadowLockPatternUtils.class)
|
||||||
|
public void processAndValidatePasswordRequirements_numericComplexNoMinComplexity_passwordRequested() {
|
||||||
|
mShadowDpm.setPasswordQuality(PASSWORD_QUALITY_NUMERIC_COMPLEX);
|
||||||
|
|
||||||
|
assertPasswordValidationResult(
|
||||||
|
/* minComplexity= */ PASSWORD_COMPLEXITY_NONE,
|
||||||
|
/* passwordType= */ PASSWORD_QUALITY_ALPHABETIC,
|
||||||
|
/* userEnteredPassword= */ "12345678",
|
||||||
|
"Ascending, descending, or repeated sequence of digits isn't allowed");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Config(shadows = ShadowLockPatternUtils.class)
|
||||||
|
public void processAndValidatePasswordRequirements_numericComplexHighComplexity_pinRequested() {
|
||||||
|
mShadowDpm.setPasswordQuality(PASSWORD_QUALITY_NUMERIC_COMPLEX);
|
||||||
|
|
||||||
|
assertPasswordValidationResult(
|
||||||
|
/* minComplexity= */ PASSWORD_COMPLEXITY_HIGH,
|
||||||
|
/* passwordType= */ PASSWORD_QUALITY_NUMERIC,
|
||||||
|
/* userEnteredPassword= */ "12345678",
|
||||||
|
"Ascending, descending, or repeated sequence of digits isn't allowed");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Config(shadows = ShadowLockPatternUtils.class)
|
||||||
|
public void processAndValidatePasswordRequirements_numericHighComplexity_pinRequested() {
|
||||||
|
mShadowDpm.setPasswordQuality(PASSWORD_QUALITY_NUMERIC);
|
||||||
|
|
||||||
|
assertPasswordValidationResult(
|
||||||
|
/* minComplexity= */ PASSWORD_COMPLEXITY_HIGH,
|
||||||
|
/* passwordType= */ PASSWORD_QUALITY_NUMERIC,
|
||||||
|
/* userEnteredPassword= */ "12345678",
|
||||||
|
"Ascending, descending, or repeated sequence of digits isn't allowed");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Config(shadows = ShadowLockPatternUtils.class)
|
||||||
|
public void processAndValidatePasswordRequirements_numericComplexLowComplexity_passwordRequested() {
|
||||||
|
mShadowDpm.setPasswordQuality(PASSWORD_QUALITY_NUMERIC_COMPLEX);
|
||||||
|
|
||||||
|
assertPasswordValidationResult(
|
||||||
|
/* minComplexity= */ PASSWORD_COMPLEXITY_LOW,
|
||||||
|
/* passwordType= */ PASSWORD_QUALITY_ALPHABETIC,
|
||||||
|
/* userEnteredPassword= */ "12345678",
|
||||||
|
"Must contain at least 1 letter");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void processAndValidatePasswordRequirements_requirementsUpdateAccordingToMinComplexityAndUserInput_empty() {
|
||||||
|
mShadowDpm.setPasswordQuality(PASSWORD_QUALITY_UNSPECIFIED);
|
||||||
|
|
||||||
|
assertPasswordValidationResult(
|
||||||
|
/* minComplexity= */ PASSWORD_COMPLEXITY_HIGH,
|
||||||
|
/* passwordType= */ PASSWORD_QUALITY_ALPHABETIC,
|
||||||
|
/* userEnteredPassword= */ "",
|
||||||
|
"Must contain at least 1 letter",
|
||||||
|
"Must be at least 6 characters");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void processAndValidatePasswordRequirements_requirementsUpdateAccordingToMinComplexityAndUserInput_numeric() {
|
||||||
|
mShadowDpm.setPasswordQuality(PASSWORD_QUALITY_UNSPECIFIED);
|
||||||
|
|
||||||
|
assertPasswordValidationResult(
|
||||||
|
/* minComplexity= */ PASSWORD_COMPLEXITY_HIGH,
|
||||||
|
/* passwordType= */ PASSWORD_QUALITY_ALPHABETIC,
|
||||||
|
/* userEnteredPassword= */ "1",
|
||||||
|
"Must contain at least 1 letter",
|
||||||
|
"Must be at least 6 characters");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void processAndValidatePasswordRequirements_requirementsUpdateAccordingToMinComplexityAndUserInput_alphabetic() {
|
||||||
|
mShadowDpm.setPasswordQuality(PASSWORD_QUALITY_UNSPECIFIED);
|
||||||
|
|
||||||
|
assertPasswordValidationResult(
|
||||||
|
/* minComplexity= */ PASSWORD_COMPLEXITY_HIGH,
|
||||||
|
/* passwordType= */ PASSWORD_QUALITY_ALPHABETIC,
|
||||||
|
/* userEnteredPassword= */ "b",
|
||||||
|
"Must be at least 6 characters");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void processAndValidatePasswordRequirements_requirementsUpdateAccordingToMinComplexityAndUserInput_alphanumeric() {
|
||||||
|
mShadowDpm.setPasswordQuality(PASSWORD_QUALITY_UNSPECIFIED);
|
||||||
|
|
||||||
|
assertPasswordValidationResult(
|
||||||
|
/* minComplexity= */ PASSWORD_COMPLEXITY_HIGH,
|
||||||
|
/* passwordType= */ PASSWORD_QUALITY_ALPHABETIC,
|
||||||
|
/* userEnteredPassword= */ "b1",
|
||||||
|
"Must be at least 6 characters");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void assertThat_chooseLockIconChanged_WhenFingerprintExtraSet() {
|
public void assertThat_chooseLockIconChanged_WhenFingerprintExtraSet() {
|
||||||
ShadowDrawable drawable = setActivityAndGetIconDrawable(true);
|
ShadowDrawable drawable = setActivityAndGetIconDrawable(true);
|
||||||
@@ -132,4 +357,18 @@ public class ChooseLockPasswordTest {
|
|||||||
ChooseLockPasswordFragment fragment = getChooseLockPasswordFragment(passwordActivity);
|
ChooseLockPasswordFragment fragment = getChooseLockPasswordFragment(passwordActivity);
|
||||||
return Shadows.shadowOf(((GlifLayout) fragment.getView()).getIcon());
|
return Shadows.shadowOf(((GlifLayout) fragment.getView()).getIcon());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void assertPasswordValidationResult(@PasswordComplexity int minComplexity,
|
||||||
|
int passwordType, String userEnteredPassword, String... expectedValidationResult) {
|
||||||
|
Intent intent = new Intent();
|
||||||
|
intent.putExtra(CONFIRM_CREDENTIALS, false);
|
||||||
|
intent.putExtra(PASSWORD_TYPE_KEY, passwordType);
|
||||||
|
intent.putExtra(EXTRA_KEY_REQUESTED_MIN_COMPLEXITY, minComplexity);
|
||||||
|
ChooseLockPassword activity = buildChooseLockPasswordActivity(intent);
|
||||||
|
ChooseLockPasswordFragment fragment = getChooseLockPasswordFragment(activity);
|
||||||
|
int validateResult = fragment.validatePassword(userEnteredPassword);
|
||||||
|
String[] messages = fragment.convertErrorCodeToMessages(validateResult);
|
||||||
|
|
||||||
|
assertThat(messages).asList().containsExactly((Object[]) expectedValidationResult);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,140 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2019 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.android.settings.password;
|
||||||
|
|
||||||
|
import static android.content.pm.PackageManager.PERMISSION_DENIED;
|
||||||
|
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
|
||||||
|
|
||||||
|
import static com.android.settings.password.PasswordUtils.getCallingAppLabel;
|
||||||
|
import static com.android.settings.password.PasswordUtils.isCallingAppPermitted;
|
||||||
|
|
||||||
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
|
import static org.mockito.ArgumentMatchers.anyInt;
|
||||||
|
import static org.mockito.ArgumentMatchers.eq;
|
||||||
|
import static org.mockito.Mockito.spy;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
import android.app.IActivityManager;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.pm.ApplicationInfo;
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
|
import android.content.pm.PackageManager.NameNotFoundException;
|
||||||
|
import android.os.IBinder;
|
||||||
|
import android.os.RemoteException;
|
||||||
|
|
||||||
|
import com.android.settings.testutils.shadow.ShadowActivityManager;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.MockitoAnnotations;
|
||||||
|
import org.robolectric.RobolectricTestRunner;
|
||||||
|
import org.robolectric.RuntimeEnvironment;
|
||||||
|
import org.robolectric.annotation.Config;
|
||||||
|
|
||||||
|
@RunWith(RobolectricTestRunner.class)
|
||||||
|
@Config(shadows = {ShadowActivityManager.class})
|
||||||
|
public class PasswordUtilsTest {
|
||||||
|
|
||||||
|
private static final String PACKAGE_NAME = "com.android.app";
|
||||||
|
private static final String PERMISSION = "com.testing.permission";
|
||||||
|
private static final int UID = 1234;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private PackageManager mPackageManager;
|
||||||
|
@Mock
|
||||||
|
private ApplicationInfo mApplicationInfo;
|
||||||
|
@Mock
|
||||||
|
private IActivityManager mActivityService;
|
||||||
|
@Mock
|
||||||
|
private IBinder mActivityToken;
|
||||||
|
|
||||||
|
private Context mContext;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() {
|
||||||
|
MockitoAnnotations.initMocks(this);
|
||||||
|
|
||||||
|
mContext = spy(RuntimeEnvironment.application);
|
||||||
|
when(mContext.getPackageManager()).thenReturn(mPackageManager);
|
||||||
|
ShadowActivityManager.setService(mActivityService);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getCallingAppLabel_activityServiceThrowsRemoteException_returnsNull()
|
||||||
|
throws Exception {
|
||||||
|
when(mActivityService.getLaunchedFromPackage(mActivityToken))
|
||||||
|
.thenThrow(new RemoteException());
|
||||||
|
|
||||||
|
assertThat(getCallingAppLabel(mContext, mActivityToken)).isNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getCallingAppLabel_activityServiceReturnsSettingsApp_returnsNull()
|
||||||
|
throws Exception {
|
||||||
|
when(mActivityService.getLaunchedFromPackage(mActivityToken))
|
||||||
|
.thenReturn("com.android.settings");
|
||||||
|
|
||||||
|
assertThat(getCallingAppLabel(mContext, mActivityToken)).isNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getCallingAppLabel_packageManagerThrowsNameNotFound_returnsNull() throws Exception {
|
||||||
|
when(mActivityService.getLaunchedFromPackage(mActivityToken))
|
||||||
|
.thenReturn(PACKAGE_NAME);
|
||||||
|
when(mPackageManager.getApplicationInfo(eq(PACKAGE_NAME), anyInt()))
|
||||||
|
.thenThrow(new NameNotFoundException());
|
||||||
|
|
||||||
|
assertThat(getCallingAppLabel(mContext, mActivityToken)).isNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getCallingAppLabel_returnsLabel() throws Exception {
|
||||||
|
when(mActivityService.getLaunchedFromPackage(mActivityToken))
|
||||||
|
.thenReturn(PACKAGE_NAME);
|
||||||
|
when(mPackageManager.getApplicationInfo(eq(PACKAGE_NAME), anyInt()))
|
||||||
|
.thenReturn(mApplicationInfo);
|
||||||
|
when(mApplicationInfo.loadLabel(mPackageManager)).thenReturn("label");
|
||||||
|
|
||||||
|
assertThat(getCallingAppLabel(mContext, mActivityToken)).isEqualTo("label");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void isCallingAppPermitted_permissionGranted_returnsTrue() throws Exception {
|
||||||
|
when(mActivityService.getLaunchedFromUid(mActivityToken)).thenReturn(UID);
|
||||||
|
when(mContext.checkPermission(PERMISSION, -1, UID)).thenReturn(PERMISSION_GRANTED);
|
||||||
|
|
||||||
|
assertThat(isCallingAppPermitted(mContext, mActivityToken, PERMISSION)).isTrue();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void isCallingAppPermitted_permissionDenied_returnsFalse() throws Exception {
|
||||||
|
when(mActivityService.getLaunchedFromUid(mActivityToken)).thenReturn(UID);
|
||||||
|
when(mContext.checkPermission(PERMISSION, -1, UID)).thenReturn(PERMISSION_DENIED);
|
||||||
|
|
||||||
|
assertThat(isCallingAppPermitted(mContext, mActivityToken, PERMISSION)).isFalse();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void isCallingAppPermitted_throwsRemoteException_returnsFalse() throws Exception {
|
||||||
|
when(mActivityService.getLaunchedFromUid(mActivityToken)).thenThrow(new RemoteException());
|
||||||
|
|
||||||
|
assertThat(isCallingAppPermitted(mContext, mActivityToken, PERMISSION)).isFalse();
|
||||||
|
}
|
||||||
|
}
|
@@ -16,6 +16,16 @@
|
|||||||
|
|
||||||
package com.android.settings.password;
|
package com.android.settings.password;
|
||||||
|
|
||||||
|
import static android.Manifest.permission.GET_AND_REQUEST_SCREEN_LOCK_COMPLEXITY;
|
||||||
|
import static android.app.admin.DevicePolicyManager.ACTION_SET_NEW_PARENT_PROFILE_PASSWORD;
|
||||||
|
import static android.app.admin.DevicePolicyManager.ACTION_SET_NEW_PASSWORD;
|
||||||
|
import static android.app.admin.DevicePolicyManager.EXTRA_PASSWORD_COMPLEXITY;
|
||||||
|
import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_HIGH;
|
||||||
|
import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_NONE;
|
||||||
|
|
||||||
|
import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_CALLER_APP_NAME;
|
||||||
|
import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_REQUESTED_MIN_COMPLEXITY;
|
||||||
|
|
||||||
import static com.google.common.truth.Truth.assertThat;
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
import android.content.ComponentName;
|
import android.content.ComponentName;
|
||||||
@@ -23,6 +33,8 @@ import android.content.Intent;
|
|||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.provider.Settings;
|
import android.provider.Settings;
|
||||||
|
|
||||||
|
import com.android.settings.testutils.shadow.ShadowPasswordUtils;
|
||||||
|
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
@@ -31,11 +43,14 @@ import org.robolectric.Robolectric;
|
|||||||
import org.robolectric.RobolectricTestRunner;
|
import org.robolectric.RobolectricTestRunner;
|
||||||
import org.robolectric.RuntimeEnvironment;
|
import org.robolectric.RuntimeEnvironment;
|
||||||
import org.robolectric.Shadows;
|
import org.robolectric.Shadows;
|
||||||
|
import org.robolectric.annotation.Config;
|
||||||
import org.robolectric.shadows.ShadowActivity;
|
import org.robolectric.shadows.ShadowActivity;
|
||||||
|
|
||||||
@RunWith(RobolectricTestRunner.class)
|
@RunWith(RobolectricTestRunner.class)
|
||||||
public class SetNewPasswordActivityTest {
|
public class SetNewPasswordActivityTest {
|
||||||
|
|
||||||
|
private static final String APP_LABEL = "label";
|
||||||
|
|
||||||
private int mProvisioned;
|
private int mProvisioned;
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
@@ -48,6 +63,7 @@ public class SetNewPasswordActivityTest {
|
|||||||
public void tearDown() {
|
public void tearDown() {
|
||||||
Settings.Global.putInt(RuntimeEnvironment.application.getContentResolver(),
|
Settings.Global.putInt(RuntimeEnvironment.application.getContentResolver(),
|
||||||
Settings.Global.DEVICE_PROVISIONED, mProvisioned);
|
Settings.Global.DEVICE_PROVISIONED, mProvisioned);
|
||||||
|
ShadowPasswordUtils.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -77,4 +93,106 @@ public class SetNewPasswordActivityTest {
|
|||||||
assertThat(intent.getComponent())
|
assertThat(intent.getComponent())
|
||||||
.isEqualTo(new ComponentName(activity, SetupChooseLockGeneric.class));
|
.isEqualTo(new ComponentName(activity, SetupChooseLockGeneric.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Config(shadows = {ShadowPasswordUtils.class})
|
||||||
|
public void testLaunchChooseLock_setNewPasswordExtraWithoutPermission() {
|
||||||
|
ShadowPasswordUtils.setCallingAppLabel(APP_LABEL);
|
||||||
|
Settings.Global.putInt(RuntimeEnvironment.application.getContentResolver(),
|
||||||
|
Settings.Global.DEVICE_PROVISIONED, 1);
|
||||||
|
|
||||||
|
Intent intent = new Intent(ACTION_SET_NEW_PASSWORD);
|
||||||
|
intent.putExtra(EXTRA_PASSWORD_COMPLEXITY, PASSWORD_COMPLEXITY_HIGH);
|
||||||
|
SetNewPasswordActivity activity =
|
||||||
|
Robolectric.buildActivity(SetNewPasswordActivity.class, intent).create().get();
|
||||||
|
|
||||||
|
ShadowActivity shadowActivity = Shadows.shadowOf(activity);
|
||||||
|
assertThat(shadowActivity.getNextStartedActivityForResult()).isNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Config(shadows = {ShadowPasswordUtils.class})
|
||||||
|
public void testLaunchChooseLock_setNewPasswordExtraWithPermission() {
|
||||||
|
ShadowPasswordUtils.setCallingAppLabel(APP_LABEL);
|
||||||
|
ShadowPasswordUtils.addGrantedPermission(GET_AND_REQUEST_SCREEN_LOCK_COMPLEXITY);
|
||||||
|
Settings.Global.putInt(RuntimeEnvironment.application.getContentResolver(),
|
||||||
|
Settings.Global.DEVICE_PROVISIONED, 1);
|
||||||
|
|
||||||
|
Intent intent = new Intent(ACTION_SET_NEW_PASSWORD);
|
||||||
|
intent.putExtra(EXTRA_PASSWORD_COMPLEXITY, PASSWORD_COMPLEXITY_HIGH);
|
||||||
|
SetNewPasswordActivity activity =
|
||||||
|
Robolectric.buildActivity(SetNewPasswordActivity.class, intent).create().get();
|
||||||
|
|
||||||
|
ShadowActivity shadowActivity = Shadows.shadowOf(activity);
|
||||||
|
Intent actualIntent = shadowActivity.getNextStartedActivityForResult().intent;
|
||||||
|
assertThat(actualIntent.getAction()).isEqualTo(ACTION_SET_NEW_PASSWORD);
|
||||||
|
assertThat(actualIntent.hasExtra(EXTRA_KEY_REQUESTED_MIN_COMPLEXITY)).isTrue();
|
||||||
|
assertThat(actualIntent.getIntExtra(EXTRA_KEY_REQUESTED_MIN_COMPLEXITY, PASSWORD_COMPLEXITY_NONE))
|
||||||
|
.isEqualTo(PASSWORD_COMPLEXITY_HIGH);
|
||||||
|
assertThat(actualIntent.hasExtra(EXTRA_KEY_CALLER_APP_NAME)).isTrue();
|
||||||
|
assertThat(actualIntent.getStringExtra(EXTRA_KEY_CALLER_APP_NAME)).isEqualTo(APP_LABEL);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Config(shadows = {ShadowPasswordUtils.class})
|
||||||
|
public void testLaunchChooseLock_setNewPasswordExtraInvalidValue() {
|
||||||
|
ShadowPasswordUtils.setCallingAppLabel(APP_LABEL);
|
||||||
|
ShadowPasswordUtils.addGrantedPermission(GET_AND_REQUEST_SCREEN_LOCK_COMPLEXITY);
|
||||||
|
Settings.Global.putInt(RuntimeEnvironment.application.getContentResolver(),
|
||||||
|
Settings.Global.DEVICE_PROVISIONED, 1);
|
||||||
|
|
||||||
|
Intent intent = new Intent(ACTION_SET_NEW_PASSWORD);
|
||||||
|
intent.putExtra(EXTRA_PASSWORD_COMPLEXITY, -1);
|
||||||
|
SetNewPasswordActivity activity =
|
||||||
|
Robolectric.buildActivity(SetNewPasswordActivity.class, intent).create().get();
|
||||||
|
|
||||||
|
ShadowActivity shadowActivity = Shadows.shadowOf(activity);
|
||||||
|
Intent actualIntent = shadowActivity.getNextStartedActivityForResult().intent;
|
||||||
|
assertThat(actualIntent.getAction()).isEqualTo(ACTION_SET_NEW_PASSWORD);
|
||||||
|
assertThat(actualIntent.hasExtra(EXTRA_KEY_REQUESTED_MIN_COMPLEXITY)).isFalse();
|
||||||
|
assertThat(actualIntent.hasExtra(EXTRA_KEY_CALLER_APP_NAME)).isTrue();
|
||||||
|
assertThat(actualIntent.getStringExtra(EXTRA_KEY_CALLER_APP_NAME)).isEqualTo(APP_LABEL);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Config(shadows = {ShadowPasswordUtils.class})
|
||||||
|
public void testLaunchChooseLock_setNewPasswordExtraNoneComplexity() {
|
||||||
|
ShadowPasswordUtils.setCallingAppLabel(APP_LABEL);
|
||||||
|
ShadowPasswordUtils.addGrantedPermission(GET_AND_REQUEST_SCREEN_LOCK_COMPLEXITY);
|
||||||
|
Settings.Global.putInt(RuntimeEnvironment.application.getContentResolver(),
|
||||||
|
Settings.Global.DEVICE_PROVISIONED, 1);
|
||||||
|
|
||||||
|
Intent intent = new Intent(ACTION_SET_NEW_PASSWORD);
|
||||||
|
intent.putExtra(EXTRA_PASSWORD_COMPLEXITY, PASSWORD_COMPLEXITY_NONE);
|
||||||
|
SetNewPasswordActivity activity =
|
||||||
|
Robolectric.buildActivity(SetNewPasswordActivity.class, intent).create().get();
|
||||||
|
|
||||||
|
ShadowActivity shadowActivity = Shadows.shadowOf(activity);
|
||||||
|
Intent actualIntent = shadowActivity.getNextStartedActivityForResult().intent;
|
||||||
|
assertThat(actualIntent.getAction()).isEqualTo(ACTION_SET_NEW_PASSWORD);
|
||||||
|
assertThat(actualIntent.hasExtra(EXTRA_KEY_REQUESTED_MIN_COMPLEXITY)).isFalse();
|
||||||
|
assertThat(actualIntent.hasExtra(EXTRA_KEY_CALLER_APP_NAME)).isTrue();
|
||||||
|
assertThat(actualIntent.getStringExtra(EXTRA_KEY_CALLER_APP_NAME)).isEqualTo(APP_LABEL);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Config(shadows = {ShadowPasswordUtils.class})
|
||||||
|
public void testLaunchChooseLock_setNewParentProfilePasswordExtraWithPermission() {
|
||||||
|
ShadowPasswordUtils.setCallingAppLabel(APP_LABEL);
|
||||||
|
ShadowPasswordUtils.addGrantedPermission(GET_AND_REQUEST_SCREEN_LOCK_COMPLEXITY);
|
||||||
|
Settings.Global.putInt(RuntimeEnvironment.application.getContentResolver(),
|
||||||
|
Settings.Global.DEVICE_PROVISIONED, 1);
|
||||||
|
|
||||||
|
Intent intent = new Intent(ACTION_SET_NEW_PARENT_PROFILE_PASSWORD);
|
||||||
|
intent.putExtra(EXTRA_PASSWORD_COMPLEXITY, PASSWORD_COMPLEXITY_HIGH);
|
||||||
|
SetNewPasswordActivity activity =
|
||||||
|
Robolectric.buildActivity(SetNewPasswordActivity.class, intent).create().get();
|
||||||
|
|
||||||
|
ShadowActivity shadowActivity = Shadows.shadowOf(activity);
|
||||||
|
Intent actualIntent = shadowActivity.getNextStartedActivityForResult().intent;
|
||||||
|
assertThat(actualIntent.getAction()).isEqualTo(ACTION_SET_NEW_PARENT_PROFILE_PASSWORD);
|
||||||
|
assertThat(actualIntent.hasExtra(EXTRA_KEY_REQUESTED_MIN_COMPLEXITY)).isFalse();
|
||||||
|
assertThat(actualIntent.hasExtra(EXTRA_KEY_CALLER_APP_NAME)).isTrue();
|
||||||
|
assertThat(actualIntent.getStringExtra(EXTRA_KEY_CALLER_APP_NAME)).isEqualTo(APP_LABEL);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,81 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2019 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.android.settings.password;
|
||||||
|
|
||||||
|
import static android.Manifest.permission.GET_AND_REQUEST_SCREEN_LOCK_COMPLEXITY;
|
||||||
|
import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_HIGH;
|
||||||
|
|
||||||
|
import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_REQUESTED_MIN_COMPLEXITY;
|
||||||
|
|
||||||
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
|
import static org.robolectric.Shadows.shadowOf;
|
||||||
|
|
||||||
|
import android.content.Intent;
|
||||||
|
|
||||||
|
import com.android.settings.testutils.shadow.ShadowLockPatternUtils;
|
||||||
|
import com.android.settings.testutils.shadow.ShadowPasswordUtils;
|
||||||
|
import com.android.settings.testutils.shadow.ShadowUserManager;
|
||||||
|
import com.android.settings.testutils.shadow.ShadowUtils;
|
||||||
|
|
||||||
|
import org.junit.After;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.robolectric.Robolectric;
|
||||||
|
import org.robolectric.RobolectricTestRunner;
|
||||||
|
import org.robolectric.Shadows;
|
||||||
|
import org.robolectric.annotation.Config;
|
||||||
|
import org.robolectric.shadows.ShadowActivity;
|
||||||
|
|
||||||
|
@RunWith(RobolectricTestRunner.class)
|
||||||
|
@Config(shadows = {
|
||||||
|
ShadowUserManager.class,
|
||||||
|
ShadowUtils.class,
|
||||||
|
ShadowLockPatternUtils.class,
|
||||||
|
})
|
||||||
|
public class SetupChooseLockGenericTest {
|
||||||
|
|
||||||
|
@After
|
||||||
|
public void tearDown() {
|
||||||
|
ShadowPasswordUtils.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void setupChooseLockGenericPasswordComplexityExtraWithoutPermission() {
|
||||||
|
Intent intent = new Intent("com.android.settings.SETUP_LOCK_SCREEN");
|
||||||
|
intent.putExtra(EXTRA_KEY_REQUESTED_MIN_COMPLEXITY, PASSWORD_COMPLEXITY_HIGH);
|
||||||
|
SetupChooseLockGeneric activity =
|
||||||
|
Robolectric.buildActivity(SetupChooseLockGeneric.class, intent).create().get();
|
||||||
|
|
||||||
|
ShadowActivity shadowActivity = Shadows.shadowOf(activity);
|
||||||
|
assertThat(shadowActivity.isFinishing()).isTrue();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Config(shadows = {ShadowPasswordUtils.class})
|
||||||
|
public void setupChooseLockGenericPasswordComplexityExtraWithPermission() {
|
||||||
|
ShadowPasswordUtils.addGrantedPermission(GET_AND_REQUEST_SCREEN_LOCK_COMPLEXITY);
|
||||||
|
|
||||||
|
Intent intent = new Intent("com.android.settings.SETUP_LOCK_SCREEN");
|
||||||
|
intent.putExtra(EXTRA_KEY_REQUESTED_MIN_COMPLEXITY, PASSWORD_COMPLEXITY_HIGH);
|
||||||
|
SetupChooseLockGeneric activity =
|
||||||
|
Robolectric.buildActivity(SetupChooseLockGeneric.class, intent).create().get();
|
||||||
|
|
||||||
|
ShadowActivity shadowActivity = Shadows.shadowOf(activity);
|
||||||
|
assertThat(shadowActivity.isFinishing()).isFalse();
|
||||||
|
}
|
||||||
|
}
|
@@ -17,6 +17,7 @@
|
|||||||
package com.android.settings.testutils.shadow;
|
package com.android.settings.testutils.shadow;
|
||||||
|
|
||||||
import android.app.ActivityManager;
|
import android.app.ActivityManager;
|
||||||
|
import android.app.IActivityManager;
|
||||||
|
|
||||||
import org.robolectric.annotation.Implementation;
|
import org.robolectric.annotation.Implementation;
|
||||||
import org.robolectric.annotation.Implements;
|
import org.robolectric.annotation.Implements;
|
||||||
@@ -24,6 +25,7 @@ import org.robolectric.annotation.Implements;
|
|||||||
@Implements(ActivityManager.class)
|
@Implements(ActivityManager.class)
|
||||||
public class ShadowActivityManager {
|
public class ShadowActivityManager {
|
||||||
private static int sCurrentUserId = 0;
|
private static int sCurrentUserId = 0;
|
||||||
|
private static IActivityManager sService = null;
|
||||||
|
|
||||||
@Implementation
|
@Implementation
|
||||||
protected static int getCurrentUser() {
|
protected static int getCurrentUser() {
|
||||||
@@ -33,4 +35,13 @@ public class ShadowActivityManager {
|
|||||||
public static void setCurrentUser(int userId) {
|
public static void setCurrentUser(int userId) {
|
||||||
sCurrentUserId = userId;
|
sCurrentUserId = userId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Implementation
|
||||||
|
public static IActivityManager getService() {
|
||||||
|
return sService;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void setService(IActivityManager service) {
|
||||||
|
sService = service;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,5 +1,7 @@
|
|||||||
package com.android.settings.testutils.shadow;
|
package com.android.settings.testutils.shadow;
|
||||||
|
|
||||||
|
import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
|
||||||
|
|
||||||
import android.annotation.NonNull;
|
import android.annotation.NonNull;
|
||||||
import android.annotation.Nullable;
|
import android.annotation.Nullable;
|
||||||
import android.annotation.UserIdInt;
|
import android.annotation.UserIdInt;
|
||||||
@@ -23,6 +25,10 @@ public class ShadowDevicePolicyManager extends org.robolectric.shadows.ShadowDev
|
|||||||
private boolean mIsAdminActiveAsUser = false;
|
private boolean mIsAdminActiveAsUser = false;
|
||||||
private ComponentName mDeviceOwnerComponentName;
|
private ComponentName mDeviceOwnerComponentName;
|
||||||
private int mDeviceOwnerUserId = -1;
|
private int mDeviceOwnerUserId = -1;
|
||||||
|
private int mPasswordMinQuality = PASSWORD_QUALITY_UNSPECIFIED;
|
||||||
|
private int mPasswordMaxLength = 16;
|
||||||
|
private int mPasswordMinLength = 0;
|
||||||
|
private int mPasswordMinSymbols = 0;
|
||||||
|
|
||||||
public void setShortSupportMessageForUser(ComponentName admin, int userHandle, String message) {
|
public void setShortSupportMessageForUser(ComponentName admin, int userHandle, String message) {
|
||||||
mSupportMessagesMap.put(Objects.hash(admin, userHandle), message);
|
mSupportMessagesMap.put(Objects.hash(admin, userHandle), message);
|
||||||
@@ -70,6 +76,42 @@ public class ShadowDevicePolicyManager extends org.robolectric.shadows.ShadowDev
|
|||||||
mDeviceOwnerComponentName = admin;
|
mDeviceOwnerComponentName = admin;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Implementation
|
||||||
|
public int getPasswordQuality(ComponentName admin, int userHandle) {
|
||||||
|
return mPasswordMinQuality;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPasswordQuality(int quality) {
|
||||||
|
mPasswordMinQuality = quality;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Implementation
|
||||||
|
public int getPasswordMinimumLength(ComponentName admin, int userHandle) {
|
||||||
|
return mPasswordMinLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPasswordMinimumLength(int length) {
|
||||||
|
mPasswordMinLength = length;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Implementation
|
||||||
|
public int getPasswordMinimumSymbols(ComponentName admin, int userHandle) {
|
||||||
|
return mPasswordMinSymbols;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPasswordMinimumSymbols(int numOfSymbols) {
|
||||||
|
mPasswordMinSymbols = numOfSymbols;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Implementation
|
||||||
|
public int getPasswordMaximumLength(int quality) {
|
||||||
|
return mPasswordMaxLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPasswordMaximumLength(int length) {
|
||||||
|
mPasswordMaxLength = length;
|
||||||
|
}
|
||||||
|
|
||||||
public static ShadowDevicePolicyManager getShadow() {
|
public static ShadowDevicePolicyManager getShadow() {
|
||||||
return (ShadowDevicePolicyManager) Shadow.extract(
|
return (ShadowDevicePolicyManager) Shadow.extract(
|
||||||
RuntimeEnvironment.application.getSystemService(DevicePolicyManager.class));
|
RuntimeEnvironment.application.getSystemService(DevicePolicyManager.class));
|
||||||
|
@@ -59,4 +59,14 @@ public class ShadowLockPatternUtils {
|
|||||||
public static void setDeviceEncryptionEnabled(boolean deviceEncryptionEnabled) {
|
public static void setDeviceEncryptionEnabled(boolean deviceEncryptionEnabled) {
|
||||||
sDeviceEncryptionEnabled = deviceEncryptionEnabled;
|
sDeviceEncryptionEnabled = deviceEncryptionEnabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Implementation
|
||||||
|
protected byte[] getPasswordHistoryHashFactor(String currentPassword, int userId) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Implementation
|
||||||
|
protected boolean checkPasswordHistory(String passwordToCheck, byte[] hashFactor, int userId) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,66 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2019 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.android.settings.testutils.shadow;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.os.IBinder;
|
||||||
|
|
||||||
|
import com.android.settings.password.PasswordUtils;
|
||||||
|
|
||||||
|
import org.robolectric.annotation.Implementation;
|
||||||
|
import org.robolectric.annotation.Implements;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
@Implements(PasswordUtils.class)
|
||||||
|
public class ShadowPasswordUtils {
|
||||||
|
|
||||||
|
private static String sCallingAppLabel;
|
||||||
|
private static Set<String> sGrantedPermissions;
|
||||||
|
|
||||||
|
public static void reset() {
|
||||||
|
sCallingAppLabel = null;
|
||||||
|
sGrantedPermissions = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Implementation
|
||||||
|
protected static boolean isCallingAppPermitted(Context context, IBinder activityToken,
|
||||||
|
String permission) {
|
||||||
|
if (sGrantedPermissions == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return sGrantedPermissions.contains(permission);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void addGrantedPermission(String... permissions) {
|
||||||
|
if (sGrantedPermissions == null) {
|
||||||
|
sGrantedPermissions = new HashSet<>();
|
||||||
|
}
|
||||||
|
sGrantedPermissions.addAll(Arrays.asList(permissions));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Implementation
|
||||||
|
protected static String getCallingAppLabel(Context context, IBinder activityToken) {
|
||||||
|
return sCallingAppLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void setCallingAppLabel(String label) {
|
||||||
|
sCallingAppLabel = label;
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user