Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 78edc210 authored by Yuri Ufimtsev's avatar Yuri Ufimtsev Committed by Android (Google) Code Review
Browse files

Merge "Move all the shared Screen Lock details into a reusable utility class"

parents acb88fb9 c10c16bb
Loading
Loading
Loading
Loading
+9 −61
Original line number Diff line number Diff line
@@ -16,40 +16,32 @@

package com.android.settings.security;

import android.app.admin.DevicePolicyManager;
import android.content.Context;
import android.os.UserHandle;
import android.os.UserManager;
import android.os.storage.StorageManager;
import android.text.TextUtils;

import androidx.preference.Preference;
import androidx.preference.PreferenceScreen;

import com.android.internal.widget.LockPatternUtils;
import com.android.settings.R;
import com.android.settings.SettingsPreferenceFragment;
import com.android.settings.Utils;
import com.android.settings.core.PreferenceControllerMixin;
import com.android.settings.core.SubSettingLauncher;
import com.android.settings.dashboard.DashboardFragment;
import com.android.settings.overlay.FeatureFactory;
import com.android.settings.password.ChooseLockGeneric;
import com.android.settings.security.screenlock.ScreenLockSettings;
import com.android.settings.widget.GearPreference;
import com.android.settingslib.RestrictedLockUtils;
import com.android.settingslib.RestrictedLockUtilsInternal;
import com.android.settingslib.RestrictedPreference;
import com.android.settingslib.core.AbstractPreferenceController;
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
import com.android.settingslib.transition.SettingsTransitionHelper;

public class ChangeScreenLockPreferenceController extends AbstractPreferenceController implements
        PreferenceControllerMixin, GearPreference.OnGearClickListener {

    private static final String KEY_UNLOCK_SET_OR_CHANGE = "unlock_set_or_change";

    protected final DevicePolicyManager mDPM;
    protected final SettingsPreferenceFragment mHost;
    protected final UserManager mUm;
    protected final LockPatternUtils mLockPatternUtils;
@@ -57,24 +49,26 @@ public class ChangeScreenLockPreferenceController extends AbstractPreferenceCont
    protected final int mUserId = UserHandle.myUserId();
    protected final int mProfileChallengeUserId;
    private final MetricsFeatureProvider mMetricsFeatureProvider;
    private final ScreenLockPreferenceDetailsUtils mScreenLockPreferenceDetailUtils;

    protected RestrictedPreference mPreference;

    public ChangeScreenLockPreferenceController(Context context, SettingsPreferenceFragment host) {
        super(context);
        mUm = (UserManager) context.getSystemService(Context.USER_SERVICE);
        mDPM = (DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE);
        mLockPatternUtils = FeatureFactory.getFactory(context)
                .getSecurityFeatureProvider()
                .getLockPatternUtils(context);
        mHost = host;
        mProfileChallengeUserId = Utils.getManagedProfileId(mUm, mUserId);
        mMetricsFeatureProvider = FeatureFactory.getFactory(context).getMetricsFeatureProvider();
        mScreenLockPreferenceDetailUtils =
                new ScreenLockPreferenceDetailsUtils(context, host.getMetricsCategory());
    }

    @Override
    public boolean isAvailable() {
        return mContext.getResources().getBoolean(R.bool.config_show_unlock_set_or_change);
        return mScreenLockPreferenceDetailUtils.isAvailable();
    }

    @Override
@@ -91,7 +85,7 @@ public class ChangeScreenLockPreferenceController extends AbstractPreferenceCont
    @Override
    public void updateState(Preference preference) {
        if (mPreference != null && mPreference instanceof GearPreference) {
            if (mLockPatternUtils.isSecure(mUserId)) {
            if (mScreenLockPreferenceDetailUtils.shouldShowGearMenu()) {
                ((GearPreference) mPreference).setOnGearClickListener(this);
            } else {
                ((GearPreference) mPreference).setOnGearClickListener(null);
@@ -112,10 +106,7 @@ public class ChangeScreenLockPreferenceController extends AbstractPreferenceCont
        if (TextUtils.equals(p.getKey(), getPreferenceKey())) {
            mMetricsFeatureProvider.logClickedPreference(p,
                    p.getExtras().getInt(DashboardFragment.CATEGORY));
            new SubSettingLauncher(mContext)
                    .setDestination(ScreenLockSettings.class.getName())
                    .setSourceMetricsCategory(mHost.getMetricsCategory())
                    .launch();
            mScreenLockPreferenceDetailUtils.openScreenLockSettings();
        }
    }

@@ -124,51 +115,11 @@ public class ChangeScreenLockPreferenceController extends AbstractPreferenceCont
        if (!TextUtils.equals(preference.getKey(), getPreferenceKey())) {
            return super.handlePreferenceTreeClick(preference);
        }
        // TODO(b/35930129): Remove once existing password can be passed into vold directly.
        // Currently we need this logic to ensure that the QUIET_MODE is off for any work
        // profile with unified challenge on FBE-enabled devices. Otherwise, vold would not be
        // able to complete the operation due to the lack of (old) encryption key.
        if (mProfileChallengeUserId != UserHandle.USER_NULL
                && !mLockPatternUtils.isSeparateProfileChallengeEnabled(mProfileChallengeUserId)
                && StorageManager.isFileEncryptedNativeOnly()) {
            if (Utils.startQuietModeDialogIfNecessary(mContext, mUm, mProfileChallengeUserId)) {
                return false;
            }
        }

        new SubSettingLauncher(mContext)
                .setDestination(ChooseLockGeneric.ChooseLockGenericFragment.class.getName())
                .setSourceMetricsCategory(mHost.getMetricsCategory())
                .setTransitionType(SettingsTransitionHelper.TransitionType.TRANSITION_SLIDE)
                .launch();
        return true;
        return mScreenLockPreferenceDetailUtils.openChooseLockGenericFragment();
    }

    protected void updateSummary(Preference preference, int userId) {
        if (!mLockPatternUtils.isSecure(userId)) {
            if (userId == mProfileChallengeUserId
                    || mLockPatternUtils.isLockScreenDisabled(userId)) {
                preference.setSummary(R.string.unlock_set_unlock_mode_off);
            } else {
                preference.setSummary(R.string.unlock_set_unlock_mode_none);
            }
        } else {
            switch (mLockPatternUtils.getKeyguardStoredPasswordQuality(userId)) {
                case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING:
                    preference.setSummary(R.string.unlock_set_unlock_mode_pattern);
                    break;
                case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC:
                case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX:
                    preference.setSummary(R.string.unlock_set_unlock_mode_pin);
                    break;
                case DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC:
                case DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC:
                case DevicePolicyManager.PASSWORD_QUALITY_COMPLEX:
                case DevicePolicyManager.PASSWORD_QUALITY_MANAGED:
                    preference.setSummary(R.string.unlock_set_unlock_mode_password);
                    break;
            }
        }
        preference.setSummary(mScreenLockPreferenceDetailUtils.getSummary(userId));
        mPreference.setEnabled(true);
    }

@@ -181,10 +132,7 @@ public class ChangeScreenLockPreferenceController extends AbstractPreferenceCont
    void disableIfPasswordQualityManaged(int userId) {
        final RestrictedLockUtils.EnforcedAdmin admin = RestrictedLockUtilsInternal
                .checkIfPasswordQualityIsSet(mContext, userId);
        final DevicePolicyManager dpm = (DevicePolicyManager) mContext
                .getSystemService(Context.DEVICE_POLICY_SERVICE);
        if (admin != null && dpm.getPasswordQuality(admin.component, userId)
                == DevicePolicyManager.PASSWORD_QUALITY_MANAGED) {
        if (mScreenLockPreferenceDetailUtils.isPasswordQualityManaged(userId, admin)) {
            mPreference.setDisabledByAdmin(admin);
        }
    }
+156 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2022 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.security;

import android.app.admin.DevicePolicyManager;
import android.content.Context;
import android.os.UserHandle;
import android.os.UserManager;
import android.os.storage.StorageManager;

import androidx.annotation.StringRes;

import com.android.internal.widget.LockPatternUtils;
import com.android.settings.R;
import com.android.settings.Utils;
import com.android.settings.core.SubSettingLauncher;
import com.android.settings.overlay.FeatureFactory;
import com.android.settings.password.ChooseLockGeneric.ChooseLockGenericFragment;
import com.android.settings.security.screenlock.ScreenLockSettings;
import com.android.settingslib.RestrictedLockUtils;
import com.android.settingslib.transition.SettingsTransitionHelper;

/**
 * Utilities for screen lock details shared between Security Settings and Safety Center.
 */
public class ScreenLockPreferenceDetailsUtils {

    private final int mUserId = UserHandle.myUserId();
    private final Context mContext;
    private final LockPatternUtils mLockPatternUtils;
    private final int mProfileChallengeUserId;
    private final UserManager mUm;
    private final int mSourceMetricsCategory;

    public ScreenLockPreferenceDetailsUtils(Context context, int sourceMetricsCategory) {
        mContext = context;
        mUm = context.getSystemService(UserManager.class);
        mLockPatternUtils = FeatureFactory.getFactory(context)
                .getSecurityFeatureProvider()
                .getLockPatternUtils(context);
        mProfileChallengeUserId = Utils.getManagedProfileId(mUm, mUserId);
        mSourceMetricsCategory = sourceMetricsCategory;
    }

    /**
     * Returns whether the screen lock settings entity should be shown.
     */
    public boolean isAvailable() {
        return mContext.getResources().getBoolean(R.bool.config_show_unlock_set_or_change);
    }

    /**
     * Returns the summary of screen lock settings entity.
     */
    public String getSummary(int userId) {
        final Integer summaryResId = getSummaryResId(userId);
        return summaryResId != null ? mContext.getResources().getString(summaryResId) : null;
    }

    /**
     * Returns whether the password quality is managed by device admin.
     */
    public boolean isPasswordQualityManaged(int userId, RestrictedLockUtils.EnforcedAdmin admin) {
        final DevicePolicyManager dpm = (DevicePolicyManager) mContext
                .getSystemService(Context.DEVICE_POLICY_SERVICE);
        return admin != null && dpm.getPasswordQuality(admin.component, userId)
                == DevicePolicyManager.PASSWORD_QUALITY_MANAGED;
    }

    /**
     * Returns whether the Gear Menu should be shown.
     */
    public boolean shouldShowGearMenu() {
        return mLockPatternUtils.isSecure(mUserId);
    }

    /**
     * Launches the {@link ScreenLockSettings}.
     */
    public void openScreenLockSettings() {
        new SubSettingLauncher(mContext)
                .setDestination(ScreenLockSettings.class.getName())
                .setSourceMetricsCategory(mSourceMetricsCategory)
                .launch();
    }

    /**
     * Tries to launch the {@link ChooseLockGenericFragment} if Quiet Mode is not enabled
     * for managed profile, otherwise shows a dialog to disable the Quiet Mode.
     *
     * @return true if the {@link ChooseLockGenericFragment} is launching.
     */
    public boolean openChooseLockGenericFragment() {
        // TODO(b/35930129): Remove once existing password can be passed into vold directly.
        // Currently we need this logic to ensure that the QUIET_MODE is off for any work
        // profile with unified challenge on FBE-enabled devices. Otherwise, vold would not be
        // able to complete the operation due to the lack of (old) encryption key.
        if (mProfileChallengeUserId != UserHandle.USER_NULL
                && !mLockPatternUtils.isSeparateProfileChallengeEnabled(mProfileChallengeUserId)
                && StorageManager.isFileEncryptedNativeOnly()) {
            if (Utils.startQuietModeDialogIfNecessary(mContext, mUm, mProfileChallengeUserId)) {
                return false;
            }
        }

        new SubSettingLauncher(mContext)
                .setDestination(ChooseLockGenericFragment.class.getName())
                .setSourceMetricsCategory(mSourceMetricsCategory)
                .setTransitionType(SettingsTransitionHelper.TransitionType.TRANSITION_SLIDE)
                .launch();
        return true;
    }

    @StringRes
    private Integer getSummaryResId(int userId) {
        if (!mLockPatternUtils.isSecure(userId)) {
            if (userId == mProfileChallengeUserId
                    || mLockPatternUtils.isLockScreenDisabled(userId)) {
                return R.string.unlock_set_unlock_mode_off;
            } else {
                return R.string.unlock_set_unlock_mode_none;
            }
        } else {
            int keyguardStoredPasswordQuality =
                    mLockPatternUtils.getKeyguardStoredPasswordQuality(userId);
            switch (keyguardStoredPasswordQuality) {
                case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING:
                    return R.string.unlock_set_unlock_mode_pattern;
                case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC:
                case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX:
                    return R.string.unlock_set_unlock_mode_pin;
                case DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC:
                case DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC:
                case DevicePolicyManager.PASSWORD_QUALITY_COMPLEX:
                case DevicePolicyManager.PASSWORD_QUALITY_MANAGED:
                    return R.string.unlock_set_unlock_mode_password;
                default:
                    return null;
            }
        }
    }
}
+7 −1
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;

@@ -35,6 +36,7 @@ import androidx.preference.PreferenceViewHolder;

import com.android.internal.widget.LockPatternUtils;
import com.android.settings.R;
import com.android.settings.SettingsPreferenceFragment;
import com.android.settings.testutils.FakeFeatureFactory;
import com.android.settings.testutils.shadow.ShadowUtils;
import com.android.settings.widget.GearPreference;
@@ -54,6 +56,8 @@ import org.robolectric.annotation.Config;
@Ignore
public class ChangeScreenLockPreferenceControllerTest {

    private static final int METRICS_CATEGORY = 1;

    @Mock
    private LockPatternUtils mLockPatternUtils;
    @Mock
@@ -80,7 +84,9 @@ public class ChangeScreenLockPreferenceControllerTest {
        when(mContext.getSystemService(Context.USER_SERVICE)).thenReturn(mUserManager);
        when(mContext.getSystemService(Context.DEVICE_POLICY_SERVICE))
                .thenReturn(mDevicePolicyManager);
        mController = new ChangeScreenLockPreferenceController(mContext, null  /* Host */ );
        final SettingsPreferenceFragment host = mock(SettingsPreferenceFragment.class);
        when(host.getMetricsCategory()).thenReturn(METRICS_CATEGORY);
        mController = new ChangeScreenLockPreferenceController(mContext, host);
    }

    @Test
+310 −0

File added.

Preview size limit exceeded, changes collapsed.