blob: 2f140036023bc8f6d2aed6f16a9dbfe0b8674029 [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
Jorim Jaggi5cf17872014-03-26 18:31:48 +010040 private static final boolean DEBUG = KeyguardConstants.DEBUG;
Brian Colonna94313662012-04-06 13:01:29 -040041 private static final String TAG = "FULLockscreen";
Jorim Jaggi5cf17872014-03-26 18:31:48 +010042 private static final String FACE_LOCK_PACKAGE = "com.android.facelock";
Brian Colonna94313662012-04-06 13:01:29 -040043
44 private final Context mContext;
Brian Colonnaea8441e2012-04-25 17:51:49 -040045 private final LockPatternUtils mLockPatternUtils;
Brian Colonna94313662012-04-06 13:01:29 -040046
Brian Colonnaea8441e2012-04-25 17:51:49 -040047 // TODO: is mServiceRunning needed or can we just use mIsRunning or check if mService is null?
48 private boolean mServiceRunning = false;
Brian Colonna257f2ec2012-04-27 13:14:22 -040049 // TODO: now that the code has been restructure to do almost all operations from a handler, this
50 // lock may no longer be necessary.
Brian Colonnaea8441e2012-04-25 17:51:49 -040051 private final Object mServiceRunningLock = new Object();
Brian Colonna94313662012-04-06 13:01:29 -040052 private IFaceLockInterface mService;
53 private boolean mBoundToService = false;
Brian Colonnaea8441e2012-04-25 17:51:49 -040054 private View mFaceUnlockView;
Brian Colonna94313662012-04-06 13:01:29 -040055
56 private Handler mHandler;
Danielle Millett61413b52012-10-09 18:07:02 -040057 private final int MSG_SERVICE_CONNECTED = 0;
58 private final int MSG_SERVICE_DISCONNECTED = 1;
59 private final int MSG_UNLOCK = 2;
60 private final int MSG_CANCEL = 3;
61 private final int MSG_REPORT_FAILED_ATTEMPT = 4;
Brian Colonna667b5d52012-10-31 23:07:00 -040062 private final int MSG_POKE_WAKELOCK = 5;
Brian Colonna94313662012-04-06 13:01:29 -040063
Brian Colonnaea8441e2012-04-25 17:51:49 -040064 // TODO: This was added for the purpose of adhering to what the biometric interface expects
65 // the isRunning() function to return. However, it is probably not necessary to have both
66 // mRunning and mServiceRunning. I'd just rather wait to change that logic.
Brian Colonna257f2ec2012-04-27 13:14:22 -040067 private volatile boolean mIsRunning = false;
Brian Colonna94313662012-04-06 13:01:29 -040068
Brian Colonnaea8441e2012-04-25 17:51:49 -040069 // So the user has a consistent amount of time when brought to the backup method from Face
70 // Unlock
Brian Colonna94313662012-04-06 13:01:29 -040071 private final int BACKUP_LOCK_TIMEOUT = 5000;
72
Jim Millerdcb3d842012-08-23 19:18:12 -070073 KeyguardSecurityCallback mKeyguardScreenCallback;
Brian Colonna94313662012-04-06 13:01:29 -040074
Brian Colonna257f2ec2012-04-27 13:14:22 -040075 /**
76 * Stores some of the structures that Face Unlock will need to access and creates the handler
77 * will be used to execute messages on the UI thread.
78 */
Jim Miller000464a2012-09-04 16:45:06 -070079 public FaceUnlock(Context context) {
Brian Colonna94313662012-04-06 13:01:29 -040080 mContext = context;
Jim Millerdcb3d842012-08-23 19:18:12 -070081 mLockPatternUtils = new LockPatternUtils(context);
Brian Colonna94313662012-04-06 13:01:29 -040082 mHandler = new Handler(this);
83 }
84
Jim Miller000464a2012-09-04 16:45:06 -070085 public void setKeyguardCallback(KeyguardSecurityCallback keyguardScreenCallback) {
86 mKeyguardScreenCallback = keyguardScreenCallback;
87 }
88
Brian Colonnaea8441e2012-04-25 17:51:49 -040089 /**
90 * Stores and displays the view that Face Unlock is allowed to draw within.
91 * TODO: since the layout object will eventually be shared by multiple biometric unlock
92 * methods, we will have to add our other views (background, cancel button) here.
93 */
94 public void initializeView(View biometricUnlockView) {
Brian Colonna257f2ec2012-04-27 13:14:22 -040095 Log.d(TAG, "initializeView()");
Brian Colonnaea8441e2012-04-25 17:51:49 -040096 mFaceUnlockView = biometricUnlockView;
Brian Colonna3223e252012-04-11 11:12:37 -040097 }
98
Brian Colonnaea8441e2012-04-25 17:51:49 -040099 /**
100 * Indicates whether Face Unlock is currently running.
101 */
102 public boolean isRunning() {
103 return mIsRunning;
104 }
105
106 /**
Danielle Millett61413b52012-10-09 18:07:02 -0400107 * Dismisses face unlock and goes to the backup lock
Brian Colonnaea8441e2012-04-25 17:51:49 -0400108 */
Danielle Millett61413b52012-10-09 18:07:02 -0400109 public void stopAndShowBackup() {
110 if (DEBUG) Log.d(TAG, "stopAndShowBackup()");
111 mHandler.sendEmptyMessage(MSG_CANCEL);
Brian Colonna3223e252012-04-11 11:12:37 -0400112 }
113
Brian Colonnaea8441e2012-04-25 17:51:49 -0400114 /**
115 * Binds to the Face Unlock service. Face Unlock will be started when the bind completes. The
Brian Colonna257f2ec2012-04-27 13:14:22 -0400116 * Face Unlock view is displayed to hide the backup lock while the service is starting up.
Brian Colonna22001c12012-05-09 11:16:04 -0400117 * Called on the UI thread.
Brian Colonnaea8441e2012-04-25 17:51:49 -0400118 */
119 public boolean start() {
Brian Colonna257f2ec2012-04-27 13:14:22 -0400120 if (DEBUG) Log.d(TAG, "start()");
Brian Colonna22001c12012-05-09 11:16:04 -0400121 if (mHandler.getLooper() != Looper.myLooper()) {
122 Log.e(TAG, "start() called off of the UI thread");
123 }
124
Brian Colonnaea8441e2012-04-25 17:51:49 -0400125 if (mIsRunning) {
126 Log.w(TAG, "start() called when already running");
127 }
128
Brian Colonnaea8441e2012-04-25 17:51:49 -0400129 if (!mBoundToService) {
Amith Yamasani4b4b9542012-09-14 13:36:29 -0700130 Log.d(TAG, "Binding to Face Unlock service for user="
131 + mLockPatternUtils.getCurrentUser());
Jorim Jaggi5cf17872014-03-26 18:31:48 +0100132 mContext.bindServiceAsUser(
133 new Intent(IFaceLockInterface.class.getName()).setPackage(FACE_LOCK_PACKAGE),
Brian Colonnaea8441e2012-04-25 17:51:49 -0400134 mConnection,
135 Context.BIND_AUTO_CREATE,
Amith Yamasani27b89e62013-01-16 12:30:11 -0800136 new UserHandle(mLockPatternUtils.getCurrentUser()));
Brian Colonnaea8441e2012-04-25 17:51:49 -0400137 mBoundToService = true;
138 } else {
139 Log.w(TAG, "Attempt to bind to Face Unlock when already bound");
140 }
141
Brian Colonnaea8441e2012-04-25 17:51:49 -0400142 mIsRunning = true;
143 return true;
144 }
145
146 /**
Brian Colonna22001c12012-05-09 11:16:04 -0400147 * Stops Face Unlock and unbinds from the service. Called on the UI thread.
Brian Colonnaea8441e2012-04-25 17:51:49 -0400148 */
Brian Colonna3223e252012-04-11 11:12:37 -0400149 public boolean stop() {
Brian Colonna257f2ec2012-04-27 13:14:22 -0400150 if (DEBUG) Log.d(TAG, "stop()");
Brian Colonna22001c12012-05-09 11:16:04 -0400151 if (mHandler.getLooper() != Looper.myLooper()) {
Jim Millera71984f2012-10-24 22:08:49 -0700152 Log.e(TAG, "stop() called from non-UI thread");
Brian Colonna22001c12012-05-09 11:16:04 -0400153 }
154
Steven Ross025fb932012-11-05 13:49:31 -0500155 // Clearing any old service connected messages.
156 mHandler.removeMessages(MSG_SERVICE_CONNECTED);
157
Brian Colonnaea8441e2012-04-25 17:51:49 -0400158 boolean mWasRunning = mIsRunning;
Danielle Millett1108a2c2012-10-29 22:16:32 -0400159
Brian Colonnac1693662012-04-19 11:34:04 -0400160 stopUi();
Brian Colonna3223e252012-04-11 11:12:37 -0400161
Brian Colonnac1693662012-04-19 11:34:04 -0400162 if (mBoundToService) {
Brian Colonnac1693662012-04-19 11:34:04 -0400163 if (mService != null) {
164 try {
Brian Colonnaea8441e2012-04-25 17:51:49 -0400165 mService.unregisterCallback(mFaceUnlockCallback);
Brian Colonnac1693662012-04-19 11:34:04 -0400166 } catch (RemoteException e) {
167 // Not much we can do
Brian Colonna3223e252012-04-11 11:12:37 -0400168 }
Brian Colonna3223e252012-04-11 11:12:37 -0400169 }
Brian Colonna257f2ec2012-04-27 13:14:22 -0400170 Log.d(TAG, "Unbinding from Face Unlock service");
Brian Colonnac1693662012-04-19 11:34:04 -0400171 mContext.unbindService(mConnection);
Brian Colonnac1693662012-04-19 11:34:04 -0400172 mBoundToService = false;
173 } else {
174 // This is usually not an error when this happens. Sometimes we will tell it to
175 // unbind multiple times because it's called from both onWindowFocusChanged and
176 // onDetachedFromWindow.
Brian Colonnaea8441e2012-04-25 17:51:49 -0400177 if (DEBUG) Log.d(TAG, "Attempt to unbind from Face Unlock when not bound");
Brian Colonna3223e252012-04-11 11:12:37 -0400178 }
Brian Colonnaea8441e2012-04-25 17:51:49 -0400179 mIsRunning = false;
180 return mWasRunning;
Brian Colonna3223e252012-04-11 11:12:37 -0400181 }
182
183 /**
Brian Colonnaea8441e2012-04-25 17:51:49 -0400184 * Frees up resources used by Face Unlock and stops it if it is still running.
Brian Colonna3223e252012-04-11 11:12:37 -0400185 */
Brian Colonna3223e252012-04-11 11:12:37 -0400186 public void cleanUp() {
Brian Colonna257f2ec2012-04-27 13:14:22 -0400187 if (DEBUG) Log.d(TAG, "cleanUp()");
Brian Colonna3223e252012-04-11 11:12:37 -0400188 if (mService != null) {
189 try {
Brian Colonnaea8441e2012-04-25 17:51:49 -0400190 mService.unregisterCallback(mFaceUnlockCallback);
Brian Colonna3223e252012-04-11 11:12:37 -0400191 } catch (RemoteException e) {
192 // Not much we can do
193 }
194 stopUi();
195 mService = null;
Brian Colonna94313662012-04-06 13:01:29 -0400196 }
Brian Colonna3223e252012-04-11 11:12:37 -0400197 }
198
Brian Colonnaea8441e2012-04-25 17:51:49 -0400199 /**
200 * Returns the Device Policy Manager quality for Face Unlock, which is BIOMETRIC_WEAK.
201 */
Brian Colonna3223e252012-04-11 11:12:37 -0400202 public int getQuality() {
203 return DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK;
Brian Colonna94313662012-04-06 13:01:29 -0400204 }
205
Brian Colonnaea8441e2012-04-25 17:51:49 -0400206 /**
Brian Colonna257f2ec2012-04-27 13:14:22 -0400207 * Handles messages such that everything happens on the UI thread in a deterministic order.
208 * Calls from the Face Unlock service come from binder threads. Calls from lockscreen typically
209 * come from the UI thread. This makes sure there are no race conditions between those calls.
Brian Colonnaea8441e2012-04-25 17:51:49 -0400210 */
Brian Colonna94313662012-04-06 13:01:29 -0400211 public boolean handleMessage(Message msg) {
212 switch (msg.what) {
Brian Colonna257f2ec2012-04-27 13:14:22 -0400213 case MSG_SERVICE_CONNECTED:
214 handleServiceConnected();
215 break;
216 case MSG_SERVICE_DISCONNECTED:
217 handleServiceDisconnected();
218 break;
219 case MSG_UNLOCK:
Brian Colonna5eb83aa2012-11-19 16:05:48 -0500220 handleUnlock(msg.arg1);
Brian Colonna257f2ec2012-04-27 13:14:22 -0400221 break;
222 case MSG_CANCEL:
223 handleCancel();
224 break;
225 case MSG_REPORT_FAILED_ATTEMPT:
226 handleReportFailedAttempt();
227 break;
Brian Colonna257f2ec2012-04-27 13:14:22 -0400228 case MSG_POKE_WAKELOCK:
Uriel Rodriguezdff30762012-05-09 16:10:41 -0400229 handlePokeWakelock(msg.arg1);
Brian Colonna257f2ec2012-04-27 13:14:22 -0400230 break;
231 default:
232 Log.e(TAG, "Unhandled message");
233 return false;
Brian Colonna94313662012-04-06 13:01:29 -0400234 }
235 return true;
236 }
237
Brian Colonnaea8441e2012-04-25 17:51:49 -0400238 /**
Brian Colonna257f2ec2012-04-27 13:14:22 -0400239 * Tells the service to start its UI via an AIDL interface. Called when the
240 * onServiceConnected() callback is received.
241 */
242 void handleServiceConnected() {
Brian Colonnac2660702012-05-16 22:11:30 -0400243 Log.d(TAG, "handleServiceConnected()");
244
245 // It is possible that an unbind has occurred in the time between the bind and when this
246 // function is reached. If an unbind has already occurred, proceeding on to call startUi()
247 // can result in a fatal error. Note that the onServiceConnected() callback is
248 // asynchronous, so this possibility would still exist if we executed this directly in
249 // onServiceConnected() rather than using a handler.
250 if (!mBoundToService) {
251 Log.d(TAG, "Dropping startUi() in handleServiceConnected() because no longer bound");
252 return;
253 }
254
Brian Colonna257f2ec2012-04-27 13:14:22 -0400255 try {
256 mService.registerCallback(mFaceUnlockCallback);
257 } catch (RemoteException e) {
258 Log.e(TAG, "Caught exception connecting to Face Unlock: " + e.toString());
259 mService = null;
260 mBoundToService = false;
261 mIsRunning = false;
262 return;
263 }
264
265 if (mFaceUnlockView != null) {
266 IBinder windowToken = mFaceUnlockView.getWindowToken();
267 if (windowToken != null) {
Uriel Rodriguezdff30762012-05-09 16:10:41 -0400268 // When switching between portrait and landscape view while Face Unlock is running,
269 // the screen will eventually go dark unless we poke the wakelock when Face Unlock
270 // is restarted.
Jim Millerdcb3d842012-08-23 19:18:12 -0700271 mKeyguardScreenCallback.userActivity(0);
Uriel Rodriguezdff30762012-05-09 16:10:41 -0400272
Brian Colonna94313662012-04-06 13:01:29 -0400273 int[] position;
274 position = new int[2];
Brian Colonnaea8441e2012-04-25 17:51:49 -0400275 mFaceUnlockView.getLocationInWindow(position);
Brian Colonna257f2ec2012-04-27 13:14:22 -0400276 startUi(windowToken, position[0], position[1], mFaceUnlockView.getWidth(),
277 mFaceUnlockView.getHeight());
278 } else {
279 Log.e(TAG, "windowToken is null in handleServiceConnected()");
Brian Colonna94313662012-04-06 13:01:29 -0400280 }
281 }
Brian Colonna257f2ec2012-04-27 13:14:22 -0400282 }
283
284 /**
285 * Called when the onServiceDisconnected() callback is received. This should not happen during
286 * normal operation. It indicates an error has occurred.
287 */
288 void handleServiceDisconnected() {
289 Log.e(TAG, "handleServiceDisconnected()");
290 // TODO: this lock may no longer be needed now that everything is being called from a
291 // handler
292 synchronized (mServiceRunningLock) {
293 mService = null;
294 mServiceRunning = false;
295 }
296 mBoundToService = false;
297 mIsRunning = false;
298 }
299
300 /**
Danielle Millett61413b52012-10-09 18:07:02 -0400301 * Stops the Face Unlock service and tells the device to grant access to the user.
Brian Colonna257f2ec2012-04-27 13:14:22 -0400302 */
Brian Colonna5eb83aa2012-11-19 16:05:48 -0500303 void handleUnlock(int authenticatedUserId) {
Brian Colonna257f2ec2012-04-27 13:14:22 -0400304 if (DEBUG) Log.d(TAG, "handleUnlock()");
Brian Colonna257f2ec2012-04-27 13:14:22 -0400305 stop();
Brian Colonna5eb83aa2012-11-19 16:05:48 -0500306 int currentUserId = mLockPatternUtils.getCurrentUser();
307 if (authenticatedUserId == currentUserId) {
308 if (DEBUG) Log.d(TAG, "Unlocking for user " + authenticatedUserId);
Jim Miller7751ff62014-01-14 18:57:03 -0800309 mKeyguardScreenCallback.reportUnlockAttempt(true);
Brian Colonna5eb83aa2012-11-19 16:05:48 -0500310 mKeyguardScreenCallback.dismiss(true);
311 } else {
312 Log.d(TAG, "Ignoring unlock for authenticated user (" + authenticatedUserId +
313 ") because the current user is " + currentUserId);
314 }
Brian Colonna257f2ec2012-04-27 13:14:22 -0400315 }
316
317 /**
Danielle Millett61413b52012-10-09 18:07:02 -0400318 * Stops the Face Unlock service and goes to the backup lock.
Brian Colonna257f2ec2012-04-27 13:14:22 -0400319 */
320 void handleCancel() {
321 if (DEBUG) Log.d(TAG, "handleCancel()");
Brian Colonna667b5d52012-10-31 23:07:00 -0400322 // We are going to the backup method, so we don't want to see Face Unlock again until the
323 // next time the user visits keyguard.
324 KeyguardUpdateMonitor.getInstance(mContext).setAlternateUnlockEnabled(false);
325
Danielle Millett61413b52012-10-09 18:07:02 -0400326 mKeyguardScreenCallback.showBackupSecurity();
Brian Colonna257f2ec2012-04-27 13:14:22 -0400327 stop();
Jim Millerdcb3d842012-08-23 19:18:12 -0700328 mKeyguardScreenCallback.userActivity(BACKUP_LOCK_TIMEOUT);
Brian Colonna257f2ec2012-04-27 13:14:22 -0400329 }
330
331 /**
Brian Colonna70193252012-06-04 16:16:46 -0400332 * Increments the number of failed Face Unlock attempts.
Brian Colonna257f2ec2012-04-27 13:14:22 -0400333 */
334 void handleReportFailedAttempt() {
335 if (DEBUG) Log.d(TAG, "handleReportFailedAttempt()");
Brian Colonna667b5d52012-10-31 23:07:00 -0400336 // We are going to the backup method, so we don't want to see Face Unlock again until the
337 // next time the user visits keyguard.
338 KeyguardUpdateMonitor.getInstance(mContext).setAlternateUnlockEnabled(false);
Brian Colonna257f2ec2012-04-27 13:14:22 -0400339
Jim Miller7751ff62014-01-14 18:57:03 -0800340 mKeyguardScreenCallback.reportUnlockAttempt(false);
Brian Colonna257f2ec2012-04-27 13:14:22 -0400341 }
342
343 /**
Steven Rossacbe41f2012-09-27 11:29:37 -0400344 * If the screen is on, pokes the wakelock to keep the screen alive and active for a specific
345 * amount of time.
Brian Colonna257f2ec2012-04-27 13:14:22 -0400346 */
Uriel Rodriguezdff30762012-05-09 16:10:41 -0400347 void handlePokeWakelock(int millis) {
Steven Rossacbe41f2012-09-27 11:29:37 -0400348 PowerManager powerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
349 if (powerManager.isScreenOn()) {
Jim Millerdcb3d842012-08-23 19:18:12 -0700350 mKeyguardScreenCallback.userActivity(millis);
Steven Rossacbe41f2012-09-27 11:29:37 -0400351 }
Brian Colonna257f2ec2012-04-27 13:14:22 -0400352 }
353
354 /**
Brian Colonna257f2ec2012-04-27 13:14:22 -0400355 * Implements service connection methods.
356 */
357 private ServiceConnection mConnection = new ServiceConnection() {
358 /**
359 * Called when the Face Unlock service connects after calling bind().
360 */
Brian Colonna257f2ec2012-04-27 13:14:22 -0400361 public void onServiceConnected(ComponentName className, IBinder iservice) {
362 Log.d(TAG, "Connected to Face Unlock service");
363 mService = IFaceLockInterface.Stub.asInterface(iservice);
364 mHandler.sendEmptyMessage(MSG_SERVICE_CONNECTED);
365 }
Brian Colonna94313662012-04-06 13:01:29 -0400366
Brian Colonnaea8441e2012-04-25 17:51:49 -0400367 /**
Brian Colonna257f2ec2012-04-27 13:14:22 -0400368 * Called if the Face Unlock service unexpectedly disconnects. This indicates an error.
Brian Colonnaea8441e2012-04-25 17:51:49 -0400369 */
Brian Colonna94313662012-04-06 13:01:29 -0400370 public void onServiceDisconnected(ComponentName className) {
Brian Colonna257f2ec2012-04-27 13:14:22 -0400371 Log.e(TAG, "Unexpected disconnect from Face Unlock service");
372 mHandler.sendEmptyMessage(MSG_SERVICE_DISCONNECTED);
Brian Colonna94313662012-04-06 13:01:29 -0400373 }
374 };
375
Brian Colonnaea8441e2012-04-25 17:51:49 -0400376 /**
Brian Colonna257f2ec2012-04-27 13:14:22 -0400377 * Tells the Face Unlock service to start displaying its UI and start processing.
Brian Colonnaea8441e2012-04-25 17:51:49 -0400378 */
Brian Colonna3223e252012-04-11 11:12:37 -0400379 private void startUi(IBinder windowToken, int x, int y, int w, int h) {
Brian Colonnac2660702012-05-16 22:11:30 -0400380 if (DEBUG) Log.d(TAG, "startUi()");
Brian Colonnac1693662012-04-19 11:34:04 -0400381 synchronized (mServiceRunningLock) {
382 if (!mServiceRunning) {
Brian Colonnac2660702012-05-16 22:11:30 -0400383 Log.d(TAG, "Starting Face Unlock");
Brian Colonnac1693662012-04-19 11:34:04 -0400384 try {
Uriel Rodriguez4fa995a2012-05-30 20:01:38 -0400385 mService.startUi(windowToken, x, y, w, h,
386 mLockPatternUtils.isBiometricWeakLivelinessEnabled());
Brian Colonnac1693662012-04-19 11:34:04 -0400387 } catch (RemoteException e) {
Brian Colonnaea8441e2012-04-25 17:51:49 -0400388 Log.e(TAG, "Caught exception starting Face Unlock: " + e.toString());
Brian Colonnac1693662012-04-19 11:34:04 -0400389 return;
Brian Colonna94313662012-04-06 13:01:29 -0400390 }
Brian Colonnac1693662012-04-19 11:34:04 -0400391 mServiceRunning = true;
392 } else {
Brian Colonna257f2ec2012-04-27 13:14:22 -0400393 Log.w(TAG, "startUi() attempted while running");
Brian Colonna94313662012-04-06 13:01:29 -0400394 }
395 }
396 }
397
Brian Colonnaea8441e2012-04-25 17:51:49 -0400398 /**
Brian Colonna257f2ec2012-04-27 13:14:22 -0400399 * Tells the Face Unlock service to stop displaying its UI and stop processing.
Brian Colonnaea8441e2012-04-25 17:51:49 -0400400 */
Brian Colonna3223e252012-04-11 11:12:37 -0400401 private void stopUi() {
Brian Colonna257f2ec2012-04-27 13:14:22 -0400402 if (DEBUG) Log.d(TAG, "stopUi()");
Brian Colonnaea8441e2012-04-25 17:51:49 -0400403 // Note that attempting to stop Face Unlock when it's not running is not an issue.
404 // Face Unlock can return, which stops it and then we try to stop it when the
Brian Colonnac1693662012-04-19 11:34:04 -0400405 // screen is turned off. That's why we check.
406 synchronized (mServiceRunningLock) {
407 if (mServiceRunning) {
Brian Colonnac2660702012-05-16 22:11:30 -0400408 Log.d(TAG, "Stopping Face Unlock");
Brian Colonnac1693662012-04-19 11:34:04 -0400409 try {
Brian Colonnac1693662012-04-19 11:34:04 -0400410 mService.stopUi();
411 } catch (RemoteException e) {
Brian Colonnaea8441e2012-04-25 17:51:49 -0400412 Log.e(TAG, "Caught exception stopping Face Unlock: " + e.toString());
Brian Colonna94313662012-04-06 13:01:29 -0400413 }
Brian Colonnac1693662012-04-19 11:34:04 -0400414 mServiceRunning = false;
Brian Colonna257f2ec2012-04-27 13:14:22 -0400415 } else {
416 // This is usually not an error when this happens. Sometimes we will tell it to
417 // stop multiple times because it's called from both onWindowFocusChanged and
418 // onDetachedFromWindow.
419 if (DEBUG) Log.d(TAG, "stopUi() attempted while not running");
Brian Colonna94313662012-04-06 13:01:29 -0400420 }
421 }
422 }
423
Brian Colonnaea8441e2012-04-25 17:51:49 -0400424 /**
Brian Colonna257f2ec2012-04-27 13:14:22 -0400425 * Implements the AIDL biometric unlock service callback interface.
Brian Colonnaea8441e2012-04-25 17:51:49 -0400426 */
427 private final IFaceLockCallback mFaceUnlockCallback = new IFaceLockCallback.Stub() {
428 /**
Brian Colonna257f2ec2012-04-27 13:14:22 -0400429 * Called when Face Unlock wants to grant access to the user.
Brian Colonnaea8441e2012-04-25 17:51:49 -0400430 */
Brian Colonna94313662012-04-06 13:01:29 -0400431 public void unlock() {
Brian Colonnaea8441e2012-04-25 17:51:49 -0400432 if (DEBUG) Log.d(TAG, "unlock()");
Brian Colonna5eb83aa2012-11-19 16:05:48 -0500433 Message message = mHandler.obtainMessage(MSG_UNLOCK, UserHandle.getCallingUserId(), -1);
434 mHandler.sendMessage(message);
Brian Colonna94313662012-04-06 13:01:29 -0400435 }
436
Brian Colonnaea8441e2012-04-25 17:51:49 -0400437 /**
Brian Colonna70193252012-06-04 16:16:46 -0400438 * Called when Face Unlock wants to go to the backup.
Brian Colonnaea8441e2012-04-25 17:51:49 -0400439 */
Brian Colonna94313662012-04-06 13:01:29 -0400440 public void cancel() {
Brian Colonnaea8441e2012-04-25 17:51:49 -0400441 if (DEBUG) Log.d(TAG, "cancel()");
Brian Colonna257f2ec2012-04-27 13:14:22 -0400442 mHandler.sendEmptyMessage(MSG_CANCEL);
Brian Colonna94313662012-04-06 13:01:29 -0400443 }
444
Brian Colonnaea8441e2012-04-25 17:51:49 -0400445 /**
Brian Colonna70193252012-06-04 16:16:46 -0400446 * Called when Face Unlock wants to increment the number of failed attempts.
Brian Colonnaea8441e2012-04-25 17:51:49 -0400447 */
Brian Colonna94313662012-04-06 13:01:29 -0400448 public void reportFailedAttempt() {
Brian Colonnaea8441e2012-04-25 17:51:49 -0400449 if (DEBUG) Log.d(TAG, "reportFailedAttempt()");
Brian Colonna257f2ec2012-04-27 13:14:22 -0400450 mHandler.sendEmptyMessage(MSG_REPORT_FAILED_ATTEMPT);
Brian Colonna94313662012-04-06 13:01:29 -0400451 }
452
Brian Colonnaea8441e2012-04-25 17:51:49 -0400453 /**
Uriel Rodriguezdff30762012-05-09 16:10:41 -0400454 * Called when Face Unlock wants to keep the screen alive and active for a specific amount
455 * of time.
Brian Colonnaea8441e2012-04-25 17:51:49 -0400456 */
Uriel Rodriguezdff30762012-05-09 16:10:41 -0400457 public void pokeWakelock(int millis) {
458 if (DEBUG) Log.d(TAG, "pokeWakelock() for " + millis + "ms");
459 Message message = mHandler.obtainMessage(MSG_POKE_WAKELOCK, millis, -1);
460 mHandler.sendMessage(message);
Brian Colonna94313662012-04-06 13:01:29 -0400461 }
Uriel Rodriguezdff30762012-05-09 16:10:41 -0400462
Brian Colonna94313662012-04-06 13:01:29 -0400463 };
464}