• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 android.app.AlertDialog;
20 import android.app.Dialog;
21 import android.app.settings.SettingsEnums;
22 import android.content.Context;
23 import android.content.DialogInterface;
24 import android.hardware.face.Face;
25 import android.hardware.face.FaceManager;
26 import android.os.Bundle;
27 import android.util.Log;
28 import android.view.View;
29 import android.widget.Button;
30 import android.widget.Toast;
31 
32 import androidx.preference.Preference;
33 
34 import com.android.settings.R;
35 import com.android.settings.SettingsActivity;
36 import com.android.settings.core.BasePreferenceController;
37 import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
38 import com.android.settings.overlay.FeatureFactory;
39 import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
40 import com.android.settingslib.widget.LayoutPreference;
41 
42 import com.google.android.setupdesign.util.ButtonStyler;
43 import com.google.android.setupdesign.util.PartnerStyleHelper;
44 
45 import java.util.List;
46 
47 /**
48  * Controller for the remove button. This assumes that there is only a single face enrolled. The UI
49  * will likely change if multiple enrollments are allowed/supported.
50  */
51 public class FaceSettingsRemoveButtonPreferenceController extends BasePreferenceController
52         implements View.OnClickListener {
53 
54     private static final String TAG = "FaceSettings/Remove";
55     static final String KEY = "security_settings_face_delete_faces_container";
56 
57     public static class ConfirmRemoveDialog extends InstrumentedDialogFragment {
58 
59         private DialogInterface.OnClickListener mOnClickListener;
60 
61         @Override
getMetricsCategory()62         public int getMetricsCategory() {
63             return SettingsEnums.DIALOG_FACE_REMOVE;
64         }
65 
66         @Override
onCreateDialog(Bundle savedInstanceState)67         public Dialog onCreateDialog(Bundle savedInstanceState) {
68             AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
69 
70             builder.setTitle(R.string.security_settings_face_settings_remove_dialog_title)
71                     .setMessage(R.string.security_settings_face_settings_remove_dialog_details)
72                     .setPositiveButton(R.string.delete, mOnClickListener)
73                     .setNegativeButton(R.string.cancel, mOnClickListener);
74             AlertDialog dialog = builder.create();
75             dialog.setCanceledOnTouchOutside(false);
76             return dialog;
77         }
78 
setOnClickListener(DialogInterface.OnClickListener listener)79         public void setOnClickListener(DialogInterface.OnClickListener listener) {
80             mOnClickListener = listener;
81         }
82     }
83 
84     interface Listener {
onRemoved()85         void onRemoved();
86     }
87 
88     private Preference mPreference;
89     private Button mButton;
90     private Listener mListener;
91     private SettingsActivity mActivity;
92     private int mUserId;
93     private boolean mRemoving;
94 
95     private final MetricsFeatureProvider mMetricsFeatureProvider;
96     private final Context mContext;
97     private final FaceManager mFaceManager;
98     private final FaceManager.RemovalCallback mRemovalCallback = new FaceManager.RemovalCallback() {
99         @Override
100         public void onRemovalError(Face face, int errMsgId, CharSequence errString) {
101             Log.e(TAG, "Unable to remove face: " + face.getBiometricId()
102                     + " error: " + errMsgId + " " + errString);
103             Toast.makeText(mContext, errString, Toast.LENGTH_SHORT).show();
104             mRemoving = false;
105         }
106 
107         @Override
108         public void onRemovalSucceeded(Face face, int remaining) {
109             if (remaining == 0) {
110                 final List<Face> faces = mFaceManager.getEnrolledFaces(mUserId);
111                 if (!faces.isEmpty()) {
112                     mButton.setEnabled(true);
113                 } else {
114                     mRemoving = false;
115                     mListener.onRemoved();
116                 }
117             } else {
118                 Log.v(TAG, "Remaining: " + remaining);
119             }
120         }
121     };
122 
123     private final DialogInterface.OnClickListener mOnClickListener
124             = new DialogInterface.OnClickListener() {
125         @Override
126         public void onClick(DialogInterface dialog, int which) {
127             if (which == DialogInterface.BUTTON_POSITIVE) {
128                 mButton.setEnabled(false);
129                 final List<Face> faces = mFaceManager.getEnrolledFaces(mUserId);
130                 if (faces.isEmpty()) {
131                     Log.e(TAG, "No faces");
132                     return;
133                 }
134                 if (faces.size() > 1) {
135                     Log.e(TAG, "Multiple enrollments: " + faces.size());
136                 }
137 
138                 // Remove the first/only face
139                 mFaceManager.remove(faces.get(0), mUserId, mRemovalCallback);
140             } else {
141                 mButton.setEnabled(true);
142                 mRemoving = false;
143             }
144         }
145     };
146 
FaceSettingsRemoveButtonPreferenceController(Context context, String preferenceKey)147     public FaceSettingsRemoveButtonPreferenceController(Context context, String preferenceKey) {
148         super(context, preferenceKey);
149         mContext = context;
150         mFaceManager = context.getSystemService(FaceManager.class);
151         mMetricsFeatureProvider = FeatureFactory.getFactory(context).getMetricsFeatureProvider();
152     }
153 
FaceSettingsRemoveButtonPreferenceController(Context context)154     public FaceSettingsRemoveButtonPreferenceController(Context context) {
155         this(context, KEY);
156     }
157 
setUserId(int userId)158     public void setUserId(int userId) {
159         mUserId = userId;
160     }
161 
162     @Override
updateState(Preference preference)163     public void updateState(Preference preference) {
164         super.updateState(preference);
165 
166         mPreference = preference;
167         mButton = ((LayoutPreference) preference)
168                 .findViewById(R.id.security_settings_face_settings_remove_button);
169 
170         if (PartnerStyleHelper.shouldApplyPartnerResource(mButton)) {
171             ButtonStyler.applyPartnerCustomizationPrimaryButtonStyle(mContext, mButton);
172         }
173 
174         mButton.setOnClickListener(this);
175 
176         if (!FaceSettings.isFaceHardwareDetected(mContext)) {
177             mButton.setEnabled(false);
178         } else {
179             mButton.setEnabled(!mRemoving);
180         }
181     }
182 
183     @Override
getAvailabilityStatus()184     public int getAvailabilityStatus() {
185         return AVAILABLE;
186     }
187 
188     @Override
getPreferenceKey()189     public String getPreferenceKey() {
190         return KEY;
191     }
192 
193     @Override
onClick(View v)194     public void onClick(View v) {
195         if (v == mButton) {
196             mMetricsFeatureProvider.logClickedPreference(mPreference, getMetricsCategory());
197             mRemoving = true;
198             ConfirmRemoveDialog dialog = new ConfirmRemoveDialog();
199             dialog.setOnClickListener(mOnClickListener);
200             dialog.show(mActivity.getSupportFragmentManager(), ConfirmRemoveDialog.class.getName());
201         }
202     }
203 
setListener(Listener listener)204     public void setListener(Listener listener) {
205         mListener = listener;
206     }
207 
setActivity(SettingsActivity activity)208     public void setActivity(SettingsActivity activity) {
209         mActivity = activity;
210     }
211 }
212