4646import android .graphics .PixelFormat ;
4747import android .graphics .drawable .Drawable ;
4848import android .os .Bundle ;
49+ import android .os .Handler ;
50+ import android .os .Message ;
4951import android .os .IBinder ;
5052import android .os .RemoteException ;
5153import android .os .SystemClock ;
7476 * {@link com.android.internal.policy.impl.KeyguardViewManager}
7577 * via its {@link com.android.internal.policy.impl.KeyguardViewCallback}, as appropriate.
7678 */
77- public class LockPatternKeyguardView extends KeyguardViewBase {
79+ public class LockPatternKeyguardView extends KeyguardViewBase implements Handler . Callback {
7880
7981 private static final int TRANSPORT_USERACTIVITY_TIMEOUT = 10000 ;
8082
@@ -103,9 +105,15 @@ public class LockPatternKeyguardView extends KeyguardViewBase {
103105 // The following were added to support FaceLock
104106 private IFaceLockInterface mFaceLockService ;
105107 private boolean mBoundToFaceLockService = false ;
106- private boolean mFaceLockServiceRunning = false ;
107108 private View mFaceLockAreaView ;
108109
110+ private boolean mFaceLockServiceRunning = false ;
111+ private final Object mFaceLockServiceRunningLock = new Object ();
112+
113+ private Handler mHandler ;
114+ private final int MSG_SHOW_FACELOCK_AREA_VIEW = 0 ;
115+ private final int MSG_HIDE_FACELOCK_AREA_VIEW = 1 ;
116+
109117 /**
110118 * The current {@link KeyguardScreen} will use this to communicate back to us.
111119 */
@@ -244,6 +252,7 @@ public LockPatternKeyguardView(
244252 KeyguardWindowController controller ) {
245253 super (context );
246254
255+ mHandler = new Handler (this );
247256 mConfiguration = context .getResources ().getConfiguration ();
248257 mEnableFallback = false ;
249258 mRequiresSim = TextUtils .isEmpty (SystemProperties .get ("keyguard.no_require_sim" ));
@@ -704,12 +713,6 @@ View createUnlockScreenFor(UnlockMode unlockMode) {
704713 mKeyguardScreenCallback ,
705714 mUpdateMonitor .getFailedAttempts ());
706715 view .setEnableFallback (mEnableFallback );
707-
708- // TODO(bcolonna): For pattern unlock, it can give us the view where the pattern is
709- // displayed and FaceLock can draw in that area.
710- // For other views it's not so simple and we should probably change how the FaceLock
711- // area is determined.
712- mFaceLockAreaView = view .getUnlockAreaView ();
713716 unlockView = view ;
714717 } else if (unlockMode == UnlockMode .SimPuk ) {
715718 unlockView = new SimPukUnlockScreen (
@@ -759,6 +762,8 @@ View createUnlockScreenFor(UnlockMode unlockMode) {
759762 throw new IllegalArgumentException ("unknown unlock mode " + unlockMode );
760763 }
761764 initializeTransportControlView (unlockView );
765+ initializeFaceLockAreaView (unlockView ); // Only shows view if FaceLock is enabled
766+
762767 mUnlockScreenMode = unlockMode ;
763768 return unlockView ;
764769 }
@@ -938,6 +943,41 @@ public int getMinimumHeight() {
938943
939944 // Everything below pertains to FaceLock - might want to separate this out
940945
946+ // Only pattern and pin unlock screens actually have a view for the FaceLock area, so it's not
947+ // uncommon for it to not exist. But if it does exist, we need to make sure it's showing if
948+ // FaceLock is enabled, and make sure it's not showing if FaceLock is disabled
949+ private void initializeFaceLockAreaView (View view ) {
950+ mFaceLockAreaView = view .findViewById (R .id .faceLockAreaView );
951+ if (mFaceLockAreaView == null ) {
952+ if (DEBUG ) Log .d (TAG , "Layout does not have faceLockAreaView" );
953+ } else {
954+ if (mLockPatternUtils .usingBiometricWeak ()) {
955+ mHandler .sendEmptyMessage (MSG_SHOW_FACELOCK_AREA_VIEW );
956+ } else {
957+ mHandler .sendEmptyMessage (MSG_HIDE_FACELOCK_AREA_VIEW );
958+ }
959+ }
960+ }
961+
962+ // Handles covering or exposing FaceLock area on the client side when FaceLock starts or stops
963+ // This needs to be done in a handler because the call could be coming from a callback from the
964+ // FaceLock service that is in a thread that can't modify the UI
965+ @ Override
966+ public boolean handleMessage (Message msg ) {
967+ switch (msg .what ) {
968+ case MSG_SHOW_FACELOCK_AREA_VIEW :
969+ mFaceLockAreaView .setVisibility (View .VISIBLE );
970+ break ;
971+ case MSG_HIDE_FACELOCK_AREA_VIEW :
972+ mFaceLockAreaView .setVisibility (View .GONE );
973+ break ;
974+ default :
975+ Log .w (TAG , "Unhandled message" );
976+ return false ;
977+ }
978+ return true ;
979+ }
980+
941981 // Binds to FaceLock service, but does not tell it to start
942982 public void bindToFaceLock () {
943983 if (mLockPatternUtils .usingBiometricWeak ()) {
@@ -986,23 +1026,20 @@ public void onServiceConnected(ComponentName className, IBinder iservice) {
9861026 throw new RuntimeException ("Remote exception" );
9871027 }
9881028
989- // TODO(bcolonna): Need to set location properly (only works for pattern view now)
9901029 if (mFaceLockAreaView != null ) {
991- int [] unlockLocationOnScreen = new int [2 ];
992- mFaceLockAreaView .getLocationOnScreen (unlockLocationOnScreen );
993- int x = unlockLocationOnScreen [0 ];
994- int y = unlockLocationOnScreen [1 ];
995- int w = mFaceLockAreaView .getWidth ();
996- int h = mFaceLockAreaView .getHeight ();
997- if (DEBUG ) Log .d (TAG , "(x,y) (wxh): (" + x + "," + y + ") (" + w + "x" + h + ")" );
998- startFaceLock (mFaceLockAreaView .getWindowToken (), x , y , w , h );
1030+ startFaceLock (mFaceLockAreaView .getWindowToken (),
1031+ mFaceLockAreaView .getLeft (), mFaceLockAreaView .getTop (),
1032+ mFaceLockAreaView .getWidth (), mFaceLockAreaView .getHeight ());
9991033 }
10001034 }
10011035
10021036 // Cleans up if FaceLock service unexpectedly disconnects
10031037 @ Override
10041038 public void onServiceDisconnected (ComponentName className ) {
1005- mFaceLockService = null ;
1039+ synchronized (mFaceLockServiceRunningLock ) {
1040+ mFaceLockService = null ;
1041+ mFaceLockServiceRunning = false ;
1042+ }
10061043 if (DEBUG ) Log .w (TAG , "Unexpected disconnect from FaceLock service" );
10071044 }
10081045 };
@@ -1011,16 +1048,18 @@ public void onServiceDisconnected(ComponentName className) {
10111048 public void startFaceLock (IBinder windowToken , int x , int y , int h , int w )
10121049 {
10131050 if (mLockPatternUtils .usingBiometricWeak ()) {
1014- if (!mFaceLockServiceRunning ) {
1015- if (DEBUG ) Log .d (TAG , "Starting FaceLock" );
1016- try {
1017- mFaceLockService .startUi (windowToken , x , y , h , w );
1018- } catch (RemoteException e ) {
1019- throw new RuntimeException ("Remote exception" );
1051+ synchronized (mFaceLockServiceRunningLock ) {
1052+ if (!mFaceLockServiceRunning ) {
1053+ if (DEBUG ) Log .d (TAG , "Starting FaceLock" );
1054+ try {
1055+ mFaceLockService .startUi (windowToken , x , y , h , w );
1056+ } catch (RemoteException e ) {
1057+ throw new RuntimeException ("Remote exception" );
1058+ }
1059+ mFaceLockServiceRunning = true ;
1060+ } else {
1061+ if (DEBUG ) Log .w (TAG , "startFaceLock() attempted while running" );
10201062 }
1021- mFaceLockServiceRunning = true ;
1022- } else {
1023- if (DEBUG ) Log .w (TAG , "startFaceLock() attempted while running" );
10241063 }
10251064 }
10261065 }
@@ -1032,14 +1071,16 @@ public void stopFaceLock()
10321071 // Note that attempting to stop FaceLock when it's not running is not an issue.
10331072 // FaceLock can return, which stops it and then we try to stop it when the
10341073 // screen is turned off. That's why we check.
1035- if (mFaceLockServiceRunning ) {
1036- try {
1037- if (DEBUG ) Log .d (TAG , "Stopping FaceLock" );
1038- mFaceLockService .stopUi ();
1039- } catch (RemoteException e ) {
1040- throw new RuntimeException ("Remote exception" );
1074+ synchronized (mFaceLockServiceRunningLock ) {
1075+ if (mFaceLockServiceRunning ) {
1076+ try {
1077+ if (DEBUG ) Log .d (TAG , "Stopping FaceLock" );
1078+ mFaceLockService .stopUi ();
1079+ } catch (RemoteException e ) {
1080+ throw new RuntimeException ("Remote exception" );
1081+ }
1082+ mFaceLockServiceRunning = false ;
10411083 }
1042- mFaceLockServiceRunning = false ;
10431084 }
10441085 }
10451086 }
@@ -1051,6 +1092,9 @@ public void stopFaceLock()
10511092 @ Override
10521093 public void unlock () {
10531094 if (DEBUG ) Log .d (TAG , "FaceLock unlock" );
1095+ // Note that we don't hide the client FaceLockAreaView because we want to keep the
1096+ // lock screen covered while the phone is unlocked
1097+
10541098 stopFaceLock ();
10551099 mKeyguardScreenCallback .keyguardDone (true );
10561100 mKeyguardScreenCallback .reportSuccessfulUnlockAttempt ();
@@ -1061,6 +1105,8 @@ public void unlock() {
10611105 public void cancel () {
10621106 // In this case, either the user has cancelled out, or FaceLock failed to recognize them
10631107 if (DEBUG ) Log .d (TAG , "FaceLock cancel" );
1108+ // Here we hide the client FaceLockViewArea to expose the underlying backup method
1109+ mHandler .sendEmptyMessage (MSG_HIDE_FACELOCK_AREA_VIEW );
10641110 stopFaceLock ();
10651111 }
10661112
@@ -1069,8 +1115,12 @@ public void cancel() {
10691115 public void sleepDevice () {
10701116 // In this case, it appears the phone has been turned on accidentally
10711117 if (DEBUG ) Log .d (TAG , "FaceLock accidental turn on" );
1118+ // Here we hide the client FaceLockViewArea to expose the underlying backup method
1119+ mHandler .sendEmptyMessage (MSG_HIDE_FACELOCK_AREA_VIEW );
10721120 stopFaceLock ();
10731121 // TODO(bcolonna): how do we put the phone back to sleep (i.e., turn off the screen)
1122+ // TODO(bcolonna): this should be removed once the service is no longer calling it
1123+ // because we are just going to let the lockscreen timeout
10741124 }
10751125 };
10761126}
0 commit comments