blob: 689366bcb42b21276657aa18b97448222784bacf [file] [log] [blame]
Brian Colonna94313662012-04-06 13:01:29 -04001/*
Jim Millerdcb3d842012-08-23 19:18:12 -07002 * Copyright (C) 2012 The Android Open Source Project
Brian Colonna94313662012-04-06 13:01:29 -04003 *
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
Jim Miller5ecd8112013-01-09 18:50:26 -080017package com.android.keyguard;
Brian Colonna94313662012-04-06 13:01:29 -040018
Brian Colonna94313662012-04-06 13:01:29 -040019import com.android.internal.policy.IFaceLockCallback;
20import com.android.internal.policy.IFaceLockInterface;
21import com.android.internal.widget.LockPatternUtils;
22
Brian Colonna3223e252012-04-11 11:12:37 -040023import android.app.admin.DevicePolicyManager;
Brian Colonna94313662012-04-06 13:01:29 -040024import android.content.ComponentName;
25import android.content.Context;
26import android.content.Intent;
27import android.content.ServiceConnection;
28import android.os.Handler;
29import android.os.IBinder;
Brian Colonna22001c12012-05-09 11:16:04 -040030import android.os.Looper;
Brian Colonna94313662012-04-06 13:01:29 -040031import android.os.Message;
Steven Rossacbe41f2012-09-27 11:29:37 -040032import android.os.PowerManager;
Brian Colonna94313662012-04-06 13:01:29 -040033import android.os.RemoteException;
Brian Colonna5eb83aa2012-11-19 16:05:48 -050034import android.os.UserHandle;
Brian Colonna94313662012-04-06 13:01:29 -040035import android.util.Log;
36import android.view.View;
37
Brian Colonna3223e252012-04-11 11:12:37 -040038public class FaceUnlock implements BiometricSensorUnlock, Handler.Callback {
Brian Colonna94313662012-04-06 13:01:29 -040039
40 private static final boolean DEBUG = false;
41 private static final String TAG = "FULLockscreen";
42
43 private final Context mContext;
Brian Colonnaea8441e2012-04-25 17:51:49 -040044 private final LockPatternUtils mLockPatternUtils;
Brian Colonna94313662012-04-06 13:01:29 -040045
Brian Colonnaea8441e2012-04-25 17:51:49 -040046 // TODO: is mServiceRunning needed or can we just use mIsRunning or check if mService is null?
47 private boolean mServiceRunning = false;
Brian Colonna257f2ec2012-04-27 13:14:22 -040048 // TODO: now that the code has been restructure to do almost all operations from a handler, this
49 // lock may no longer be necessary.
Brian Colonnaea8441e2012-04-25 17:51:49 -040050 private final Object mServiceRunningLock = new Object();
Brian Colonna94313662012-04-06 13:01:29 -040051 private IFaceLockInterface mService;
52 private boolean mBoundToService = false;
Brian Colonnaea8441e2012-04-25 17:51:49 -040053 private View mFaceUnlockView;
Brian Colonna94313662012-04-06 13:01:29 -040054
55 private Handler mHandler;
Danielle Millett61413b52012-10-09 18:07:02 -040056 private final int MSG_SERVICE_CONNECTED = 0;
57 private final int MSG_SERVICE_DISCONNECTED = 1;
58 private final int MSG_UNLOCK = 2;
59 private final int MSG_CANCEL = 3;
60 private final int MSG_REPORT_FAILED_ATTEMPT = 4;
Brian Colonna667b5d52012-10-31 23:07:00 -040061 private final int MSG_POKE_WAKELOCK = 5;
Brian Colonna94313662012-04-06 13:01:29 -040062
Brian Colonnaea8441e2012-04-25 17:51:49 -040063 // TODO: This was added for the purpose of adhering to what the biometric interface expects
64 // the isRunning() function to return. However, it is probably not necessary to have both
65 // mRunning and mServiceRunning. I'd just rather wait to change that logic.
Brian Colonna257f2ec2012-04-27 13:14:22 -040066 private volatile boolean mIsRunning = false;
Brian Colonna94313662012-04-06 13:01:29 -040067
Brian Colonnaea8441e2012-04-25 17:51:49 -040068 // So the user has a consistent amount of time when brought to the backup method from Face
69 // Unlock
Brian Colonna94313662012-04-06 13:01:29 -040070 private final int BACKUP_LOCK_TIMEOUT = 5000;
71
Jim Millerdcb3d842012-08-23 19:18:12 -070072 KeyguardSecurityCallback mKeyguardScreenCallback;
Brian Colonna94313662012-04-06 13:01:29 -040073
Brian Colonna257f2ec2012-04-27 13:14:22 -040074 /**
75 * Stores some of the structures that Face Unlock will need to access and creates the handler
76 * will be used to execute messages on the UI thread.
77 */
Jim Miller000464a2012-09-04 16:45:06 -070078 public FaceUnlock(Context context) {
Brian Colonna94313662012-04-06 13:01:29 -040079 mContext = context;
Jim Millerdcb3d842012-08-23 19:18:12 -070080 mLockPatternUtils = new LockPatternUtils(context);
Brian Colonna94313662012-04-06 13:01:29 -040081 mHandler = new Handler(this);
82 }
83
Jim Miller000464a2012-09-04 16:45:06 -070084 public void setKeyguardCallback(KeyguardSecurityCallback keyguardScreenCallback) {
85 mKeyguardScreenCallback = keyguardScreenCallback;
86 }
87
Brian Colonnaea8441e2012-04-25 17:51:49 -040088 /**
89 * Stores and displays the view that Face Unlock is allowed to draw within.
90 * TODO: since the layout object will eventually be shared by multiple biometric unlock
91 * methods, we will have to add our other views (background, cancel button) here.
92 */
93 public void initializeView(View biometricUnlockView) {
Brian Colonna257f2ec2012-04-27 13:14:22 -040094 Log.d(TAG, "initializeView()");
Brian Colonnaea8441e2012-04-25 17:51:49 -040095 mFaceUnlockView = biometricUnlockView;
Brian Colonna3223e252012-04-11 11:12:37 -040096 }
97
Brian Colonnaea8441e2012-04-25 17:51:49 -040098 /**
99 * Indicates whether Face Unlock is currently running.
100 */
101 public boolean isRunning() {
102 return mIsRunning;
103 }
104
105 /**
Danielle Millett61413b52012-10-09 18:07:02 -0400106 * Dismisses face unlock and goes to the backup lock
Brian Colonnaea8441e2012-04-25 17:51:49 -0400107 */
Danielle Millett61413b52012-10-09 18:07:02 -0400108 public void stopAndShowBackup() {
109 if (DEBUG) Log.d(TAG, "stopAndShowBackup()");
110 mHandler.sendEmptyMessage(MSG_CANCEL);
Brian Colonna3223e252012-04-11 11:12:37 -0400111 }
112
Brian Colonnaea8441e2012-04-25 17:51:49 -0400113 /**
114 * Binds to the Face Unlock service. Face Unlock will be started when the bind completes. The
Brian Colonna257f2ec2012-04-27 13:14:22 -0400115 * Face Unlock view is displayed to hide the backup lock while the service is starting up.
Brian Colonna22001c12012-05-09 11:16:04 -0400116 * Called on the UI thread.
Brian Colonnaea8441e2012-04-25 17:51:49 -0400117 */
118 public boolean start() {
Brian Colonna257f2ec2012-04-27 13:14:22 -0400119 if (DEBUG) Log.d(TAG, "start()");
Brian Colonna22001c12012-05-09 11:16:04 -0400120 if (mHandler.getLooper() != Looper.myLooper()) {
121 Log.e(TAG, "start() called off of the UI thread");
122 }
123
Brian Colonnaea8441e2012-04-25 17:51:49 -0400124 if (mIsRunning) {
125 Log.w(TAG, "start() called when already running");
126 }
127
Brian Colonnaea8441e2012-04-25 17:51:49 -0400128 if (!mBoundToService) {
Amith Yamasani4b4b9542012-09-14 13:36:29 -0700129 Log.d(TAG, "Binding to Face Unlock service for user="
130 + mLockPatternUtils.getCurrentUser());
Amith Yamasani27b89e62013-01-16 12:30:11 -0800131 mContext.bindServiceAsUser(new Intent(IFaceLockInterface.class.getName()),
Brian Colonnaea8441e2012-04-25 17:51:49 -0400132 mConnection,
133 Context.BIND_AUTO_CREATE,
Amith Yamasani27b89e62013-01-16 12:30:11 -0800134 new UserHandle(mLockPatternUtils.getCurrentUser()));
Brian Colonnaea8441e2012-04-25 17:51:49 -0400135 mBoundToService = true;
136 } else {
137 Log.w(TAG, "Attempt to bind to Face Unlock when already bound");
138 }
139
Brian Colonnaea8441e2012-04-25 17:51:49 -0400140 mIsRunning = true;
141 return true;
142 }
143
144 /**
Brian Colonna22001c12012-05-09 11:16:04 -0400145 * Stops Face Unlock and unbinds from the service. Called on the UI thread.
Brian Colonnaea8441e2012-04-25 17:51:49 -0400146 */
Brian Colonna3223e252012-04-11 11:12:37 -0400147 public boolean stop() {
Brian Colonna257f2ec2012-04-27 13:14:22 -0400148 if (DEBUG) Log.d(TAG, "stop()");
Brian Colonna22001c12012-05-09 11:16:04 -0400149 if (mHandler.getLooper() != Looper.myLooper()) {
Jim Millera71984f2012-10-24 22:08:49 -0700150 Log.e(TAG, "stop() called from non-UI thread");
Brian Colonna22001c12012-05-09 11:16:04 -0400151 }
152
Steven Ross025fb932012-11-05 13:49:31 -0500153 // Clearing any old service connected messages.
154 mHandler.removeMessages(MSG_SERVICE_CONNECTED);
155
Brian Colonnaea8441e2012-04-25 17:51:49 -0400156 boolean mWasRunning = mIsRunning;
Danielle Millett1108a2c2012-10-29 22:16:32 -0400157
Brian Colonnac1693662012-04-19 11:34:04 -0400158 stopUi();
Brian Colonna3223e252012-04-11 11:12:37 -0400159
Brian Colonnac1693662012-04-19 11:34:04 -0400160 if (mBoundToService) {
Brian Colonnac1693662012-04-19 11:34:04 -0400161 if (mService != null) {
162 try {
Brian Colonnaea8441e2012-04-25 17:51:49 -0400163 mService.unregisterCallback(mFaceUnlockCallback);
Brian Colonnac1693662012-04-19 11:34:04 -0400164 } catch (RemoteException e) {
165 // Not much we can do
Brian Colonna3223e252012-04-11 11:12:37 -0400166 }
Brian Colonna3223e252012-04-11 11:12:37 -0400167 }
Brian Colonna257f2ec2012-04-27 13:14:22 -0400168 Log.d(TAG, "Unbinding from Face Unlock service");
Brian Colonnac1693662012-04-19 11:34:04 -0400169 mContext.unbindService(mConnection);
Brian Colonnac1693662012-04-19 11:34:04 -0400170 mBoundToService = false;
171 } else {
172 // This is usually not an error when this happens. Sometimes we will tell it to
173 // unbind multiple times because it's called from both onWindowFocusChanged and
174 // onDetachedFromWindow.
Brian Colonnaea8441e2012-04-25 17:51:49 -0400175 if (DEBUG) Log.d(TAG, "Attempt to unbind from Face Unlock when not bound");
Brian Colonna3223e252012-04-11 11:12:37 -0400176 }
Brian Colonnaea8441e2012-04-25 17:51:49 -0400177 mIsRunning = false;
178 return mWasRunning;
Brian Colonna3223e252012-04-11 11:12:37 -0400179 }
180
181 /**
Brian Colonnaea8441e2012-04-25 17:51:49 -0400182 * Frees up resources used by Face Unlock and stops it if it is still running.
Brian Colonna3223e252012-04-11 11:12:37 -0400183 */
Brian Colonna3223e252012-04-11 11:12:37 -0400184 public void cleanUp() {
Brian Colonna257f2ec2012-04-27 13:14:22 -0400185 if (DEBUG) Log.d(TAG, "cleanUp()");
Brian Colonna3223e252012-04-11 11:12:37 -0400186 if (mService != null) {
187 try {
Brian Colonnaea8441e2012-04-25 17:51:49 -0400188 mService.unregisterCallback(mFaceUnlockCallback);
Brian Colonna3223e252012-04-11 11:12:37 -0400189 } catch (RemoteException e) {
190 // Not much we can do
191 }
192 stopUi();
193 mService = null;
Brian Colonna94313662012-04-06 13:01:29 -0400194 }
Brian Colonna3223e252012-04-11 11:12:37 -0400195 }
196
Brian Colonnaea8441e2012-04-25 17:51:49 -0400197 /**
198 * Returns the Device Policy Manager quality for Face Unlock, which is BIOMETRIC_WEAK.
199 */
Brian Colonna3223e252012-04-11 11:12:37 -0400200 public int getQuality() {
201 return DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK;
Brian Colonna94313662012-04-06 13:01:29 -0400202 }
203
Brian Colonnaea8441e2012-04-25 17:51:49 -0400204 /**
Brian Colonna257f2ec2012-04-27 13:14:22 -0400205 * Handles messages such that everything happens on the UI thread in a deterministic order.
206 * Calls from the Face Unlock service come from binder threads. Calls from lockscreen typically
207 * come from the UI thread. This makes sure there are no race conditions between those calls.
Brian Colonnaea8441e2012-04-25 17:51:49 -0400208 */
Brian Colonna94313662012-04-06 13:01:29 -0400209 public boolean handleMessage(Message msg) {
210 switch (msg.what) {
Brian Colonna257f2ec2012-04-27 13:14:22 -0400211 case MSG_SERVICE_CONNECTED:
212 handleServiceConnected();
213 break;
214 case MSG_SERVICE_DISCONNECTED:
215 handleServiceDisconnected();
216 break;
217 case MSG_UNLOCK:
Brian Colonna5eb83aa2012-11-19 16:05:48 -0500218 handleUnlock(msg.arg1);
Brian Colonna257f2ec2012-04-27 13:14:22 -0400219 break;
220 case MSG_CANCEL:
221 handleCancel();
222 break;
223 case MSG_REPORT_FAILED_ATTEMPT:
224 handleReportFailedAttempt();
225 break;
Brian Colonna257f2ec2012-04-27 13:14:22 -0400226 case MSG_POKE_WAKELOCK:
Uriel Rodriguezdff30762012-05-09 16:10:41 -0400227 handlePokeWakelock(msg.arg1);
Brian Colonna257f2ec2012-04-27 13:14:22 -0400228 break;
229 default:
230 Log.e(TAG, "Unhandled message");
231 return false;
Brian Colonna94313662012-04-06 13:01:29 -0400232 }
233 return true;
234 }
235
Brian Colonnaea8441e2012-04-25 17:51:49 -0400236 /**
Brian Colonna257f2ec2012-04-27 13:14:22 -0400237 * Tells the service to start its UI via an AIDL interface. Called when the
238 * onServiceConnected() callback is received.
239 */
240 void handleServiceConnected() {
Brian Colonnac2660702012-05-16 22:11:30 -0400241 Log.d(TAG, "handleServiceConnected()");
242
243 // It is possible that an unbind has occurred in the time between the bind and when this
244 // function is reached. If an unbind has already occurred, proceeding on to call startUi()
245 // can result in a fatal error. Note that the onServiceConnected() callback is
246 // asynchronous, so this possibility would still exist if we executed this directly in
247 // onServiceConnected() rather than using a handler.
248 if (!mBoundToService) {
249 Log.d(TAG, "Dropping startUi() in handleServiceConnected() because no longer bound");
250 return;
251 }
252
Brian Colonna257f2ec2012-04-27 13:14:22 -0400253 try {
254 mService.registerCallback(mFaceUnlockCallback);
255 } catch (RemoteException e) {
256 Log.e(TAG, "Caught exception connecting to Face Unlock: " + e.toString());
257 mService = null;
258 mBoundToService = false;
259 mIsRunning = false;
260 return;
261 }
262
263 if (mFaceUnlockView != null) {
264 IBinder windowToken = mFaceUnlockView.getWindowToken();
265 if (windowToken != null) {
Uriel Rodriguezdff30762012-05-09 16:10:41 -0400266 // When switching between portrait and landscape view while Face Unlock is running,
267 // the screen will eventually go dark unless we poke the wakelock when Face Unlock
268 // is restarted.
Jim Millerdcb3d842012-08-23 19:18:12 -0700269 mKeyguardScreenCallback.userActivity(0);
Uriel Rodriguezdff30762012-05-09 16:10:41 -0400270
Brian Colonna94313662012-04-06 13:01:29 -0400271 int[] position;
272 position = new int[2];
Brian Colonnaea8441e2012-04-25 17:51:49 -0400273 mFaceUnlockView.getLocationInWindow(position);
Brian Colonna257f2ec2012-04-27 13:14:22 -0400274 startUi(windowToken, position[0], position[1], mFaceUnlockView.getWidth(),
275 mFaceUnlockView.getHeight());
276 } else {
277 Log.e(TAG, "windowToken is null in handleServiceConnected()");
Brian Colonna94313662012-04-06 13:01:29 -0400278 }
279 }
Brian Colonna257f2ec2012-04-27 13:14:22 -0400280 }
281
282 /**
283 * Called when the onServiceDisconnected() callback is received. This should not happen during
284 * normal operation. It indicates an error has occurred.
285 */
286 void handleServiceDisconnected() {
287 Log.e(TAG, "handleServiceDisconnected()");
288 // TODO: this lock may no longer be needed now that everything is being called from a
289 // handler
290 synchronized (mServiceRunningLock) {
291 mService = null;
292 mServiceRunning = false;
293 }
294 mBoundToService = false;
295 mIsRunning = false;
296 }
297
298 /**
Danielle Millett61413b52012-10-09 18:07:02 -0400299 * Stops the Face Unlock service and tells the device to grant access to the user.
Brian Colonna257f2ec2012-04-27 13:14:22 -0400300 */
Brian Colonna5eb83aa2012-11-19 16:05:48 -0500301 void handleUnlock(int authenticatedUserId) {
Brian Colonna257f2ec2012-04-27 13:14:22 -0400302 if (DEBUG) Log.d(TAG, "handleUnlock()");
Brian Colonna257f2ec2012-04-27 13:14:22 -0400303 stop();
Brian Colonna5eb83aa2012-11-19 16:05:48 -0500304 int currentUserId = mLockPatternUtils.getCurrentUser();
305 if (authenticatedUserId == currentUserId) {
306 if (DEBUG) Log.d(TAG, "Unlocking for user " + authenticatedUserId);
307 mKeyguardScreenCallback.reportSuccessfulUnlockAttempt();
308 mKeyguardScreenCallback.dismiss(true);
309 } else {
310 Log.d(TAG, "Ignoring unlock for authenticated user (" + authenticatedUserId +
311 ") because the current user is " + currentUserId);
312 }
Brian Colonna257f2ec2012-04-27 13:14:22 -0400313 }
314
315 /**
Danielle Millett61413b52012-10-09 18:07:02 -0400316 * Stops the Face Unlock service and goes to the backup lock.
Brian Colonna257f2ec2012-04-27 13:14:22 -0400317 */
318 void handleCancel() {
319 if (DEBUG) Log.d(TAG, "handleCancel()");
Brian Colonna667b5d52012-10-31 23:07:00 -0400320 // We are going to the backup method, so we don't want to see Face Unlock again until the
321 // next time the user visits keyguard.
322 KeyguardUpdateMonitor.getInstance(mContext).setAlternateUnlockEnabled(false);
323
Danielle Millett61413b52012-10-09 18:07:02 -0400324 mKeyguardScreenCallback.showBackupSecurity();
Brian Colonna257f2ec2012-04-27 13:14:22 -0400325 stop();
Jim Millerdcb3d842012-08-23 19:18:12 -0700326 mKeyguardScreenCallback.userActivity(BACKUP_LOCK_TIMEOUT);
Brian Colonna257f2ec2012-04-27 13:14:22 -0400327 }
328
329 /**
Brian Colonna70193252012-06-04 16:16:46 -0400330 * Increments the number of failed Face Unlock attempts.
Brian Colonna257f2ec2012-04-27 13:14:22 -0400331 */
332 void handleReportFailedAttempt() {
333 if (DEBUG) Log.d(TAG, "handleReportFailedAttempt()");
Brian Colonna667b5d52012-10-31 23:07:00 -0400334 // We are going to the backup method, so we don't want to see Face Unlock again until the
335 // next time the user visits keyguard.
336 KeyguardUpdateMonitor.getInstance(mContext).setAlternateUnlockEnabled(false);
Brian Colonna257f2ec2012-04-27 13:14:22 -0400337
Brian Colonna667b5d52012-10-31 23:07:00 -0400338 mKeyguardScreenCallback.reportFailedUnlockAttempt();
Brian Colonna257f2ec2012-04-27 13:14:22 -0400339 }
340
341 /**
Steven Rossacbe41f2012-09-27 11:29:37 -0400342 * If the screen is on, pokes the wakelock to keep the screen alive and active for a specific
343 * amount of time.
Brian Colonna257f2ec2012-04-27 13:14:22 -0400344 */
Uriel Rodriguezdff30762012-05-09 16:10:41 -0400345 void handlePokeWakelock(int millis) {
Steven Rossacbe41f2012-09-27 11:29:37 -0400346 PowerManager powerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
347 if (powerManager.isScreenOn()) {
Jim Millerdcb3d842012-08-23 19:18:12 -0700348 mKeyguardScreenCallback.userActivity(millis);
Steven Rossacbe41f2012-09-27 11:29:37 -0400349 }
Brian Colonna257f2ec2012-04-27 13:14:22 -0400350 }
351
352 /**
Brian Colonna257f2ec2012-04-27 13:14:22 -0400353 * Implements service connection methods.
354 */
355 private ServiceConnection mConnection = new ServiceConnection() {
356 /**
357 * Called when the Face Unlock service connects after calling bind().
358 */
Brian Colonna257f2ec2012-04-27 13:14:22 -0400359 public void onServiceConnected(ComponentName className, IBinder iservice) {
360 Log.d(TAG, "Connected to Face Unlock service");
361 mService = IFaceLockInterface.Stub.asInterface(iservice);
362 mHandler.sendEmptyMessage(MSG_SERVICE_CONNECTED);
363 }
Brian Colonna94313662012-04-06 13:01:29 -0400364
Brian Colonnaea8441e2012-04-25 17:51:49 -0400365 /**
Brian Colonna257f2ec2012-04-27 13:14:22 -0400366 * Called if the Face Unlock service unexpectedly disconnects. This indicates an error.
Brian Colonnaea8441e2012-04-25 17:51:49 -0400367 */
Brian Colonna94313662012-04-06 13:01:29 -0400368 public void onServiceDisconnected(ComponentName className) {
Brian Colonna257f2ec2012-04-27 13:14:22 -0400369 Log.e(TAG, "Unexpected disconnect from Face Unlock service");
370 mHandler.sendEmptyMessage(MSG_SERVICE_DISCONNECTED);
Brian Colonna94313662012-04-06 13:01:29 -0400371 }
372 };
373
Brian Colonnaea8441e2012-04-25 17:51:49 -0400374 /**
Brian Colonna257f2ec2012-04-27 13:14:22 -0400375 * Tells the Face Unlock service to start displaying its UI and start processing.
Brian Colonnaea8441e2012-04-25 17:51:49 -0400376 */
Brian Colonna3223e252012-04-11 11:12:37 -0400377 private void startUi(IBinder windowToken, int x, int y, int w, int h) {
Brian Colonnac2660702012-05-16 22:11:30 -0400378 if (DEBUG) Log.d(TAG, "startUi()");
Brian Colonnac1693662012-04-19 11:34:04 -0400379 synchronized (mServiceRunningLock) {
380 if (!mServiceRunning) {
Brian Colonnac2660702012-05-16 22:11:30 -0400381 Log.d(TAG, "Starting Face Unlock");
Brian Colonnac1693662012-04-19 11:34:04 -0400382 try {
Uriel Rodriguez4fa995a2012-05-30 20:01:38 -0400383 mService.startUi(windowToken, x, y, w, h,
384 mLockPatternUtils.isBiometricWeakLivelinessEnabled());
Brian Colonnac1693662012-04-19 11:34:04 -0400385 } catch (RemoteException e) {
Brian Colonnaea8441e2012-04-25 17:51:49 -0400386 Log.e(TAG, "Caught exception starting Face Unlock: " + e.toString());
Brian Colonnac1693662012-04-19 11:34:04 -0400387 return;
Brian Colonna94313662012-04-06 13:01:29 -0400388 }
Brian Colonnac1693662012-04-19 11:34:04 -0400389 mServiceRunning = true;
390 } else {
Brian Colonna257f2ec2012-04-27 13:14:22 -0400391 Log.w(TAG, "startUi() attempted while running");
Brian Colonna94313662012-04-06 13:01:29 -0400392 }
393 }
394 }
395
Brian Colonnaea8441e2012-04-25 17:51:49 -0400396 /**
Brian Colonna257f2ec2012-04-27 13:14:22 -0400397 * Tells the Face Unlock service to stop displaying its UI and stop processing.
Brian Colonnaea8441e2012-04-25 17:51:49 -0400398 */
Brian Colonna3223e252012-04-11 11:12:37 -0400399 private void stopUi() {
Brian Colonna257f2ec2012-04-27 13:14:22 -0400400 if (DEBUG) Log.d(TAG, "stopUi()");
Brian Colonnaea8441e2012-04-25 17:51:49 -0400401 // Note that attempting to stop Face Unlock when it's not running is not an issue.
402 // Face Unlock can return, which stops it and then we try to stop it when the
Brian Colonnac1693662012-04-19 11:34:04 -0400403 // screen is turned off. That's why we check.
404 synchronized (mServiceRunningLock) {
405 if (mServiceRunning) {
Brian Colonnac2660702012-05-16 22:11:30 -0400406 Log.d(TAG, "Stopping Face Unlock");
Brian Colonnac1693662012-04-19 11:34:04 -0400407 try {
Brian Colonnac1693662012-04-19 11:34:04 -0400408 mService.stopUi();
409 } catch (RemoteException e) {
Brian Colonnaea8441e2012-04-25 17:51:49 -0400410 Log.e(TAG, "Caught exception stopping Face Unlock: " + e.toString());
Brian Colonna94313662012-04-06 13:01:29 -0400411 }
Brian Colonnac1693662012-04-19 11:34:04 -0400412 mServiceRunning = false;
Brian Colonna257f2ec2012-04-27 13:14:22 -0400413 } else {
414 // This is usually not an error when this happens. Sometimes we will tell it to
415 // stop multiple times because it's called from both onWindowFocusChanged and
416 // onDetachedFromWindow.
417 if (DEBUG) Log.d(TAG, "stopUi() attempted while not running");
Brian Colonna94313662012-04-06 13:01:29 -0400418 }
419 }
420 }
421
Brian Colonnaea8441e2012-04-25 17:51:49 -0400422 /**
Brian Colonna257f2ec2012-04-27 13:14:22 -0400423 * Implements the AIDL biometric unlock service callback interface.
Brian Colonnaea8441e2012-04-25 17:51:49 -0400424 */
425 private final IFaceLockCallback mFaceUnlockCallback = new IFaceLockCallback.Stub() {
426 /**
Brian Colonna257f2ec2012-04-27 13:14:22 -0400427 * Called when Face Unlock wants to grant access to the user.
Brian Colonnaea8441e2012-04-25 17:51:49 -0400428 */
Brian Colonna94313662012-04-06 13:01:29 -0400429 public void unlock() {
Brian Colonnaea8441e2012-04-25 17:51:49 -0400430 if (DEBUG) Log.d(TAG, "unlock()");
Brian Colonna5eb83aa2012-11-19 16:05:48 -0500431 Message message = mHandler.obtainMessage(MSG_UNLOCK, UserHandle.getCallingUserId(), -1);
432 mHandler.sendMessage(message);
Brian Colonna94313662012-04-06 13:01:29 -0400433 }
434
Brian Colonnaea8441e2012-04-25 17:51:49 -0400435 /**
Brian Colonna70193252012-06-04 16:16:46 -0400436 * Called when Face Unlock wants to go to the backup.
Brian Colonnaea8441e2012-04-25 17:51:49 -0400437 */
Brian Colonna94313662012-04-06 13:01:29 -0400438 public void cancel() {
Brian Colonnaea8441e2012-04-25 17:51:49 -0400439 if (DEBUG) Log.d(TAG, "cancel()");
Brian Colonna257f2ec2012-04-27 13:14:22 -0400440 mHandler.sendEmptyMessage(MSG_CANCEL);
Brian Colonna94313662012-04-06 13:01:29 -0400441 }
442
Brian Colonnaea8441e2012-04-25 17:51:49 -0400443 /**
Brian Colonna70193252012-06-04 16:16:46 -0400444 * Called when Face Unlock wants to increment the number of failed attempts.
Brian Colonnaea8441e2012-04-25 17:51:49 -0400445 */
Brian Colonna94313662012-04-06 13:01:29 -0400446 public void reportFailedAttempt() {
Brian Colonnaea8441e2012-04-25 17:51:49 -0400447 if (DEBUG) Log.d(TAG, "reportFailedAttempt()");
Brian Colonna257f2ec2012-04-27 13:14:22 -0400448 mHandler.sendEmptyMessage(MSG_REPORT_FAILED_ATTEMPT);
Brian Colonna94313662012-04-06 13:01:29 -0400449 }
450
Brian Colonnaea8441e2012-04-25 17:51:49 -0400451 /**
Uriel Rodriguezdff30762012-05-09 16:10:41 -0400452 * Called when Face Unlock wants to keep the screen alive and active for a specific amount
453 * of time.
Brian Colonnaea8441e2012-04-25 17:51:49 -0400454 */
Uriel Rodriguezdff30762012-05-09 16:10:41 -0400455 public void pokeWakelock(int millis) {
456 if (DEBUG) Log.d(TAG, "pokeWakelock() for " + millis + "ms");
457 Message message = mHandler.obtainMessage(MSG_POKE_WAKELOCK, millis, -1);
458 mHandler.sendMessage(message);
Brian Colonna94313662012-04-06 13:01:29 -0400459 }
Uriel Rodriguezdff30762012-05-09 16:10:41 -0400460
Brian Colonna94313662012-04-06 13:01:29 -0400461 };
462}