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" ));
@@ -700,12 +709,6 @@ View createUnlockScreenFor(UnlockMode unlockMode) {
700709 mKeyguardScreenCallback ,
701710 mUpdateMonitor .getFailedAttempts ());
702711 view .setEnableFallback (mEnableFallback );
703-
704- // TODO(bcolonna): For pattern unlock, it can give us the view where the pattern is
705- // displayed and FaceLock can draw in that area.
706- // For other views it's not so simple and we should probably change how the FaceLock
707- // area is determined.
708- mFaceLockAreaView = view .getUnlockAreaView ();
709712 unlockView = view ;
710713 } else if (unlockMode == UnlockMode .SimPuk ) {
711714 unlockView = new SimPukUnlockScreen (
@@ -755,6 +758,8 @@ View createUnlockScreenFor(UnlockMode unlockMode) {
755758 throw new IllegalArgumentException ("unknown unlock mode " + unlockMode );
756759 }
757760 initializeTransportControlView (unlockView );
761+ initializeFaceLockAreaView (unlockView ); // Only shows view if FaceLock is enabled
762+
758763 mUnlockScreenMode = unlockMode ;
759764 return unlockView ;
760765 }
@@ -934,6 +939,41 @@ public int getMinimumHeight() {
934939
935940 // Everything below pertains to FaceLock - might want to separate this out
936941
942+ // Only pattern and pin unlock screens actually have a view for the FaceLock area, so it's not
943+ // uncommon for it to not exist. But if it does exist, we need to make sure it's showing if
944+ // FaceLock is enabled, and make sure it's not showing if FaceLock is disabled
945+ private void initializeFaceLockAreaView (View view ) {
946+ mFaceLockAreaView = view .findViewById (R .id .faceLockAreaView );
947+ if (mFaceLockAreaView == null ) {
948+ if (DEBUG ) Log .d (TAG , "Layout does not have faceLockAreaView" );
949+ } else {
950+ if (mLockPatternUtils .usingBiometricWeak ()) {
951+ mHandler .sendEmptyMessage (MSG_SHOW_FACELOCK_AREA_VIEW );
952+ } else {
953+ mHandler .sendEmptyMessage (MSG_HIDE_FACELOCK_AREA_VIEW );
954+ }
955+ }
956+ }
957+
958+ // Handles covering or exposing FaceLock area on the client side when FaceLock starts or stops
959+ // This needs to be done in a handler because the call could be coming from a callback from the
960+ // FaceLock service that is in a thread that can't modify the UI
961+ @ Override
962+ public boolean handleMessage (Message msg ) {
963+ switch (msg .what ) {
964+ case MSG_SHOW_FACELOCK_AREA_VIEW :
965+ mFaceLockAreaView .setVisibility (View .VISIBLE );
966+ break ;
967+ case MSG_HIDE_FACELOCK_AREA_VIEW :
968+ mFaceLockAreaView .setVisibility (View .GONE );
969+ break ;
970+ default :
971+ Log .w (TAG , "Unhandled message" );
972+ return false ;
973+ }
974+ return true ;
975+ }
976+
937977 // Binds to FaceLock service, but does not tell it to start
938978 public void bindToFaceLock () {
939979 if (mLockPatternUtils .usingBiometricWeak ()) {
@@ -982,23 +1022,20 @@ public void onServiceConnected(ComponentName className, IBinder iservice) {
9821022 throw new RuntimeException ("Remote exception" );
9831023 }
9841024
985- // TODO(bcolonna): Need to set location properly (only works for pattern view now)
9861025 if (mFaceLockAreaView != null ) {
987- int [] unlockLocationOnScreen = new int [2 ];
988- mFaceLockAreaView .getLocationOnScreen (unlockLocationOnScreen );
989- int x = unlockLocationOnScreen [0 ];
990- int y = unlockLocationOnScreen [1 ];
991- int w = mFaceLockAreaView .getWidth ();
992- int h = mFaceLockAreaView .getHeight ();
993- if (DEBUG ) Log .d (TAG , "(x,y) (wxh): (" + x + "," + y + ") (" + w + "x" + h + ")" );
994- startFaceLock (mFaceLockAreaView .getWindowToken (), x , y , w , h );
1026+ startFaceLock (mFaceLockAreaView .getWindowToken (),
1027+ mFaceLockAreaView .getLeft (), mFaceLockAreaView .getTop (),
1028+ mFaceLockAreaView .getWidth (), mFaceLockAreaView .getHeight ());
9951029 }
9961030 }
9971031
9981032 // Cleans up if FaceLock service unexpectedly disconnects
9991033 @ Override
10001034 public void onServiceDisconnected (ComponentName className ) {
1001- mFaceLockService = null ;
1035+ synchronized (mFaceLockServiceRunningLock ) {
1036+ mFaceLockService = null ;
1037+ mFaceLockServiceRunning = false ;
1038+ }
10021039 if (DEBUG ) Log .w (TAG , "Unexpected disconnect from FaceLock service" );
10031040 }
10041041 };
@@ -1007,16 +1044,18 @@ public void onServiceDisconnected(ComponentName className) {
10071044 public void startFaceLock (IBinder windowToken , int x , int y , int h , int w )
10081045 {
10091046 if (mLockPatternUtils .usingBiometricWeak ()) {
1010- if (!mFaceLockServiceRunning ) {
1011- if (DEBUG ) Log .d (TAG , "Starting FaceLock" );
1012- try {
1013- mFaceLockService .startUi (windowToken , x , y , h , w );
1014- } catch (RemoteException e ) {
1015- throw new RuntimeException ("Remote exception" );
1047+ synchronized (mFaceLockServiceRunningLock ) {
1048+ if (!mFaceLockServiceRunning ) {
1049+ if (DEBUG ) Log .d (TAG , "Starting FaceLock" );
1050+ try {
1051+ mFaceLockService .startUi (windowToken , x , y , h , w );
1052+ } catch (RemoteException e ) {
1053+ throw new RuntimeException ("Remote exception" );
1054+ }
1055+ mFaceLockServiceRunning = true ;
1056+ } else {
1057+ if (DEBUG ) Log .w (TAG , "startFaceLock() attempted while running" );
10161058 }
1017- mFaceLockServiceRunning = true ;
1018- } else {
1019- if (DEBUG ) Log .w (TAG , "startFaceLock() attempted while running" );
10201059 }
10211060 }
10221061 }
@@ -1028,14 +1067,16 @@ public void stopFaceLock()
10281067 // Note that attempting to stop FaceLock when it's not running is not an issue.
10291068 // FaceLock can return, which stops it and then we try to stop it when the
10301069 // screen is turned off. That's why we check.
1031- if (mFaceLockServiceRunning ) {
1032- try {
1033- if (DEBUG ) Log .d (TAG , "Stopping FaceLock" );
1034- mFaceLockService .stopUi ();
1035- } catch (RemoteException e ) {
1036- throw new RuntimeException ("Remote exception" );
1070+ synchronized (mFaceLockServiceRunningLock ) {
1071+ if (mFaceLockServiceRunning ) {
1072+ try {
1073+ if (DEBUG ) Log .d (TAG , "Stopping FaceLock" );
1074+ mFaceLockService .stopUi ();
1075+ } catch (RemoteException e ) {
1076+ throw new RuntimeException ("Remote exception" );
1077+ }
1078+ mFaceLockServiceRunning = false ;
10371079 }
1038- mFaceLockServiceRunning = false ;
10391080 }
10401081 }
10411082 }
@@ -1047,6 +1088,9 @@ public void stopFaceLock()
10471088 @ Override
10481089 public void unlock () {
10491090 if (DEBUG ) Log .d (TAG , "FaceLock unlock" );
1091+ // Note that we don't hide the client FaceLockAreaView because we want to keep the
1092+ // lock screen covered while the phone is unlocked
1093+
10501094 stopFaceLock ();
10511095 mKeyguardScreenCallback .keyguardDone (true );
10521096 mKeyguardScreenCallback .reportSuccessfulUnlockAttempt ();
@@ -1057,6 +1101,8 @@ public void unlock() {
10571101 public void cancel () {
10581102 // In this case, either the user has cancelled out, or FaceLock failed to recognize them
10591103 if (DEBUG ) Log .d (TAG , "FaceLock cancel" );
1104+ // Here we hide the client FaceLockViewArea to expose the underlying backup method
1105+ mHandler .sendEmptyMessage (MSG_HIDE_FACELOCK_AREA_VIEW );
10601106 stopFaceLock ();
10611107 }
10621108
@@ -1065,8 +1111,12 @@ public void cancel() {
10651111 public void sleepDevice () {
10661112 // In this case, it appears the phone has been turned on accidentally
10671113 if (DEBUG ) Log .d (TAG , "FaceLock accidental turn on" );
1114+ // Here we hide the client FaceLockViewArea to expose the underlying backup method
1115+ mHandler .sendEmptyMessage (MSG_HIDE_FACELOCK_AREA_VIEW );
10681116 stopFaceLock ();
10691117 // TODO(bcolonna): how do we put the phone back to sleep (i.e., turn off the screen)
1118+ // TODO(bcolonna): this should be removed once the service is no longer calling it
1119+ // because we are just going to let the lockscreen timeout
10701120 }
10711121 };
10721122}
0 commit comments