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.face; 18 19 import static android.hardware.biometrics.BiometricFaceConstants.FEATURE_REQUIRE_ATTENTION; 20 21 import android.content.Context; 22 import android.hardware.face.FaceManager; 23 import android.hardware.face.FaceManager.GetFeatureCallback; 24 import android.hardware.face.FaceManager.SetFeatureCallback; 25 import android.provider.Settings; 26 27 import androidx.annotation.Nullable; 28 import androidx.preference.Preference; 29 import androidx.preference.PreferenceScreen; 30 import androidx.preference.TwoStatePreference; 31 32 import com.android.settings.R; 33 import com.android.settings.Utils; 34 35 /** 36 * Preference controller that manages the ability to use face authentication with/without 37 * user attention. See {@link FaceManager#setRequireAttention(boolean, byte[])}. 38 */ 39 public class FaceSettingsAttentionPreferenceController extends FaceSettingsPreferenceController { 40 41 public static final String KEY = "security_settings_face_require_attention"; 42 43 private byte[] mToken; 44 private FaceManager mFaceManager; 45 private TwoStatePreference mPreference; 46 47 private final SetFeatureCallback mSetFeatureCallback = new SetFeatureCallback() { 48 @Override 49 public void onCompleted(boolean success, int feature) { 50 if (feature == FEATURE_REQUIRE_ATTENTION) { 51 mPreference.setEnabled(true); 52 if (!success) { 53 mPreference.setChecked(!mPreference.isChecked()); 54 } else { 55 Settings.Secure.putIntForUser(mContext.getContentResolver(), 56 Settings.Secure.FACE_UNLOCK_ATTENTION_REQUIRED, 57 mPreference.isChecked() ? 1 : 0, getUserId()); 58 } 59 } 60 } 61 }; 62 63 private final GetFeatureCallback mGetFeatureCallback = new GetFeatureCallback() { 64 @Override 65 public void onCompleted(boolean success, int[] features, boolean[] featureState) { 66 boolean requireAttentionEnabled = false; 67 for (int i = 0; i < features.length; i++) { 68 if (features[i] == FEATURE_REQUIRE_ATTENTION) { 69 requireAttentionEnabled = featureState[i]; 70 } 71 } 72 mPreference.setChecked(requireAttentionEnabled); 73 if (getRestrictingAdmin() != null) { 74 mPreference.setEnabled(false); 75 } else { 76 mPreference.setEnabled(success); 77 } 78 } 79 }; 80 FaceSettingsAttentionPreferenceController(Context context, String preferenceKey)81 public FaceSettingsAttentionPreferenceController(Context context, String preferenceKey) { 82 super(context, preferenceKey); 83 mFaceManager = Utils.getFaceManagerOrNull(context); 84 } 85 FaceSettingsAttentionPreferenceController(Context context)86 public FaceSettingsAttentionPreferenceController(Context context) { 87 this(context, KEY); 88 } 89 setToken(byte[] token)90 public void setToken(byte[] token) { 91 mToken = token; 92 } 93 94 /** 95 * Displays preference in this controller. 96 */ 97 @Override displayPreference(PreferenceScreen screen)98 public void displayPreference(PreferenceScreen screen) { 99 super.displayPreference(screen); 100 mPreference = screen.findPreference(KEY); 101 } 102 103 @Override updateState(@ullable Preference preference)104 public void updateState(@Nullable Preference preference) { 105 if (preference == null) { 106 return; 107 } 108 super.updateState(preference); 109 if (Utils.isPrivateProfile(getUserId(), mContext)) { 110 preference.setSummary(mContext.getString( 111 R.string.private_space_face_settings_require_attention_details)); 112 } 113 } 114 115 @Override isChecked()116 public boolean isChecked() { 117 if (!FaceSettings.isFaceHardwareDetected(mContext)) { 118 return true; 119 } 120 // Set to disabled until we know the true value. 121 mPreference.setEnabled(false); 122 mFaceManager.getFeature(getUserId(), FEATURE_REQUIRE_ATTENTION, 123 mGetFeatureCallback); 124 125 // Ideally returns a cached value. 126 return true; 127 } 128 129 @Override setChecked(boolean isChecked)130 public boolean setChecked(boolean isChecked) { 131 // Optimistically update state and set to disabled until we know it succeeded. 132 mPreference.setEnabled(false); 133 mPreference.setChecked(isChecked); 134 135 mFaceManager.setFeature(getUserId(), FEATURE_REQUIRE_ATTENTION, 136 isChecked, mToken, mSetFeatureCallback); 137 return true; 138 } 139 140 @Override getAvailabilityStatus()141 public int getAvailabilityStatus() { 142 return AVAILABLE; 143 } 144 } 145