ronnie
2022-10-23 eadd9db01b24ccde96a129dafa989d4ec436cdfd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
/*
 * Copyright (C) 2016 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.ACTION_SET_NEW_PASSWORD;
import static android.app.admin.DevicePolicyManager.KEYGUARD_DISABLE_FACE;
import static android.app.admin.DevicePolicyManager.KEYGUARD_DISABLE_FINGERPRINT;
import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_SOMETHING;
 
import static com.android.internal.util.Preconditions.checkNotNull;
 
import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.admin.DevicePolicyManager;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.hardware.face.FaceManager;
import android.hardware.fingerprint.FingerprintManager;
import android.os.Bundle;
import android.os.IBinder;
import android.os.UserManager;
 
import androidx.annotation.VisibleForTesting;
 
import com.android.internal.widget.LockPatternUtils;
import com.android.settings.Utils;
 
/**
 * Business logic for {@link SetNewPasswordActivity}.
 *
 * <p>On devices that supports fingerprint, this controller directs the user to configure
 * fingerprint + a backup password if the device admin allows fingerprint for keyguard and
 * the user has never configured a fingerprint before.
 */
final class SetNewPasswordController {
 
    interface Ui {
        /** Starts the {@link ChooseLockGeneric} activity with the given extras. */
        void launchChooseLock(Bundle chooseLockFingerprintExtras);
    }
 
    /**
     * Which user is setting new password.
     */
    private final int mTargetUserId;
    private final PackageManager mPackageManager;
    @Nullable
    private final FingerprintManager mFingerprintManager;
    @Nullable
    private final FaceManager mFaceManager;
    private final DevicePolicyManager mDevicePolicyManager;
    private final Ui mUi;
 
    public static SetNewPasswordController create(Context context, Ui ui, Intent intent,
            IBinder activityToken) {
        // Trying to figure out which user is setting new password. If it is
        // ACTION_SET_NEW_PARENT_PROFILE_PASSWORD or the calling user is not allowed to set
        // separate profile challenge, it is the current user to set new password. Otherwise,
        // it is the user who starts this activity setting new password.
        int userId = ActivityManager.getCurrentUser();
        if (ACTION_SET_NEW_PASSWORD.equals(intent.getAction())) {
            final int callingUserId = Utils.getSecureTargetUser(activityToken,
                    UserManager.get(context), null, intent.getExtras()).getIdentifier();
            final LockPatternUtils lockPatternUtils = new LockPatternUtils(context);
            if (lockPatternUtils.isSeparateProfileChallengeAllowed(callingUserId)) {
                userId = callingUserId;
            }
        }
        // Create a wrapper of FingerprintManager for testing, see IFingerPrintManager for details.
        final FingerprintManager fingerprintManager = Utils.getFingerprintManagerOrNull(context);
        final FaceManager faceManager = Utils.getFaceManagerOrNull(context);
        return new SetNewPasswordController(userId,
                context.getPackageManager(),
                fingerprintManager, faceManager,
                (DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE), ui);
    }
 
    @VisibleForTesting
    SetNewPasswordController(
            int targetUserId,
            PackageManager packageManager,
            FingerprintManager fingerprintManager,
            FaceManager faceManager,
            DevicePolicyManager devicePolicyManager,
            Ui ui) {
        mTargetUserId = targetUserId;
        mPackageManager = checkNotNull(packageManager);
        mFingerprintManager = fingerprintManager;
        mFaceManager = faceManager;
        mDevicePolicyManager = checkNotNull(devicePolicyManager);
        mUi = checkNotNull(ui);
    }
 
    /**
     * Dispatches the set new password intent to the correct activity that handles it.
     */
    public void dispatchSetNewPasswordIntent() {
        final Bundle extras;
        // TODO: handle the case with multiple biometrics, perhaps take an arg for biometric type?
        if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_FACE)
                && mFaceManager != null
                && mFaceManager.isHardwareDetected()
                && !mFaceManager.hasEnrolledTemplates(mTargetUserId)
                && !isFaceDisabledByAdmin()) {
            extras = getFaceChooseLockExtras();
        } else if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)
                && mFingerprintManager != null
                && mFingerprintManager.isHardwareDetected()
                && !mFingerprintManager.hasEnrolledFingerprints(mTargetUserId)
                && !isFingerprintDisabledByAdmin()) {
            extras = getFingerprintChooseLockExtras();
        } else {
            extras = new Bundle();
        }
        // No matter we show fingerprint options or not, we should tell the next activity which
        // user is setting new password.
        extras.putInt(Intent.EXTRA_USER_ID, mTargetUserId);
        mUi.launchChooseLock(extras);
    }
 
    private Bundle getFingerprintChooseLockExtras() {
        Bundle chooseLockExtras = new Bundle();
        long challenge = mFingerprintManager.preEnroll();
        chooseLockExtras.putInt(ChooseLockGeneric.ChooseLockGenericFragment.MINIMUM_QUALITY_KEY,
                PASSWORD_QUALITY_SOMETHING);
        chooseLockExtras.putBoolean(
                ChooseLockGeneric.ChooseLockGenericFragment.HIDE_DISABLED_PREFS, true);
        chooseLockExtras.putBoolean(ChooseLockSettingsHelper.EXTRA_KEY_HAS_CHALLENGE, true);
        chooseLockExtras.putLong(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE, challenge);
        chooseLockExtras.putBoolean(ChooseLockSettingsHelper.EXTRA_KEY_FOR_FINGERPRINT, true);
        return chooseLockExtras;
    }
 
    private Bundle getFaceChooseLockExtras() {
        Bundle chooseLockExtras = new Bundle();
        long challenge = mFaceManager.generateChallenge();
        chooseLockExtras.putInt(ChooseLockGeneric.ChooseLockGenericFragment.MINIMUM_QUALITY_KEY,
                PASSWORD_QUALITY_SOMETHING);
        chooseLockExtras.putBoolean(
                ChooseLockGeneric.ChooseLockGenericFragment.HIDE_DISABLED_PREFS, true);
        chooseLockExtras.putBoolean(ChooseLockSettingsHelper.EXTRA_KEY_HAS_CHALLENGE, true);
        chooseLockExtras.putLong(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE, challenge);
        chooseLockExtras.putBoolean(ChooseLockSettingsHelper.EXTRA_KEY_FOR_FACE, true);
        return chooseLockExtras;
    }
 
    private boolean isFingerprintDisabledByAdmin() {
        int disabledFeatures =
                mDevicePolicyManager.getKeyguardDisabledFeatures(null, mTargetUserId);
        return (disabledFeatures & KEYGUARD_DISABLE_FINGERPRINT) != 0;
    }
 
    private boolean isFaceDisabledByAdmin() {
        int disabledFeatures =
                mDevicePolicyManager.getKeyguardDisabledFeatures(null, mTargetUserId);
        return (disabledFeatures & KEYGUARD_DISABLE_FACE) != 0;
    }
}