1/*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.settings.password;
18
19import static android.app.admin.DevicePolicyManager.ACTION_SET_NEW_PASSWORD;
20import static android.app.admin.DevicePolicyManager.KEYGUARD_DISABLE_FINGERPRINT;
21import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_SOMETHING;
22import static com.android.internal.util.Preconditions.checkNotNull;
23
24import android.annotation.Nullable;
25import android.app.ActivityManager;
26import android.app.admin.DevicePolicyManager;
27import android.content.Context;
28import android.content.Intent;
29import android.content.pm.PackageManager;
30import android.hardware.fingerprint.FingerprintManager;
31import android.os.Bundle;
32import android.os.IBinder;
33import android.os.UserManager;
34
35import com.android.internal.annotations.VisibleForTesting;
36import com.android.internal.widget.LockPatternUtils;
37import com.android.settings.ChooseLockGeneric;
38import com.android.settings.ChooseLockSettingsHelper;
39import com.android.settings.Utils;
40
41/**
42 * Business logic for {@link SetNewPasswordActivity}.
43 *
44 * <p>On devices that supports fingerprint, this controller directs the user to configure
45 * fingerprint + a backup password if the device admin allows fingerprint for keyguard and
46 * the user has never configured a fingerprint before.
47 */
48final class SetNewPasswordController {
49
50    interface Ui {
51        /** Starts the {@link ChooseLockGeneric} activity with the given extras. */
52        void launchChooseLock(Bundle chooseLockFingerprintExtras);
53    }
54
55    /**
56     * Which user is setting new password.
57     */
58    private final int mTargetUserId;
59    private final PackageManager mPackageManager;
60    @Nullable private final IFingerprintManager mFingerprintManager;
61    private final DevicePolicyManager mDevicePolicyManager;
62    private final Ui mUi;
63
64    public static SetNewPasswordController create(Context context, Ui ui, Intent intent,
65            IBinder activityToken) {
66        // Trying to figure out which user is setting new password. If it is
67        // ACTION_SET_NEW_PARENT_PROFILE_PASSWORD or the calling user is not allowed to set
68        // separate profile challenge, it is the current user to set new password. Otherwise,
69        // it is the user who starts this activity setting new password.
70        int userId = ActivityManager.getCurrentUser();
71        if (ACTION_SET_NEW_PASSWORD.equals(intent.getAction())) {
72            final int callingUserId = Utils.getSecureTargetUser(activityToken,
73                    UserManager.get(context), null, intent.getExtras()).getIdentifier();
74            final LockPatternUtils lockPatternUtils = new LockPatternUtils(context);
75            if (lockPatternUtils.isSeparateProfileChallengeAllowed(callingUserId)) {
76                userId = callingUserId;
77            }
78        }
79        // Create a wrapper of FingerprintManager for testing, see IFingerPrintManager for details.
80        final FingerprintManager fingerprintManager =
81                (FingerprintManager) context.getSystemService(Context.FINGERPRINT_SERVICE);
82        final IFingerprintManager fingerprintManagerWrapper =
83                fingerprintManager == null
84                        ? null
85                        : new FingerprintManagerWrapper(fingerprintManager);
86        return new SetNewPasswordController(userId,
87                context.getPackageManager(),
88                fingerprintManagerWrapper,
89                (DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE), ui);
90    }
91
92    @VisibleForTesting
93    SetNewPasswordController(
94            int targetUserId,
95            PackageManager packageManager,
96            IFingerprintManager fingerprintManager,
97            DevicePolicyManager devicePolicyManager,
98            Ui ui) {
99        mTargetUserId = targetUserId;
100        mPackageManager = checkNotNull(packageManager);
101        mFingerprintManager = fingerprintManager;
102        mDevicePolicyManager = checkNotNull(devicePolicyManager);
103        mUi = checkNotNull(ui);
104    }
105
106    /**
107     * Dispatches the set new password intent to the correct activity that handles it.
108     */
109    public void dispatchSetNewPasswordIntent() {
110        final Bundle extras;
111        if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)
112                && mFingerprintManager != null
113                && mFingerprintManager.isHardwareDetected()
114                && !mFingerprintManager.hasEnrolledFingerprints(mTargetUserId)
115                && !isFingerprintDisabledByAdmin()) {
116            extras = getFingerprintChooseLockExtras();
117        } else {
118            extras = new Bundle();
119        }
120        // No matter we show fingerprint options or not, we should tell the next activity which
121        // user is setting new password.
122        extras.putInt(Intent.EXTRA_USER_ID, mTargetUserId);
123        mUi.launchChooseLock(extras);
124    }
125
126    private Bundle getFingerprintChooseLockExtras() {
127        Bundle chooseLockExtras = new Bundle();
128        long challenge = mFingerprintManager.preEnroll();
129        chooseLockExtras.putInt(ChooseLockGeneric.ChooseLockGenericFragment.MINIMUM_QUALITY_KEY,
130                PASSWORD_QUALITY_SOMETHING);
131        chooseLockExtras.putBoolean(
132                ChooseLockGeneric.ChooseLockGenericFragment.HIDE_DISABLED_PREFS, true);
133        chooseLockExtras.putBoolean(ChooseLockSettingsHelper.EXTRA_KEY_HAS_CHALLENGE, true);
134        chooseLockExtras.putLong(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE, challenge);
135        chooseLockExtras.putBoolean(ChooseLockSettingsHelper.EXTRA_KEY_FOR_FINGERPRINT, true);
136        return chooseLockExtras;
137    }
138
139    private boolean isFingerprintDisabledByAdmin() {
140        int disabledFeatures =
141                mDevicePolicyManager.getKeyguardDisabledFeatures(null, mTargetUserId);
142        return (disabledFeatures & KEYGUARD_DISABLE_FINGERPRINT) != 0;
143    }
144}
145