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