1 /* 2 * Copyright (C) 2023 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.activeunlock; 18 19 import android.content.Context; 20 21 import androidx.annotation.NonNull; 22 import androidx.annotation.Nullable; 23 import androidx.lifecycle.Lifecycle; 24 import androidx.lifecycle.LifecycleObserver; 25 import androidx.lifecycle.OnLifecycleEvent; 26 import androidx.preference.PreferenceScreen; 27 28 import com.android.settings.Utils; 29 import com.android.settings.biometrics.BiometricStatusPreferenceController; 30 import com.android.settings.biometrics.activeunlock.ActiveUnlockContentListener.OnContentChangedListener; 31 import com.android.settings.biometrics.combination.CombinedBiometricStatusUtils; 32 import com.android.settingslib.RestrictedPreference; 33 34 /** 35 * Preference controller for active unlock settings within the biometrics settings page, that 36 * controls the ability to unlock the phone with watch authentication. 37 */ 38 public class ActiveUnlockStatusPreferenceController 39 extends BiometricStatusPreferenceController implements LifecycleObserver { 40 /** 41 * Preference key. 42 * 43 * This must match the key found in security_settings_combined_biometric.xml 44 **/ 45 public static final String KEY_ACTIVE_UNLOCK_SETTINGS = "biometric_active_unlock_settings"; 46 @Nullable private RestrictedPreference mPreference; 47 @Nullable private PreferenceScreen mPreferenceScreen; 48 @Nullable private String mSummary; 49 private final ActiveUnlockStatusUtils mActiveUnlockStatusUtils; 50 private final CombinedBiometricStatusUtils mCombinedBiometricStatusUtils; 51 private final ActiveUnlockSummaryListener mActiveUnlockSummaryListener; 52 private final ActiveUnlockDeviceNameListener mActiveUnlockDeviceNameListener; 53 private final boolean mIsAvailable; 54 ActiveUnlockStatusPreferenceController(@onNull Context context)55 public ActiveUnlockStatusPreferenceController(@NonNull Context context) { 56 this(context, KEY_ACTIVE_UNLOCK_SETTINGS); 57 } 58 ActiveUnlockStatusPreferenceController( @onNull Context context, @NonNull String key)59 public ActiveUnlockStatusPreferenceController( 60 @NonNull Context context, @NonNull String key) { 61 super(context, key); 62 mActiveUnlockStatusUtils = new ActiveUnlockStatusUtils(context); 63 mIsAvailable = mActiveUnlockStatusUtils.isAvailable(); 64 mCombinedBiometricStatusUtils = new CombinedBiometricStatusUtils(context, getUserId()); 65 OnContentChangedListener onSummaryChangedListener = new OnContentChangedListener() { 66 @Override 67 public void onContentChanged(String newContent) { 68 mSummary = newContent; 69 if (mPreference != null) { 70 mPreference.setSummary(getSummaryText()); 71 } 72 } 73 }; 74 OnContentChangedListener onDeviceNameChangedListener = 75 new OnContentChangedListener() { 76 77 @Override 78 public void onContentChanged(String newContent) { 79 if (mPreference != null) { 80 mPreference.setSummary(getSummaryText()); 81 } 82 } 83 84 }; 85 mActiveUnlockSummaryListener = 86 new ActiveUnlockSummaryListener(context, onSummaryChangedListener); 87 mActiveUnlockDeviceNameListener = 88 new ActiveUnlockDeviceNameListener(context, onDeviceNameChangedListener); 89 } 90 91 92 /** Subscribes to update preference summary dynamically. */ 93 @OnLifecycleEvent(Lifecycle.Event.ON_START) onStart()94 public void onStart() { 95 if (mIsAvailable) { 96 mActiveUnlockSummaryListener.subscribe(); 97 mActiveUnlockDeviceNameListener.subscribe(); 98 } 99 } 100 101 /** Resets the preference reference on resume. */ 102 @OnLifecycleEvent(Lifecycle.Event.ON_RESUME) onResume()103 public void onResume() { 104 if (mPreferenceScreen != null) { 105 displayPreference(mPreferenceScreen); 106 } 107 } 108 109 /** Unsubscribes to prevent leaked listener. */ 110 @OnLifecycleEvent(Lifecycle.Event.ON_STOP) onStop()111 public void onStop() { 112 if (mIsAvailable) { 113 mActiveUnlockSummaryListener.unsubscribe(); 114 mActiveUnlockDeviceNameListener.unsubscribe(); 115 } 116 } 117 118 @Override displayPreference(PreferenceScreen screen)119 public void displayPreference(PreferenceScreen screen) { 120 super.displayPreference(screen); 121 mPreferenceScreen = screen; 122 mPreference = screen.findPreference(mPreferenceKey); 123 updateState(mPreference); 124 } 125 126 @Override getAvailabilityStatus()127 public int getAvailabilityStatus() { 128 return mActiveUnlockStatusUtils.getAvailability(); 129 } 130 131 @Override isDeviceSupported()132 protected boolean isDeviceSupported() { 133 // This should never be called, as getAvailabilityStatus() will return the exact value. 134 // However, this is an abstract method in BiometricStatusPreferenceController, and so 135 // needs to be overridden. 136 return mIsAvailable; 137 } 138 139 @Override isHardwareSupported()140 protected boolean isHardwareSupported() { 141 // This should never be called, as getAvailabilityStatus() will return the exact value. 142 // However, this is an abstract method in BiometricStatusPreferenceController, and so 143 // needs to be overridden. 144 return Utils.hasFaceHardware(mContext) || Utils.hasFingerprintHardware(mContext); 145 } 146 147 @Override getSummaryText()148 protected String getSummaryText() { 149 if (mActiveUnlockStatusUtils.useBiometricFailureLayout() 150 && !mActiveUnlockDeviceNameListener.hasEnrolled() 151 && !mCombinedBiometricStatusUtils.hasEnrolled()) { 152 @Nullable final String setupString = 153 mActiveUnlockStatusUtils.getSummaryWhenBiometricSetupRequired(); 154 if (setupString != null) { 155 return setupString; 156 } 157 } 158 if (mSummary == null) { 159 // return non-empty string to prevent re-sizing of the tile 160 return " "; 161 } 162 return mSummary; 163 } 164 165 @Override getSettingsClassName()166 protected String getSettingsClassName() { 167 return ActiveUnlockRequireBiometricSetup.class.getName(); 168 } 169 } 170