Home | History | Annotate | Download | only in keyguard
      1 /*
      2  * Copyright (C) 2012 The Android Open Source Project
      3  *
      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 package com.android.keyguard;
     17 
     18 import android.content.Context;
     19 import android.graphics.drawable.Drawable;
     20 import android.os.PowerManager;
     21 import android.os.RemoteException;
     22 import android.os.ServiceManager;
     23 import android.telephony.TelephonyManager;
     24 import android.util.AttributeSet;
     25 import android.util.Log;
     26 import android.view.IRotationWatcher;
     27 import android.view.IWindowManager;
     28 import android.view.View;
     29 import android.widget.ImageButton;
     30 import android.widget.LinearLayout;
     31 
     32 import com.android.internal.widget.LockPatternUtils;
     33 
     34 import java.lang.Math;
     35 
     36 public class KeyguardFaceUnlockView extends LinearLayout implements KeyguardSecurityView {
     37 
     38     private static final String TAG = "FULKeyguardFaceUnlockView";
     39     private static final boolean DEBUG = false;
     40     private KeyguardSecurityCallback mKeyguardSecurityCallback;
     41     private LockPatternUtils mLockPatternUtils;
     42     private BiometricSensorUnlock mBiometricUnlock;
     43     private View mFaceUnlockAreaView;
     44     private ImageButton mCancelButton;
     45     private SecurityMessageDisplay mSecurityMessageDisplay;
     46     private View mEcaView;
     47     private Drawable mBouncerFrame;
     48 
     49     private boolean mIsShowing = false;
     50     private final Object mIsShowingLock = new Object();
     51 
     52     private int mLastRotation;
     53     private boolean mWatchingRotation;
     54     private final IWindowManager mWindowManager =
     55             IWindowManager.Stub.asInterface(ServiceManager.getService("window"));
     56 
     57     private final IRotationWatcher mRotationWatcher = new IRotationWatcher.Stub() {
     58         public void onRotationChanged(int rotation) {
     59             if (DEBUG) Log.d(TAG, "onRotationChanged(): " + mLastRotation + "->" + rotation);
     60 
     61             // If the difference between the new rotation value and the previous rotation value is
     62             // equal to 2, the rotation change was 180 degrees.  This stops the biometric unlock
     63             // and starts it in the new position.  This is not performed for 90 degree rotations
     64             // since a 90 degree rotation is a configuration change, which takes care of this for
     65             // us.
     66             if (Math.abs(rotation - mLastRotation) == 2) {
     67                 if (mBiometricUnlock != null) {
     68                     mBiometricUnlock.stop();
     69                     maybeStartBiometricUnlock();
     70                 }
     71             }
     72             mLastRotation = rotation;
     73         }
     74     };
     75 
     76     public KeyguardFaceUnlockView(Context context) {
     77         this(context, null);
     78     }
     79 
     80     public KeyguardFaceUnlockView(Context context, AttributeSet attrs) {
     81         super(context, attrs);
     82     }
     83 
     84     @Override
     85     protected void onFinishInflate() {
     86         super.onFinishInflate();
     87 
     88         initializeBiometricUnlockView();
     89 
     90         mSecurityMessageDisplay = new KeyguardMessageArea.Helper(this);
     91         mEcaView = findViewById(R.id.keyguard_selector_fade_container);
     92         View bouncerFrameView = findViewById(R.id.keyguard_bouncer_frame);
     93         if (bouncerFrameView != null) {
     94             mBouncerFrame = bouncerFrameView.getBackground();
     95         }
     96     }
     97 
     98     @Override
     99     public void setKeyguardCallback(KeyguardSecurityCallback callback) {
    100         mKeyguardSecurityCallback = callback;
    101         // TODO: formalize this in the interface or factor it out
    102         ((FaceUnlock)mBiometricUnlock).setKeyguardCallback(callback);
    103     }
    104 
    105     @Override
    106     public void setLockPatternUtils(LockPatternUtils utils) {
    107         mLockPatternUtils = utils;
    108     }
    109 
    110     @Override
    111     public void reset() {
    112 
    113     }
    114 
    115     @Override
    116     public void onDetachedFromWindow() {
    117         if (DEBUG) Log.d(TAG, "onDetachedFromWindow()");
    118         if (mBiometricUnlock != null) {
    119             mBiometricUnlock.stop();
    120         }
    121         KeyguardUpdateMonitor.getInstance(mContext).removeCallback(mUpdateCallback);
    122         if (mWatchingRotation) {
    123             try {
    124                 mWindowManager.removeRotationWatcher(mRotationWatcher);
    125                 mWatchingRotation = false;
    126             } catch (RemoteException e) {
    127                 Log.e(TAG, "Remote exception when removing rotation watcher");
    128             }
    129         }
    130     }
    131 
    132     @Override
    133     public void onPause() {
    134         if (DEBUG) Log.d(TAG, "onPause()");
    135         if (mBiometricUnlock != null) {
    136             mBiometricUnlock.stop();
    137         }
    138         KeyguardUpdateMonitor.getInstance(mContext).removeCallback(mUpdateCallback);
    139         if (mWatchingRotation) {
    140             try {
    141                 mWindowManager.removeRotationWatcher(mRotationWatcher);
    142                 mWatchingRotation = false;
    143             } catch (RemoteException e) {
    144                 Log.e(TAG, "Remote exception when removing rotation watcher");
    145             }
    146         }
    147     }
    148 
    149     @Override
    150     public void onResume(int reason) {
    151         if (DEBUG) Log.d(TAG, "onResume()");
    152         mIsShowing = KeyguardUpdateMonitor.getInstance(mContext).isKeyguardVisible();
    153         if (!KeyguardUpdateMonitor.getInstance(mContext).isSwitchingUser()) {
    154           maybeStartBiometricUnlock();
    155         }
    156         KeyguardUpdateMonitor.getInstance(mContext).registerCallback(mUpdateCallback);
    157 
    158         // Registers a callback which handles stopping the biometric unlock and restarting it in
    159         // the new position for a 180 degree rotation change.
    160         if (!mWatchingRotation) {
    161             try {
    162                 mLastRotation = mWindowManager.watchRotation(mRotationWatcher);
    163                 mWatchingRotation = true;
    164             } catch (RemoteException e) {
    165                 Log.e(TAG, "Remote exception when adding rotation watcher");
    166             }
    167         }
    168     }
    169 
    170     @Override
    171     public boolean needsInput() {
    172         return false;
    173     }
    174 
    175     @Override
    176     public KeyguardSecurityCallback getCallback() {
    177         return mKeyguardSecurityCallback;
    178     }
    179 
    180     @Override
    181     protected void onLayout(boolean changed, int l, int t, int r, int b) {
    182         super.onLayout(changed, l, t, r, b);
    183         mBiometricUnlock.initializeView(mFaceUnlockAreaView);
    184     }
    185 
    186     private void initializeBiometricUnlockView() {
    187         if (DEBUG) Log.d(TAG, "initializeBiometricUnlockView()");
    188         mFaceUnlockAreaView = findViewById(R.id.face_unlock_area_view);
    189         if (mFaceUnlockAreaView != null) {
    190             mBiometricUnlock = new FaceUnlock(mContext);
    191 
    192             mCancelButton = (ImageButton) findViewById(R.id.face_unlock_cancel_button);
    193             mCancelButton.setOnClickListener(new OnClickListener() {
    194                 @Override
    195                 public void onClick(View v) {
    196                     mBiometricUnlock.stopAndShowBackup();
    197                 }
    198             });
    199         } else {
    200             Log.w(TAG, "Couldn't find biometric unlock view");
    201         }
    202     }
    203 
    204     /**
    205      * Starts the biometric unlock if it should be started based on a number of factors.  If it
    206      * should not be started, it either goes to the back up, or remains showing to prepare for
    207      * it being started later.
    208      */
    209     private void maybeStartBiometricUnlock() {
    210         if (DEBUG) Log.d(TAG, "maybeStartBiometricUnlock()");
    211         if (mBiometricUnlock != null) {
    212             KeyguardUpdateMonitor monitor = KeyguardUpdateMonitor.getInstance(mContext);
    213             final boolean backupIsTimedOut = (
    214                     monitor.getFailedUnlockAttempts() >=
    215                     LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT);
    216             PowerManager powerManager = (PowerManager) mContext.getSystemService(
    217                     Context.POWER_SERVICE);
    218 
    219             boolean isShowing;
    220             synchronized(mIsShowingLock) {
    221                 isShowing = mIsShowing;
    222             }
    223 
    224             // Don't start it if the screen is off or if it's not showing, but keep this view up
    225             // because we want it here and ready for when the screen turns on or when it does start
    226             // showing.
    227             if (!powerManager.isScreenOn() || !isShowing) {
    228                 mBiometricUnlock.stop(); // It shouldn't be running but calling this can't hurt.
    229                 return;
    230             }
    231 
    232             // Although these same conditions are handled in KeyguardSecurityModel, they are still
    233             // necessary here.  When a tablet is rotated 90 degrees, a configuration change is
    234             // triggered and everything is torn down and reconstructed.  That means
    235             // KeyguardSecurityModel gets a chance to take care of the logic and doesn't even
    236             // reconstruct KeyguardFaceUnlockView if the biometric unlock should be suppressed.
    237             // However, for a 180 degree rotation, no configuration change is triggered, so only
    238             // the logic here is capable of suppressing Face Unlock.
    239             if (monitor.getPhoneState() == TelephonyManager.CALL_STATE_IDLE
    240                     && monitor.isAlternateUnlockEnabled()
    241                     && !monitor.getMaxBiometricUnlockAttemptsReached()
    242                     && !backupIsTimedOut) {
    243                 mBiometricUnlock.start();
    244             } else {
    245                 mBiometricUnlock.stopAndShowBackup();
    246             }
    247         }
    248     }
    249 
    250     KeyguardUpdateMonitorCallback mUpdateCallback = new KeyguardUpdateMonitorCallback() {
    251         // We need to stop the biometric unlock when a phone call comes in
    252         @Override
    253         public void onPhoneStateChanged(int phoneState) {
    254             if (DEBUG) Log.d(TAG, "onPhoneStateChanged(" + phoneState + ")");
    255             if (phoneState == TelephonyManager.CALL_STATE_RINGING) {
    256                 if (mBiometricUnlock != null) {
    257                     mBiometricUnlock.stopAndShowBackup();
    258                 }
    259             }
    260         }
    261 
    262         @Override
    263         public void onUserSwitching(int userId) {
    264             if (DEBUG) Log.d(TAG, "onUserSwitched(" + userId + ")");
    265             if (mBiometricUnlock != null) {
    266                 mBiometricUnlock.stop();
    267             }
    268             // No longer required; static value set by KeyguardViewMediator
    269             // mLockPatternUtils.setCurrentUser(userId);
    270         }
    271 
    272         @Override
    273         public void onUserSwitchComplete(int userId) {
    274             if (DEBUG) Log.d(TAG, "onUserSwitchComplete(" + userId + ")");
    275             if (mBiometricUnlock != null) {
    276                 maybeStartBiometricUnlock();
    277             }
    278         }
    279 
    280         @Override
    281         public void onKeyguardVisibilityChanged(boolean showing) {
    282             if (DEBUG) Log.d(TAG, "onKeyguardVisibilityChanged(" + showing + ")");
    283             boolean wasShowing = false;
    284             synchronized(mIsShowingLock) {
    285                 wasShowing = mIsShowing;
    286                 mIsShowing = showing;
    287             }
    288             PowerManager powerManager = (PowerManager) mContext.getSystemService(
    289                     Context.POWER_SERVICE);
    290             if (mBiometricUnlock != null) {
    291                 if (!showing && wasShowing) {
    292                     mBiometricUnlock.stop();
    293                 } else if (showing && powerManager.isScreenOn() && !wasShowing) {
    294                     maybeStartBiometricUnlock();
    295                 }
    296             }
    297         }
    298 
    299         @Override
    300         public void onEmergencyCallAction() {
    301             if (mBiometricUnlock != null) {
    302                 mBiometricUnlock.stop();
    303             }
    304         }
    305     };
    306 
    307     @Override
    308     public void showUsabilityHint() {
    309     }
    310 
    311     @Override
    312     public void showBouncer(int duration) {
    313         KeyguardSecurityViewHelper.
    314                 showBouncer(mSecurityMessageDisplay, mEcaView, mBouncerFrame, duration);
    315     }
    316 
    317     @Override
    318     public void hideBouncer(int duration) {
    319         KeyguardSecurityViewHelper.
    320                 hideBouncer(mSecurityMessageDisplay, mEcaView, mBouncerFrame, duration);
    321     }
    322 
    323 }
    324