Skip to content

Commit 61413b5

Browse files
author
Danielle Millett
committed
Face Unlock is shown correctly during a phone call - fix b/7271718
If the user was in the middle of a phone call and went to the lock screen it would show a black box with an X, but Face Unlock wouldn't pop up and the X was unresponsive. There were a few issues causing this. The X on the default view wasn't a button, so it has been changed to a button which will go to the backup lock. The concept of show() and hide() in FaceUnlock.java are obsolete because Face Unlock is no longer being overlayed on top of the backup so there's isn't a black box to show or hide. In addition, since it's not being overlayed, Face Unlock doesn't cover the backup lock so fading to the backup looks janky. The flip animation is more appropriate. Change-Id: I730aa4bbce42b4656ee1bce61352b8aefbd6892d
1 parent 6be35dd commit 61413b5

File tree

6 files changed

+53
-114
lines changed

6 files changed

+53
-114
lines changed

core/res/res/layout/keyguard_face_unlock_view.xml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,13 +46,14 @@
4646
android:background="@color/facelock_spotlight_mask"
4747
/>
4848

49-
<ImageView
50-
android:id="@+id/cancel_button"
49+
<ImageButton
50+
android:id="@+id/face_unlock_cancel_button"
5151
android:layout_width="wrap_content"
5252
android:layout_height="wrap_content"
5353
android:padding="5dip"
5454
android:layout_alignParentTop="true"
5555
android:layout_alignParentEnd="true"
56+
android:background="#00000000"
5657
android:src="@drawable/ic_facial_backup"
5758
/>
5859

core/res/res/values/symbols.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1230,6 +1230,7 @@
12301230
<java-symbol type="id" name="eight" />
12311231
<java-symbol type="id" name="emergencyCallButton" />
12321232
<java-symbol type="id" name="face_unlock_area_view" />
1233+
<java-symbol type="id" name="face_unlock_cancel_button" />
12331234
<java-symbol type="id" name="five" />
12341235
<java-symbol type="id" name="forgotPatternButton" />
12351236
<java-symbol type="id" name="four" />

policy/src/com/android/internal/policy/impl/keyguard/BiometricSensorUnlock.java

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -37,21 +37,9 @@ interface BiometricSensorUnlock {
3737
public boolean isRunning();
3838

3939
/**
40-
* Covers the backup unlock mechanism by showing the contents of the view initialized in
41-
* {@link BiometricSensorUnlock#initializeView(View)}. The view should disappear after the
42-
* specified timeout. If the timeout is 0, the interface shows until another event, such as
43-
* calling {@link BiometricSensorUnlock#hide()}, causes it to disappear. Called on the UI
44-
* thread.
45-
* @param timeoutMilliseconds Amount of time in milliseconds to display the view before
46-
* disappearing. A value of 0 means the view should remain visible.
47-
*/
48-
public void show(long timeoutMilliseconds);
49-
50-
/**
51-
* Uncovers the backup unlock mechanism by hiding the contents of the view initialized in
52-
* {@link BiometricSensorUnlock#initializeView(View)}.
40+
* Stops and removes the biometric unlock and shows the backup unlock
5341
*/
54-
public void hide();
42+
public void stopAndShowBackup();
5543

5644
/**
5745
* Binds to the biometric unlock service and starts the unlock procedure. Called on the UI

policy/src/com/android/internal/policy/impl/keyguard/FaceUnlock.java

Lines changed: 15 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -52,26 +52,19 @@ public class FaceUnlock implements BiometricSensorUnlock, Handler.Callback {
5252
private View mFaceUnlockView;
5353

5454
private Handler mHandler;
55-
private final int MSG_SHOW_FACE_UNLOCK_VIEW = 0;
56-
private final int MSG_HIDE_FACE_UNLOCK_VIEW = 1;
57-
private final int MSG_SERVICE_CONNECTED = 2;
58-
private final int MSG_SERVICE_DISCONNECTED = 3;
59-
private final int MSG_UNLOCK = 4;
60-
private final int MSG_CANCEL = 5;
61-
private final int MSG_REPORT_FAILED_ATTEMPT = 6;
62-
private final int MSG_EXPOSE_FALLBACK = 7;
63-
private final int MSG_POKE_WAKELOCK = 8;
55+
private final int MSG_SERVICE_CONNECTED = 0;
56+
private final int MSG_SERVICE_DISCONNECTED = 1;
57+
private final int MSG_UNLOCK = 2;
58+
private final int MSG_CANCEL = 3;
59+
private final int MSG_REPORT_FAILED_ATTEMPT = 4;
60+
private final int MSG_EXPOSE_FALLBACK = 5;
61+
private final int MSG_POKE_WAKELOCK = 6;
6462

6563
// TODO: This was added for the purpose of adhering to what the biometric interface expects
6664
// the isRunning() function to return. However, it is probably not necessary to have both
6765
// mRunning and mServiceRunning. I'd just rather wait to change that logic.
6866
private volatile boolean mIsRunning = false;
6967

70-
// Long enough to stay visible while the service starts
71-
// Short enough to not have to wait long for backup if service fails to start or crashes
72-
// The service can take a couple of seconds to start on the first try after boot
73-
private final int SERVICE_STARTUP_VIEW_TIMEOUT = 3000;
74-
7568
// So the user has a consistent amount of time when brought to the backup method from Face
7669
// Unlock
7770
private final int BACKUP_LOCK_TIMEOUT = 5000;
@@ -110,30 +103,11 @@ public boolean isRunning() {
110103
}
111104

112105
/**
113-
* Sets the Face Unlock view to visible, hiding it after the specified amount of time. If
114-
* timeoutMillis is 0, no hide is performed. Called on the UI thread.
106+
* Dismisses face unlock and goes to the backup lock
115107
*/
116-
public void show(long timeoutMillis) {
117-
if (DEBUG) Log.d(TAG, "show()");
118-
if (mHandler.getLooper() != Looper.myLooper()) {
119-
Log.e(TAG, "show() called off of the UI thread");
120-
}
121-
removeDisplayMessages();
122-
if (timeoutMillis > 0) {
123-
mHandler.sendEmptyMessageDelayed(MSG_HIDE_FACE_UNLOCK_VIEW, timeoutMillis);
124-
}
125-
}
126-
127-
/**
128-
* Hides the Face Unlock view.
129-
*/
130-
public void hide() {
131-
if (DEBUG) Log.d(TAG, "hide()");
132-
// Removes any wakelock messages to make sure they don't cause the screen to turn back on.
133-
mHandler.removeMessages(MSG_POKE_WAKELOCK);
134-
// Remove messages to prevent a delayed show message from undo-ing the hide
135-
removeDisplayMessages();
136-
mHandler.sendEmptyMessage(MSG_HIDE_FACE_UNLOCK_VIEW);
108+
public void stopAndShowBackup() {
109+
if (DEBUG) Log.d(TAG, "stopAndShowBackup()");
110+
mHandler.sendEmptyMessage(MSG_CANCEL);
137111
}
138112

139113
/**
@@ -151,10 +125,6 @@ public boolean start() {
151125
Log.w(TAG, "start() called when already running");
152126
}
153127

154-
// Show Face Unlock view, but only for a little bit so lockpattern will become visible if
155-
// Face Unlock fails to start or crashes
156-
// This must show before bind to guarantee that Face Unlock has a place to display
157-
show(SERVICE_STARTUP_VIEW_TIMEOUT);
158128
if (!mBoundToService) {
159129
Log.d(TAG, "Binding to Face Unlock service for user="
160130
+ mLockPatternUtils.getCurrentUser());
@@ -234,12 +204,6 @@ public int getQuality() {
234204
*/
235205
public boolean handleMessage(Message msg) {
236206
switch (msg.what) {
237-
case MSG_SHOW_FACE_UNLOCK_VIEW:
238-
handleShowFaceUnlockView();
239-
break;
240-
case MSG_HIDE_FACE_UNLOCK_VIEW:
241-
handleHideFaceUnlockView();
242-
break;
243207
case MSG_SERVICE_CONNECTED:
244208
handleServiceConnected();
245209
break;
@@ -268,22 +232,6 @@ public boolean handleMessage(Message msg) {
268232
return true;
269233
}
270234

271-
/**
272-
* Sets the Face Unlock view to visible, thus covering the backup lock.
273-
*/
274-
void handleShowFaceUnlockView() {
275-
if (DEBUG) Log.d(TAG, "handleShowFaceUnlockView()");
276-
// Not required
277-
}
278-
279-
/**
280-
* Hide face unlock and show backup
281-
*/
282-
void handleHideFaceUnlockView() {
283-
if (DEBUG) Log.d(TAG, "handleHideFaceUnlockView()");
284-
mKeyguardScreenCallback.showBackupSecurity();
285-
}
286-
287235
/**
288236
* Tells the service to start its UI via an AIDL interface. Called when the
289237
* onServiceConnected() callback is received.
@@ -347,23 +295,21 @@ void handleServiceDisconnected() {
347295
}
348296

349297
/**
350-
* Stops the Face Unlock service and tells the device to grant access to the user. Shows the
351-
* Face Unlock view to keep the backup lock covered while the device unlocks.
298+
* Stops the Face Unlock service and tells the device to grant access to the user.
352299
*/
353300
void handleUnlock() {
354301
if (DEBUG) Log.d(TAG, "handleUnlock()");
355-
removeDisplayMessages();
356302
stop();
357303
mKeyguardScreenCallback.reportSuccessfulUnlockAttempt();
358304
mKeyguardScreenCallback.dismiss(true);
359305
}
360306

361307
/**
362-
* Stops the Face Unlock service and exposes the backup lock.
308+
* Stops the Face Unlock service and goes to the backup lock.
363309
*/
364310
void handleCancel() {
365311
if (DEBUG) Log.d(TAG, "handleCancel()");
366-
mKeyguardScreenCallback.dismiss(false);
312+
mKeyguardScreenCallback.showBackupSecurity();
367313
stop();
368314
mKeyguardScreenCallback.userActivity(BACKUP_LOCK_TIMEOUT);
369315
}
@@ -397,15 +343,6 @@ void handlePokeWakelock(int millis) {
397343
}
398344
}
399345

400-
/**
401-
* Removes show and hide messages from the message queue. Called to prevent delayed show/hide
402-
* messages from undoing a new message.
403-
*/
404-
private void removeDisplayMessages() {
405-
mHandler.removeMessages(MSG_SHOW_FACE_UNLOCK_VIEW);
406-
mHandler.removeMessages(MSG_HIDE_FACE_UNLOCK_VIEW);
407-
}
408-
409346
/**
410347
* Implements service connection methods.
411348
*/
@@ -508,7 +445,7 @@ public void reportFailedAttempt() {
508445
* Called when the Face Unlock service starts displaying the UI, indicating that the backup
509446
* unlock can be exposed because the Face Unlock service is now covering the backup with its
510447
* UI.
511-
**/
448+
*/
512449
public void exposeFallback() {
513450
if (DEBUG) Log.d(TAG, "exposeFallback()");
514451
mHandler.sendEmptyMessage(MSG_EXPOSE_FALLBACK);

policy/src/com/android/internal/policy/impl/keyguard/KeyguardFaceUnlockView.java

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import android.util.AttributeSet;
2121
import android.util.Log;
2222
import android.view.View;
23+
import android.widget.ImageButton;
2324
import android.widget.LinearLayout;
2425

2526
import com.android.internal.R;
@@ -29,11 +30,13 @@
2930
public class KeyguardFaceUnlockView extends LinearLayout implements KeyguardSecurityView {
3031

3132
private static final String TAG = "KeyguardFaceUnlockView";
33+
private static final boolean DEBUG = false;
3234
private KeyguardSecurityCallback mKeyguardSecurityCallback;
3335
private LockPatternUtils mLockPatternUtils;
3436
private BiometricSensorUnlock mBiometricUnlock;
3537
private KeyguardNavigationManager mNavigationManager;
3638
private View mFaceUnlockAreaView;
39+
private ImageButton mCancelButton;
3740

3841
public KeyguardFaceUnlockView(Context context) {
3942
this(context, null);
@@ -70,25 +73,25 @@ public void reset() {
7073

7174
@Override
7275
public void onDetachedFromWindow() {
76+
if (DEBUG) Log.d(TAG, "onDetachedFromWindow()");
7377
if (mBiometricUnlock != null) {
74-
mBiometricUnlock.hide();
75-
mBiometricUnlock.stop();
78+
mBiometricUnlock.stopAndShowBackup();
7679
}
7780
}
7881

7982
@Override
8083
public void onPause() {
84+
if (DEBUG) Log.d(TAG, "onPause()");
8185
if (mBiometricUnlock != null) {
82-
mBiometricUnlock.hide();
83-
mBiometricUnlock.stop();
86+
mBiometricUnlock.stopAndShowBackup();
8487
}
8588
KeyguardUpdateMonitor.getInstance(mContext).removeCallback(mUpdateCallback);
8689
}
8790

8891
@Override
8992
public void onResume() {
93+
if (DEBUG) Log.d(TAG, "onResume()");
9094
maybeStartBiometricUnlock();
91-
mBiometricUnlock.show(0);
9295
KeyguardUpdateMonitor.getInstance(mContext).registerCallback(mUpdateCallback);
9396
}
9497

@@ -112,6 +115,14 @@ private void initializeBiometricUnlockView() {
112115
mFaceUnlockAreaView = findViewById(R.id.face_unlock_area_view);
113116
if (mFaceUnlockAreaView != null) {
114117
mBiometricUnlock = new FaceUnlock(mContext);
118+
119+
mCancelButton = (ImageButton) findViewById(R.id.face_unlock_cancel_button);
120+
mCancelButton.setOnClickListener(new OnClickListener() {
121+
@Override
122+
public void onClick(View v) {
123+
mBiometricUnlock.stopAndShowBackup();
124+
}
125+
});
115126
} else {
116127
Log.w(TAG, "Couldn't find biometric unlock view");
117128
}
@@ -123,17 +134,20 @@ private void initializeBiometricUnlockView() {
123134
* unlock area.
124135
*/
125136
private void maybeStartBiometricUnlock() {
137+
if (DEBUG) Log.d(TAG, "maybeStartBiometricUnlock()");
126138
if (mBiometricUnlock != null) {
127139
KeyguardUpdateMonitor monitor = KeyguardUpdateMonitor.getInstance(mContext);
128140
final boolean backupIsTimedOut = (
129141
monitor.getFailedUnlockAttempts() >=
130142
LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT);
131-
if (monitor.getPhoneState() == TelephonyManager.CALL_STATE_IDLE
143+
// TODO: These max attempts checks are also checked in KeyguardSecurityModel so they
144+
// might not be necessary here anymore.
145+
if (monitor.getPhoneState() != TelephonyManager.CALL_STATE_RINGING
132146
&& !monitor.getMaxBiometricUnlockAttemptsReached()
133147
&& !backupIsTimedOut) {
134148
mBiometricUnlock.start();
135149
} else {
136-
mBiometricUnlock.hide();
150+
mBiometricUnlock.stopAndShowBackup();
137151
}
138152
}
139153
}
@@ -142,14 +156,15 @@ private void maybeStartBiometricUnlock() {
142156
// We need to stop the biometric unlock when a phone call comes in
143157
@Override
144158
public void onPhoneStateChanged(int phoneState) {
159+
if (DEBUG) Log.d(TAG, "onPhoneStateChanged(" + phoneState + ")");
145160
if (phoneState == TelephonyManager.CALL_STATE_RINGING) {
146-
mBiometricUnlock.stop();
147-
mBiometricUnlock.hide();
161+
mBiometricUnlock.stopAndShowBackup();
148162
}
149163
}
150164

151165
@Override
152166
public void onUserSwitched(int userId) {
167+
if (DEBUG) Log.d(TAG, "onUserSwitched(" + userId + ")");
153168
if (mBiometricUnlock != null) {
154169
mBiometricUnlock.stop();
155170
}

policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -403,6 +403,7 @@ private void reportFailedUnlockAttempt() {
403403
* account unlock screen and biometric unlock to show the user's normal unlock.
404404
*/
405405
private void showBackupSecurity() {
406+
if (DEBUG) Log.d(TAG, "showBackupSecurity()");
406407
showSecurityScreen(mSecurityModel.getBackupSecurityMode());
407408
}
408409

@@ -419,6 +420,7 @@ public boolean showNextSecurityScreenIfPresent() {
419420
}
420421

421422
private void showNextSecurityScreenOrFinish(boolean authenticated) {
423+
if (DEBUG) Log.d(TAG, "showNextSecurityScreenOrFinish(" + authenticated + ")");
422424
boolean finish = false;
423425
if (SecurityMode.None == mCurrentSecuritySelection) {
424426
SecurityMode securityMode = mSecurityModel.getSecurityMode();
@@ -547,7 +549,7 @@ private KeyguardSecurityView getSecurityView(SecurityMode securityMode) {
547549
* @param securityMode
548550
*/
549551
private void showSecurityScreen(SecurityMode securityMode) {
550-
552+
if (DEBUG) Log.d(TAG, "showSecurityScreen");
551553
if (securityMode == mCurrentSecuritySelection) return;
552554

553555
KeyguardSecurityView oldView = getSecurityView(mCurrentSecuritySelection);
@@ -565,16 +567,11 @@ private void showSecurityScreen(SecurityMode securityMode) {
565567
// Find and show this child.
566568
final int childCount = mSecurityViewContainer.getChildCount();
567569

568-
// If we're go to/from the selector view, do flip animation, otherwise use fade animation.
569-
final boolean doFlip = mCurrentSecuritySelection == SecurityMode.None
570-
|| securityMode == SecurityMode.None;
571-
final int inAnimation = doFlip ? R.anim.keyguard_security_animate_in
572-
: R.anim.keyguard_security_fade_in;
573-
final int outAnimation = doFlip ? R.anim.keyguard_security_animate_out
574-
: R.anim.keyguard_security_fade_out;
575-
576-
mSecurityViewContainer.setInAnimation(AnimationUtils.loadAnimation(mContext, inAnimation));
577-
mSecurityViewContainer.setOutAnimation(AnimationUtils.loadAnimation(mContext, outAnimation));
570+
// Do flip animation to the next screen
571+
mSecurityViewContainer.setInAnimation(
572+
AnimationUtils.loadAnimation(mContext, R.anim.keyguard_security_animate_in));
573+
mSecurityViewContainer.setOutAnimation(
574+
AnimationUtils.loadAnimation(mContext, R.anim.keyguard_security_animate_out));
578575
final int securityViewIdForMode = getSecurityViewIdForMode(securityMode);
579576
for (int i = 0; i < childCount; i++) {
580577
if (mSecurityViewContainer.getChildAt(i).getId() == securityViewIdForMode) {

0 commit comments

Comments
 (0)