When an app that has the permission GET_AND_REQUEST_PASSWORD_COMPLEXITY
launches ACTION_SET_NEW_PASSWORD, it can use the DPM PASSWORD_COMPLEXITY_*
constants to specify the complexity it wants in a new extra
EXTRA_PASSWORD_COMPLEXITY.
The screen lock type picker would then filter out the options which
cannot fulfil the min complexity (and DPM restrictions) and will show a
footer with a brief description of the calling app and the requested type.
The same password requirements UI is used in ChooseLockPassword screen
to display the minimum requirements that can fulfil both DPM
restrictions and the min complexity.
The app must have permission GET_AND_REQUEST_PASSWORD_COMPLEXITY
otherwise the extra would be ignored.
ACTION_SET_NEW_PASSWORD is also updated to always display the calling app
name in the screen lock type picker if it is not launched by Settings,
with or without the new extra.
Bug: 111173457
Test: atest packages/apps/Settings/tests/robotests/src/com/android/settings/password/ChooseLockGenericControllerTest.java
atest packages/apps/Settings/tests/robotests/src/com/android/settings/password/ChooseLockGenericTest.java
atest packages/apps/Settings/tests/robotests/src/com/android/settings/password/ChooseLockPasswordTest.java
atest packages/apps/Settings/tests/robotests/src/com/android/settings/password/PasswordUtilsTest.java
atest packages/apps/Settings/tests/robotests/src/com/android/settings/password/SetNewPasswordActivityTest.java
atest packages/apps/Settings/tests/robotests/src/com/android/settings/password/SetupChooseLockGenericTest.java
manual test with TestDpc (ag/5901733)
Change-Id: I21a25d28669bf1223c3b02ba85c0755e59feee2e
184 lines
7.1 KiB
Java
184 lines
7.1 KiB
Java
/*
|
|
* Copyright (C) 2017 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.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_NONE;
|
|
|
|
import android.app.admin.DevicePolicyManager;
|
|
import android.app.admin.DevicePolicyManager.PasswordComplexity;
|
|
import android.app.admin.PasswordMetrics;
|
|
import android.content.Context;
|
|
import android.os.UserHandle;
|
|
|
|
import androidx.annotation.NonNull;
|
|
import androidx.annotation.VisibleForTesting;
|
|
|
|
import com.android.settings.R;
|
|
|
|
import java.util.ArrayList;
|
|
import java.util.List;
|
|
|
|
/**
|
|
* A controller for ChooseLockGeneric, and other similar classes which shows a list of possible
|
|
* screen locks for the user to choose from.
|
|
*/
|
|
public class ChooseLockGenericController {
|
|
|
|
private final Context mContext;
|
|
private final int mUserId;
|
|
@PasswordComplexity private final int mRequestedMinComplexity;
|
|
private ManagedLockPasswordProvider mManagedPasswordProvider;
|
|
private DevicePolicyManager mDpm;
|
|
|
|
public ChooseLockGenericController(Context context, int userId) {
|
|
this(
|
|
context,
|
|
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),
|
|
ManagedLockPasswordProvider.get(context, userId));
|
|
}
|
|
|
|
@VisibleForTesting
|
|
ChooseLockGenericController(
|
|
Context context,
|
|
int userId,
|
|
@PasswordComplexity int requestedMinComplexity,
|
|
DevicePolicyManager dpm,
|
|
ManagedLockPasswordProvider managedLockPasswordProvider) {
|
|
mContext = context;
|
|
mUserId = userId;
|
|
mRequestedMinComplexity = requestedMinComplexity;
|
|
mManagedPasswordProvider = managedLockPasswordProvider;
|
|
mDpm = dpm;
|
|
}
|
|
|
|
/**
|
|
* Returns the highest quality among the specified {@code quality}, the quality required by
|
|
* {@link DevicePolicyManager#getPasswordQuality}, and the quality required by min password
|
|
* complexity.
|
|
*/
|
|
public int upgradeQuality(int quality) {
|
|
// Compare specified quality and dpm quality
|
|
int dpmUpgradedQuality = Math.max(quality, mDpm.getPasswordQuality(null, mUserId));
|
|
return Math.max(dpmUpgradedQuality,
|
|
PasswordMetrics.complexityLevelToMinQuality(mRequestedMinComplexity));
|
|
}
|
|
|
|
/**
|
|
* Whether the given screen lock type should be visible in the given context.
|
|
*/
|
|
public boolean isScreenLockVisible(ScreenLockType type) {
|
|
final boolean managedProfile = mUserId != UserHandle.myUserId();
|
|
switch (type) {
|
|
case NONE:
|
|
return !mContext.getResources().getBoolean(R.bool.config_hide_none_security_option)
|
|
&& !managedProfile; // Profiles should use unified challenge instead.
|
|
case SWIPE:
|
|
return !mContext.getResources().getBoolean(R.bool.config_hide_swipe_security_option)
|
|
&& !managedProfile; // Swipe doesn't make sense for profiles.
|
|
case MANAGED:
|
|
return mManagedPasswordProvider.isManagedPasswordChoosable();
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Whether screen lock with {@code type} should be enabled.
|
|
*
|
|
* @param type The screen lock type.
|
|
* @param quality The minimum required quality. This can either be requirement by device policy
|
|
* manager or because some flow only makes sense with secure lock screens.
|
|
*/
|
|
public boolean isScreenLockEnabled(ScreenLockType type, int quality) {
|
|
return type.maxQuality >= quality;
|
|
}
|
|
|
|
/**
|
|
* Whether screen lock with {@code type} is disabled by device policy admin.
|
|
*
|
|
* @param type The screen lock type.
|
|
* @param adminEnforcedQuality The minimum quality that the admin enforces.
|
|
*/
|
|
public boolean isScreenLockDisabledByAdmin(ScreenLockType type, int adminEnforcedQuality) {
|
|
boolean disabledByAdmin = type.maxQuality < adminEnforcedQuality;
|
|
if (type == ScreenLockType.MANAGED) {
|
|
disabledByAdmin = disabledByAdmin
|
|
|| !mManagedPasswordProvider.isManagedPasswordChoosable();
|
|
}
|
|
return disabledByAdmin;
|
|
}
|
|
|
|
/**
|
|
* User friendly title for the given screen lock type.
|
|
*/
|
|
public CharSequence getTitle(ScreenLockType type) {
|
|
switch (type) {
|
|
case NONE:
|
|
return mContext.getText(R.string.unlock_set_unlock_off_title);
|
|
case SWIPE:
|
|
return mContext.getText(R.string.unlock_set_unlock_none_title);
|
|
case PATTERN:
|
|
return mContext.getText(R.string.unlock_set_unlock_pattern_title);
|
|
case PIN:
|
|
return mContext.getText(R.string.unlock_set_unlock_pin_title);
|
|
case PASSWORD:
|
|
return mContext.getText(R.string.unlock_set_unlock_password_title);
|
|
case MANAGED:
|
|
return mManagedPasswordProvider.getPickerOptionTitle(false);
|
|
}
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Gets a list of screen locks that should be visible for the given quality. The returned list
|
|
* is ordered in the natural order of the enum (the order those enums were defined).
|
|
*
|
|
* @param quality The minimum quality required in the context of the current flow. This should
|
|
* be one of the constants defined in
|
|
* {@code DevicePolicyManager#PASSWORD_QUALITY_*}.
|
|
* @param includeDisabled Whether to include screen locks disabled by {@code quality}
|
|
* requirements in the returned list.
|
|
*/
|
|
@NonNull
|
|
public List<ScreenLockType> getVisibleScreenLockTypes(int quality, boolean includeDisabled) {
|
|
int upgradedQuality = upgradeQuality(quality);
|
|
List<ScreenLockType> locks = new ArrayList<>();
|
|
// EnumSet's iterator guarantees the natural order of the enums
|
|
for (ScreenLockType lock : ScreenLockType.values()) {
|
|
if (isScreenLockVisible(lock)) {
|
|
if (includeDisabled || isScreenLockEnabled(lock, upgradedQuality)) {
|
|
locks.add(lock);
|
|
}
|
|
}
|
|
}
|
|
return locks;
|
|
}
|
|
}
|