1 /*
2  * Copyright (C) 2018 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 
17 package com.android.settings.biometrics;
18 
19 import android.content.Context;
20 import android.content.Intent;
21 import android.os.UserHandle;
22 import android.os.UserManager;
23 import android.text.TextUtils;
24 
25 import androidx.activity.result.ActivityResultLauncher;
26 import androidx.annotation.NonNull;
27 import androidx.annotation.Nullable;
28 import androidx.preference.Preference;
29 
30 import com.android.internal.widget.LockPatternUtils;
31 import com.android.settings.Utils;
32 import com.android.settings.biometrics.activeunlock.ActiveUnlockStatusUtils;
33 import com.android.settings.core.BasePreferenceController;
34 import com.android.settings.overlay.FeatureFactory;
35 
36 import java.lang.ref.WeakReference;
37 
38 public abstract class BiometricStatusPreferenceController extends BasePreferenceController {
39 
40     protected final UserManager mUm;
41     protected final LockPatternUtils mLockPatternUtils;
42 
43     private final int mUserId = UserHandle.myUserId();
44     protected final int mProfileChallengeUserId;
45 
46     private final BiometricNavigationUtils mBiometricNavigationUtils;
47     private final ActiveUnlockStatusUtils mActiveUnlockStatusUtils;
48     @NonNull private WeakReference<ActivityResultLauncher<Intent>> mLauncherWeakReference =
49             new WeakReference<>(null);
50 
51     /**
52      * @return true if the controller should be shown exclusively.
53      */
isDeviceSupported()54     protected abstract boolean isDeviceSupported();
55 
56     /**
57      * @return true if the manager is not null and the hardware is detected.
58      */
isHardwareSupported()59     protected abstract boolean isHardwareSupported();
60 
61     /**
62      * @return the summary text.
63      */
getSummaryText()64     protected abstract String getSummaryText();
65 
66     /**
67      * @return the class name for the settings page.
68      */
getSettingsClassName()69     protected abstract String getSettingsClassName();
70 
BiometricStatusPreferenceController(Context context, String key)71     public BiometricStatusPreferenceController(Context context, String key) {
72         super(context, key);
73         mUm = (UserManager) context.getSystemService(Context.USER_SERVICE);
74         mLockPatternUtils = FeatureFactory.getFeatureFactory()
75                 .getSecurityFeatureProvider()
76                 .getLockPatternUtils(context);
77         mProfileChallengeUserId = Utils.getManagedProfileId(mUm, mUserId);
78         mBiometricNavigationUtils = new BiometricNavigationUtils(getUserId());
79         mActiveUnlockStatusUtils = new ActiveUnlockStatusUtils(context);
80     }
81 
82     @Override
getAvailabilityStatus()83     public int getAvailabilityStatus() {
84         if (mActiveUnlockStatusUtils.isAvailable()) {
85             return getAvailabilityStatusWithWorkProfileCheck();
86         }
87         if (!isDeviceSupported()) {
88             return UNSUPPORTED_ON_DEVICE;
89         }
90         return getAvailabilityFromUserSupported();
91     }
92 
getAvailabilityFromUserSupported()93     private int getAvailabilityFromUserSupported() {
94         if (isUserSupported()) {
95             return AVAILABLE;
96         } else {
97             return DISABLED_FOR_USER;
98         }
99     }
100 
101     // Since this code is flag guarded by mActiveUnlockStatusUtils.isAvailable(), we don't need to
102     // do another check here.
getAvailabilityStatusWithWorkProfileCheck()103     private int getAvailabilityStatusWithWorkProfileCheck() {
104         if (!isHardwareSupported()) {
105             // no hardware, never show
106             return UNSUPPORTED_ON_DEVICE;
107         }
108         if (!isDeviceSupported() && isWorkProfileController()) {
109             // hardware supported but work profile, don't show
110             return UNSUPPORTED_ON_DEVICE;
111         }
112         // hardware supported, not work profile, active unlock enabled
113         return getAvailabilityFromUserSupported();
114     }
115 
116     @Override
updateState(Preference preference)117     public void updateState(Preference preference) {
118         if (!isAvailable()) {
119             if (preference != null) {
120                 preference.setVisible(false);
121             }
122             return;
123         } else {
124             preference.setVisible(true);
125         }
126         preference.setSummary(getSummaryText());
127     }
128 
129     /**
130      * Set ActivityResultLauncher that will be used later during handlePreferenceTreeClick()
131      *
132      * @param preference the preference being compared
133      * @param launcher the ActivityResultLauncher
134      * @return {@code true} if matched preference.
135      */
setPreferenceTreeClickLauncher(@onNull Preference preference, @Nullable ActivityResultLauncher<Intent> launcher)136     public boolean setPreferenceTreeClickLauncher(@NonNull Preference preference,
137             @Nullable ActivityResultLauncher<Intent> launcher) {
138         if (!TextUtils.equals(preference.getKey(), getPreferenceKey())) {
139             return false;
140         }
141 
142         mLauncherWeakReference = new WeakReference<>(launcher);
143         return true;
144     }
145 
146     @Override
handlePreferenceTreeClick(Preference preference)147     public boolean handlePreferenceTreeClick(Preference preference) {
148         if (!TextUtils.equals(preference.getKey(), getPreferenceKey())) {
149             return super.handlePreferenceTreeClick(preference);
150         }
151 
152         return mBiometricNavigationUtils.launchBiometricSettings(preference.getContext(),
153                 getSettingsClassName(), preference.getExtras(), mLauncherWeakReference.get());
154     }
155 
getUserId()156     protected int getUserId() {
157         return mUserId;
158     }
159 
isUserSupported()160     protected boolean isUserSupported() {
161         return true;
162     }
163 
164     /**
165      * Returns true if the controller controls is used for work profile.
166      */
isWorkProfileController()167     protected boolean isWorkProfileController() {
168         return false;
169     }
170 }
171