LockPatternKeyguardView.java revision 9eeaaa39c3bad72a369aeff11f95ffea13a5e214
1/*
2 * Copyright (C) 2007 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
17package com.android.internal.policy.impl;
18
19import com.android.internal.R;
20import com.android.internal.policy.impl.LockPatternKeyguardView.UnlockMode;
21import com.android.internal.policy.IFaceLockCallback;
22import com.android.internal.policy.IFaceLockInterface;
23import com.android.internal.telephony.IccCard;
24import com.android.internal.widget.LockPatternUtils;
25import com.android.internal.widget.LockScreenWidgetCallback;
26import com.android.internal.widget.LockScreenWidgetInterface;
27import com.android.internal.widget.TransportControlView;
28
29import android.accounts.Account;
30import android.accounts.AccountManager;
31import android.accounts.AccountManagerCallback;
32import android.accounts.AccountManagerFuture;
33import android.accounts.AuthenticatorException;
34import android.accounts.OperationCanceledException;
35import android.app.AlertDialog;
36import android.app.admin.DevicePolicyManager;
37import android.content.ComponentName;
38import android.content.Context;
39import android.content.Intent;
40import android.content.res.Configuration;
41import android.content.res.Resources;
42import android.content.ServiceConnection;
43import android.graphics.Bitmap;
44import android.graphics.Canvas;
45import android.graphics.ColorFilter;
46import android.graphics.PixelFormat;
47import android.graphics.drawable.Drawable;
48import android.os.Bundle;
49import android.os.Handler;
50import android.os.Message;
51import android.os.IBinder;
52import android.os.RemoteException;
53import android.os.SystemClock;
54import android.os.SystemProperties;
55import android.telephony.TelephonyManager;
56import android.text.TextUtils;
57import android.util.Log;
58import android.util.Slog;
59import android.view.KeyEvent;
60import android.view.MotionEvent;
61import android.view.View;
62import android.view.WindowManager;
63import android.view.accessibility.AccessibilityManager;
64
65import java.io.IOException;
66
67
68/**
69 * The host view for all of the screens of the pattern unlock screen.  There are
70 * two {@link Mode}s of operation, lock and unlock.  This will show the appropriate
71 * screen, and listen for callbacks via
72 * {@link com.android.internal.policy.impl.KeyguardScreenCallback}
73 * from the current screen.
74 *
75 * This view, in turn, communicates back to
76 * {@link com.android.internal.policy.impl.KeyguardViewManager}
77 * via its {@link com.android.internal.policy.impl.KeyguardViewCallback}, as appropriate.
78 */
79public class LockPatternKeyguardView extends KeyguardViewBase implements Handler.Callback,
80        KeyguardUpdateMonitor.InfoCallback {
81
82    private static final int TRANSPORT_USERACTIVITY_TIMEOUT = 10000;
83
84    static final boolean DEBUG_CONFIGURATION = false;
85
86    // time after launching EmergencyDialer before the screen goes blank.
87    private static final int EMERGENCY_CALL_TIMEOUT = 10000;
88
89    // intent action for launching emergency dialer activity.
90    static final String ACTION_EMERGENCY_DIAL = "com.android.phone.EmergencyDialer.DIAL";
91
92    private static final boolean DEBUG = false;
93    private static final String TAG = "LockPatternKeyguardView";
94
95    private final KeyguardUpdateMonitor mUpdateMonitor;
96    private final KeyguardWindowController mWindowController;
97
98    private View mLockScreen;
99    private View mUnlockScreen;
100
101    private volatile boolean mScreenOn = false;
102    private volatile boolean mWindowFocused = false;
103    private boolean mEnableFallback = false; // assume no fallback UI until we know better
104
105    private boolean mShowLockBeforeUnlock = false;
106
107    // The following were added to support FaceLock
108    private IFaceLockInterface mFaceLockService;
109    private boolean mBoundToFaceLockService = false;
110    private View mFaceLockAreaView;
111
112    private boolean mFaceLockServiceRunning = false;
113    private final Object mFaceLockServiceRunningLock = new Object();
114    private final Object mFaceLockStartupLock = new Object();
115
116    private Handler mHandler;
117    private final int MSG_SHOW_FACELOCK_AREA_VIEW = 0;
118    private final int MSG_HIDE_FACELOCK_AREA_VIEW = 1;
119
120    // Long enough to stay visible while dialer comes up
121    // Short enough to not be visible if the user goes back immediately
122    private final int FACELOCK_VIEW_AREA_EMERGENCY_DIALER_TIMEOUT = 1000;
123
124    // Long enough to stay visible while the service starts
125    // Short enough to not have to wait long for backup if service fails to start or crashes
126    // The service can take a couple of seconds to start on the first try after boot
127    private final int FACELOCK_VIEW_AREA_SERVICE_TIMEOUT = 3000;
128
129    // So the user has a consistent amount of time when brought to the backup method from FaceLock
130    private final int BACKUP_LOCK_TIMEOUT = 5000;
131
132    /**
133     * The current {@link KeyguardScreen} will use this to communicate back to us.
134     */
135    KeyguardScreenCallback mKeyguardScreenCallback;
136
137
138    private boolean mRequiresSim;
139    private volatile boolean mEmergencyCall;
140
141
142    /**
143     * Either a lock screen (an informational keyguard screen), or an unlock
144     * screen (a means for unlocking the device) is shown at any given time.
145     */
146    enum Mode {
147        LockScreen,
148        UnlockScreen
149    }
150
151    /**
152     * The different types screens available for {@link Mode#UnlockScreen}.
153     * @see com.android.internal.policy.impl.LockPatternKeyguardView#getUnlockMode()
154     */
155    enum UnlockMode {
156
157        /**
158         * Unlock by drawing a pattern.
159         */
160        Pattern,
161
162        /**
163         * Unlock by entering a sim pin.
164         */
165        SimPin,
166
167        /**
168         * Unlock by entering a sim puk.
169         */
170        SimPuk,
171
172        /**
173         * Unlock by entering an account's login and password.
174         */
175        Account,
176
177        /**
178         * Unlock by entering a password or PIN
179         */
180        Password,
181
182        /**
183         * Unknown (uninitialized) value
184         */
185        Unknown
186    }
187
188    /**
189     * The current mode.
190     */
191    private Mode mMode = Mode.LockScreen;
192
193    /**
194     * Keeps track of what mode the current unlock screen is (cached from most recent computation in
195     * {@link #getUnlockMode}).
196     */
197    private UnlockMode mUnlockScreenMode = UnlockMode.Unknown;
198
199    private boolean mForgotPattern;
200
201    /**
202     * If true, it means we are in the process of verifying that the user
203     * can get past the lock screen per {@link #verifyUnlock()}
204     */
205    private boolean mIsVerifyUnlockOnly = false;
206
207
208    /**
209     * Used to lookup the state of the lock pattern
210     */
211    private final LockPatternUtils mLockPatternUtils;
212
213    /**
214     * The current configuration.
215     */
216    private Configuration mConfiguration;
217
218    private Runnable mRecreateRunnable = new Runnable() {
219        public void run() {
220            updateScreen(mMode, true);
221        }
222    };
223
224    private LockScreenWidgetCallback mWidgetCallback = new LockScreenWidgetCallback() {
225        public void userActivity(View self) {
226            mKeyguardScreenCallback.pokeWakelock(TRANSPORT_USERACTIVITY_TIMEOUT);
227        }
228
229        public void requestShow(View view) {
230            if (DEBUG) Log.v(TAG, "View " + view + " requested show transports");
231            view.setVisibility(View.VISIBLE);
232
233            // TODO: examine all widgets to derive clock status
234            mUpdateMonitor.reportClockVisible(false);
235        }
236
237        public void requestHide(View view) {
238            if (DEBUG) Log.v(TAG, "View " + view + " requested hide transports");
239            view.setVisibility(View.GONE);
240
241            // TODO: examine all widgets to derive clock status
242            mUpdateMonitor.reportClockVisible(true);
243        }
244    };
245
246    private TransportControlView mTransportControlView;
247
248    /**
249     * @return Whether we are stuck on the lock screen because the sim is
250     *   missing.
251     */
252    private boolean stuckOnLockScreenBecauseSimMissing() {
253        return mRequiresSim
254                && (!mUpdateMonitor.isDeviceProvisioned())
255                && (mUpdateMonitor.getSimState() == IccCard.State.ABSENT ||
256                    mUpdateMonitor.getSimState() == IccCard.State.PERM_DISABLED);
257    }
258
259    /**
260     * @param context Used to inflate, and create views.
261     * @param updateMonitor Knows the state of the world, and passed along to each
262     *   screen so they can use the knowledge, and also register for callbacks
263     *   on dynamic information.
264     * @param lockPatternUtils Used to look up state of lock pattern.
265     */
266    public LockPatternKeyguardView(
267            Context context,
268            KeyguardUpdateMonitor updateMonitor,
269            LockPatternUtils lockPatternUtils,
270            KeyguardWindowController controller) {
271        super(context);
272
273        mHandler = new Handler(this);
274        mConfiguration = context.getResources().getConfiguration();
275        mEnableFallback = false;
276        mRequiresSim = TextUtils.isEmpty(SystemProperties.get("keyguard.no_require_sim"));
277        mUpdateMonitor = updateMonitor;
278        mLockPatternUtils = lockPatternUtils;
279        mWindowController = controller;
280        mEmergencyCall = false;
281
282        mUpdateMonitor.registerInfoCallback(this);
283
284        mKeyguardScreenCallback = new KeyguardScreenCallback() {
285
286            public void goToLockScreen() {
287                mForgotPattern = false;
288                if (mIsVerifyUnlockOnly) {
289                    // navigating away from unlock screen during verify mode means
290                    // we are done and the user failed to authenticate.
291                    mIsVerifyUnlockOnly = false;
292                    getCallback().keyguardDone(false);
293                } else {
294                    updateScreen(Mode.LockScreen, false);
295                }
296            }
297
298            public void goToUnlockScreen() {
299                final IccCard.State simState = mUpdateMonitor.getSimState();
300                if (stuckOnLockScreenBecauseSimMissing()
301                         || (simState == IccCard.State.PUK_REQUIRED
302                             && !mLockPatternUtils.isPukUnlockScreenEnable())){
303                    // stuck on lock screen when sim missing or
304                    // puk'd but puk unlock screen is disabled
305                    return;
306                }
307                if (!isSecure()) {
308                    getCallback().keyguardDone(true);
309                } else {
310                    updateScreen(Mode.UnlockScreen, false);
311                }
312            }
313
314            public void forgotPattern(boolean isForgotten) {
315                if (mEnableFallback) {
316                    mForgotPattern = isForgotten;
317                    updateScreen(Mode.UnlockScreen, false);
318                }
319            }
320
321            public boolean isSecure() {
322                return LockPatternKeyguardView.this.isSecure();
323            }
324
325            public boolean isVerifyUnlockOnly() {
326                return mIsVerifyUnlockOnly;
327            }
328
329            public void recreateMe(Configuration config) {
330                removeCallbacks(mRecreateRunnable);
331                post(mRecreateRunnable);
332            }
333
334            public void takeEmergencyCallAction() {
335                mEmergencyCall = true;
336                // FaceLock must be stopped if it is running when emergency call is pressed
337                stopAndUnbindFromFaceLock();
338
339                // Continue showing FaceLock area until dialer comes up
340                showFaceLockAreaWithTimeout(FACELOCK_VIEW_AREA_EMERGENCY_DIALER_TIMEOUT);
341
342                pokeWakelock(EMERGENCY_CALL_TIMEOUT);
343                if (TelephonyManager.getDefault().getCallState()
344                        == TelephonyManager.CALL_STATE_OFFHOOK) {
345                    mLockPatternUtils.resumeCall();
346                } else {
347                    Intent intent = new Intent(ACTION_EMERGENCY_DIAL);
348                    intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
349                            | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
350                    getContext().startActivity(intent);
351                }
352            }
353
354            public void pokeWakelock() {
355                getCallback().pokeWakelock();
356            }
357
358            public void pokeWakelock(int millis) {
359                getCallback().pokeWakelock(millis);
360            }
361
362            public void keyguardDone(boolean authenticated) {
363                getCallback().keyguardDone(authenticated);
364            }
365
366            public void keyguardDoneDrawing() {
367                // irrelevant to keyguard screen, they shouldn't be calling this
368            }
369
370            public void reportFailedUnlockAttempt() {
371                mUpdateMonitor.reportFailedAttempt();
372                final int failedAttempts = mUpdateMonitor.getFailedAttempts();
373                if (DEBUG) Log.d(TAG, "reportFailedPatternAttempt: #" + failedAttempts +
374                    " (enableFallback=" + mEnableFallback + ")");
375
376                final boolean usingPattern = mLockPatternUtils.getKeyguardStoredPasswordQuality()
377                        == DevicePolicyManager.PASSWORD_QUALITY_SOMETHING;
378
379                final int failedAttemptsBeforeWipe = mLockPatternUtils.getDevicePolicyManager()
380                        .getMaximumFailedPasswordsForWipe(null);
381
382                final int failedAttemptWarning = LockPatternUtils.FAILED_ATTEMPTS_BEFORE_RESET
383                        - LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT;
384
385                final int remainingBeforeWipe = failedAttemptsBeforeWipe > 0 ?
386                        (failedAttemptsBeforeWipe - failedAttempts)
387                        : Integer.MAX_VALUE; // because DPM returns 0 if no restriction
388
389                if (remainingBeforeWipe < LockPatternUtils.FAILED_ATTEMPTS_BEFORE_WIPE_GRACE) {
390                    // If we reach this code, it means the user has installed a DevicePolicyManager
391                    // that requests device wipe after N attempts.  Once we get below the grace
392                    // period, we'll post this dialog every time as a clear warning until the
393                    // bombshell hits and the device is wiped.
394                    if (remainingBeforeWipe > 0) {
395                        showAlmostAtWipeDialog(failedAttempts, remainingBeforeWipe);
396                    } else {
397                        // Too many attempts. The device will be wiped shortly.
398                        Slog.i(TAG, "Too many unlock attempts; device will be wiped!");
399                        showWipeDialog(failedAttempts);
400                    }
401                } else if (usingPattern && mEnableFallback) {
402                    if (failedAttempts == failedAttemptWarning) {
403                        showAlmostAtAccountLoginDialog();
404                    } else if (failedAttempts >= LockPatternUtils.FAILED_ATTEMPTS_BEFORE_RESET) {
405                        mLockPatternUtils.setPermanentlyLocked(true);
406                        updateScreen(mMode, false);
407                    }
408                } else {
409                    final boolean showTimeout =
410                        (failedAttempts % LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT) == 0;
411                    if (showTimeout) {
412                        showTimeoutDialog();
413                    }
414                }
415                mLockPatternUtils.reportFailedPasswordAttempt();
416            }
417
418            public boolean doesFallbackUnlockScreenExist() {
419                return mEnableFallback;
420            }
421
422            public void reportSuccessfulUnlockAttempt() {
423                mLockPatternUtils.reportSuccessfulPasswordAttempt();
424            }
425        };
426
427        /**
428         * We'll get key events the current screen doesn't use. see
429         * {@link KeyguardViewBase#onKeyDown(int, android.view.KeyEvent)}
430         */
431        setFocusableInTouchMode(true);
432        setDescendantFocusability(FOCUS_AFTER_DESCENDANTS);
433
434        updateScreen(getInitialMode(), false);
435        maybeEnableFallback(context);
436    }
437
438    private class AccountAnalyzer implements AccountManagerCallback<Bundle> {
439        private final AccountManager mAccountManager;
440        private final Account[] mAccounts;
441        private int mAccountIndex;
442
443        private AccountAnalyzer(AccountManager accountManager) {
444            mAccountManager = accountManager;
445            mAccounts = accountManager.getAccountsByType("com.google");
446        }
447
448        private void next() {
449            // if we are ready to enable the fallback or if we depleted the list of accounts
450            // then finish and get out
451            if (mEnableFallback || mAccountIndex >= mAccounts.length) {
452                if (mUnlockScreen == null) {
453                    if (DEBUG) Log.w(TAG, "no unlock screen when trying to enable fallback");
454                } else if (mUnlockScreen instanceof PatternUnlockScreen) {
455                    ((PatternUnlockScreen)mUnlockScreen).setEnableFallback(mEnableFallback);
456                }
457                return;
458            }
459
460            // lookup the confirmCredentials intent for the current account
461            mAccountManager.confirmCredentials(mAccounts[mAccountIndex], null, null, this, null);
462        }
463
464        public void start() {
465            mEnableFallback = false;
466            mAccountIndex = 0;
467            next();
468        }
469
470        public void run(AccountManagerFuture<Bundle> future) {
471            try {
472                Bundle result = future.getResult();
473                if (result.getParcelable(AccountManager.KEY_INTENT) != null) {
474                    mEnableFallback = true;
475                }
476            } catch (OperationCanceledException e) {
477                // just skip the account if we are unable to query it
478            } catch (IOException e) {
479                // just skip the account if we are unable to query it
480            } catch (AuthenticatorException e) {
481                // just skip the account if we are unable to query it
482            } finally {
483                mAccountIndex++;
484                next();
485            }
486        }
487    }
488
489    private void maybeEnableFallback(Context context) {
490        // Ask the account manager if we have an account that can be used as a
491        // fallback in case the user forgets his pattern.
492        AccountAnalyzer accountAnalyzer = new AccountAnalyzer(AccountManager.get(context));
493        accountAnalyzer.start();
494    }
495
496
497    // TODO:
498    // This overloaded method was added to workaround a race condition in the framework between
499    // notification for orientation changed, layout() and switching resources.  This code attempts
500    // to avoid drawing the incorrect layout while things are in transition.  The method can just
501    // be removed once the race condition is fixed. See bugs 2262578 and 2292713.
502    @Override
503    protected void dispatchDraw(Canvas canvas) {
504        if (DEBUG) Log.v(TAG, "*** dispatchDraw() time: " + SystemClock.elapsedRealtime());
505        super.dispatchDraw(canvas);
506    }
507
508    @Override
509    public void reset() {
510        mIsVerifyUnlockOnly = false;
511        mForgotPattern = false;
512        post(mRecreateRunnable);
513    }
514
515    @Override
516    public void onScreenTurnedOff() {
517        mScreenOn = false;
518        mForgotPattern = false;
519        mEmergencyCall = false;
520        if (mMode == Mode.LockScreen) {
521            ((KeyguardScreen) mLockScreen).onPause();
522        } else {
523            ((KeyguardScreen) mUnlockScreen).onPause();
524        }
525
526        // When screen is turned off, need to unbind from FaceLock service if using FaceLock
527        stopAndUnbindFromFaceLock();
528    }
529
530    /** When screen is turned on and focused, need to bind to FaceLock service if we are using
531     *  FaceLock, but only if we're not dealing with a call
532    */
533    private void activateFaceLockIfAble() {
534        final boolean transportInvisible = mTransportControlView == null ? true :
535                mTransportControlView.getVisibility() != View.VISIBLE;
536        if (mUpdateMonitor.getPhoneState() == TelephonyManager.CALL_STATE_IDLE
537                && transportInvisible) {
538            bindToFaceLock();
539            // Show FaceLock area, but only for a little bit so lockpattern will become visible if
540            // FaceLock fails to start or crashes
541            showFaceLockAreaWithTimeout(FACELOCK_VIEW_AREA_SERVICE_TIMEOUT);
542        } else {
543            hideFaceLockArea();
544        }
545    }
546
547    @Override
548    public void onScreenTurnedOn() {
549        boolean runFaceLock = false;
550        //Make sure to start facelock iff the screen is both on and focused
551        synchronized(mFaceLockStartupLock) {
552            mScreenOn = true;
553            runFaceLock = mWindowFocused;
554        }
555        show();
556        if(runFaceLock) activateFaceLockIfAble();
557    }
558
559    /** Unbind from facelock if something covers this window (such as an alarm)
560     * bind to facelock if the lockscreen window just came into focus, and the screen is on
561     */
562    @Override
563    public void onWindowFocusChanged (boolean hasWindowFocus) {
564        if(DEBUG) Log.d(TAG, hasWindowFocus ? "focused" : "unfocused");
565        boolean runFaceLock = false;
566        //Make sure to start facelock iff the screen is both on and focused
567        synchronized(mFaceLockStartupLock) {
568            if(mScreenOn && !mWindowFocused) runFaceLock = hasWindowFocus;
569            mWindowFocused = hasWindowFocus;
570        }
571        if(!hasWindowFocus) {
572            stopAndUnbindFromFaceLock();
573            hideFaceLockArea();
574        } else if (runFaceLock) {
575            //Don't activate facelock while the user is calling 911!
576            if(mEmergencyCall) mEmergencyCall = false;
577            else {
578                activateFaceLockIfAble();
579            }
580        }
581    }
582
583    @Override
584    public void show() {
585        if (mMode == Mode.LockScreen) {
586            ((KeyguardScreen) mLockScreen).onResume();
587        } else {
588            ((KeyguardScreen) mUnlockScreen).onResume();
589        }
590
591        if (mLockPatternUtils.usingBiometricWeak() &&
592                mLockPatternUtils.isBiometricWeakInstalled()) {
593            // Note that show() gets called before the screen turns off to set it up for next time
594            // it is turned on.  We don't want to set a timeout on the FaceLock area here because it
595            // may be gone by the time the screen is turned on again.  We set the timout when the
596            // screen turns on instead.
597            showFaceLockArea();
598        } else {
599            hideFaceLockArea();
600        }
601    }
602
603    private void recreateLockScreen() {
604        if (mLockScreen != null) {
605            ((KeyguardScreen) mLockScreen).onPause();
606            ((KeyguardScreen) mLockScreen).cleanUp();
607            removeView(mLockScreen);
608        }
609
610        mLockScreen = createLockScreen();
611        mLockScreen.setVisibility(View.INVISIBLE);
612        addView(mLockScreen);
613    }
614
615    private void recreateUnlockScreen(UnlockMode unlockMode) {
616        if (mUnlockScreen != null) {
617            ((KeyguardScreen) mUnlockScreen).onPause();
618            ((KeyguardScreen) mUnlockScreen).cleanUp();
619            removeView(mUnlockScreen);
620        }
621
622        mUnlockScreen = createUnlockScreenFor(unlockMode);
623        mUnlockScreen.setVisibility(View.INVISIBLE);
624        addView(mUnlockScreen);
625    }
626
627    @Override
628    protected void onDetachedFromWindow() {
629        removeCallbacks(mRecreateRunnable);
630
631        // When view is hidden, need to unbind from FaceLock service if we are using FaceLock
632        // e.g., when device becomes unlocked
633        stopAndUnbindFromFaceLock();
634
635        super.onDetachedFromWindow();
636    }
637
638    protected void onConfigurationChanged(Configuration newConfig) {
639        Resources resources = getResources();
640        mShowLockBeforeUnlock = resources.getBoolean(R.bool.config_enableLockBeforeUnlockScreen);
641        mConfiguration = newConfig;
642        if (DEBUG_CONFIGURATION) Log.v(TAG, "**** re-creating lock screen since config changed");
643        removeCallbacks(mRecreateRunnable);
644        post(mRecreateRunnable);
645    }
646
647    //Ignore these events; they are implemented only because they come from the same interface
648    @Override
649    public void onRefreshBatteryInfo(boolean showBatteryInfo, boolean pluggedIn, int batteryLevel)
650    {}
651    @Override
652    public void onTimeChanged() {}
653    @Override
654    public void onRefreshCarrierInfo(CharSequence plmn, CharSequence spn) {}
655    @Override
656    public void onRingerModeChanged(int state) {}
657    @Override
658    public void onClockVisibilityChanged() {}
659
660    //We need to stop faceunlock when a phonecall comes in
661    @Override
662    public void onPhoneStateChanged(int phoneState) {
663        if (DEBUG) Log.d(TAG, "phone state: " + phoneState);
664        if(phoneState == TelephonyManager.CALL_STATE_RINGING) {
665            stopAndUnbindFromFaceLock();
666            hideFaceLockArea();
667        }
668    }
669
670    @Override
671    protected boolean dispatchHoverEvent(MotionEvent event) {
672        // Do not let the screen to get locked while the user is disabled and touch
673        // exploring. A blind user will need significantly more time to find and
674        // interact with the lock screen views.
675        AccessibilityManager accessibilityManager = AccessibilityManager.getInstance(mContext);
676        if (accessibilityManager.isEnabled() && accessibilityManager.isTouchExplorationEnabled()) {
677            getCallback().pokeWakelock();
678        }
679        return super.dispatchHoverEvent(event);
680    }
681
682    @Override
683    public void wakeWhenReadyTq(int keyCode) {
684        if (DEBUG) Log.d(TAG, "onWakeKey");
685        if (keyCode == KeyEvent.KEYCODE_MENU && isSecure() && (mMode == Mode.LockScreen)
686                && (mUpdateMonitor.getSimState() != IccCard.State.PUK_REQUIRED)) {
687            if (DEBUG) Log.d(TAG, "switching screens to unlock screen because wake key was MENU");
688            updateScreen(Mode.UnlockScreen, false);
689            getCallback().pokeWakelock();
690        } else {
691            if (DEBUG) Log.d(TAG, "poking wake lock immediately");
692            getCallback().pokeWakelock();
693        }
694    }
695
696    @Override
697    public void verifyUnlock() {
698        if (!isSecure()) {
699            // non-secure keyguard screens are successfull by default
700            getCallback().keyguardDone(true);
701        } else if (mUnlockScreenMode != UnlockMode.Pattern
702                && mUnlockScreenMode != UnlockMode.Password) {
703            // can only verify unlock when in pattern/password mode
704            getCallback().keyguardDone(false);
705        } else {
706            // otherwise, go to the unlock screen, see if they can verify it
707            mIsVerifyUnlockOnly = true;
708            updateScreen(Mode.UnlockScreen, false);
709        }
710    }
711
712    @Override
713    public void cleanUp() {
714        if (mLockScreen != null) {
715            ((KeyguardScreen) mLockScreen).onPause();
716            ((KeyguardScreen) mLockScreen).cleanUp();
717            this.removeView(mLockScreen);
718            mLockScreen = null;
719        }
720        if (mUnlockScreen != null) {
721            ((KeyguardScreen) mUnlockScreen).onPause();
722            ((KeyguardScreen) mUnlockScreen).cleanUp();
723            this.removeView(mUnlockScreen);
724            mUnlockScreen = null;
725        }
726    }
727
728    private boolean isSecure() {
729        UnlockMode unlockMode = getUnlockMode();
730        boolean secure = false;
731        switch (unlockMode) {
732            case Pattern:
733                secure = mLockPatternUtils.isLockPatternEnabled();
734                break;
735            case SimPin:
736                secure = mUpdateMonitor.getSimState() == IccCard.State.PIN_REQUIRED;
737                break;
738            case SimPuk:
739                secure = mUpdateMonitor.getSimState() == IccCard.State.PUK_REQUIRED;
740                break;
741            case Account:
742                secure = true;
743                break;
744            case Password:
745                secure = mLockPatternUtils.isLockPasswordEnabled();
746                break;
747            default:
748                throw new IllegalStateException("unknown unlock mode " + unlockMode);
749        }
750        return secure;
751    }
752
753    private void updateScreen(Mode mode, boolean force) {
754
755        if (DEBUG_CONFIGURATION) Log.v(TAG, "**** UPDATE SCREEN: mode=" + mode
756                + " last mode=" + mMode + ", force = " + force, new RuntimeException());
757
758        mMode = mode;
759
760        // Re-create the lock screen if necessary
761        if (mode == Mode.LockScreen || mShowLockBeforeUnlock) {
762            if (force || mLockScreen == null) {
763                recreateLockScreen();
764            }
765        }
766
767        // Re-create the unlock screen if necessary. This is primarily required to properly handle
768        // SIM state changes. This typically happens when this method is called by reset()
769        if (mode == Mode.UnlockScreen) {
770            final UnlockMode unlockMode = getUnlockMode();
771            if (force || mUnlockScreen == null || unlockMode != mUnlockScreenMode) {
772                recreateUnlockScreen(unlockMode);
773            }
774        }
775
776        // visibleScreen should never be null
777        final View goneScreen = (mode == Mode.LockScreen) ? mUnlockScreen : mLockScreen;
778        final View visibleScreen = (mode == Mode.LockScreen) ? mLockScreen : mUnlockScreen;
779
780        // do this before changing visibility so focus isn't requested before the input
781        // flag is set
782        mWindowController.setNeedsInput(((KeyguardScreen)visibleScreen).needsInput());
783
784        if (DEBUG_CONFIGURATION) {
785            Log.v(TAG, "Gone=" + goneScreen);
786            Log.v(TAG, "Visible=" + visibleScreen);
787        }
788
789        if (mScreenOn) {
790            if (goneScreen != null && goneScreen.getVisibility() == View.VISIBLE) {
791                ((KeyguardScreen) goneScreen).onPause();
792            }
793            if (visibleScreen.getVisibility() != View.VISIBLE) {
794                ((KeyguardScreen) visibleScreen).onResume();
795            }
796        }
797
798        if (goneScreen != null) {
799            goneScreen.setVisibility(View.GONE);
800        }
801        visibleScreen.setVisibility(View.VISIBLE);
802        requestLayout();
803
804        if (!visibleScreen.requestFocus()) {
805            throw new IllegalStateException("keyguard screen must be able to take "
806                    + "focus when shown " + visibleScreen.getClass().getCanonicalName());
807        }
808    }
809
810    View createLockScreen() {
811        View lockView = new LockScreen(
812                mContext,
813                mConfiguration,
814                mLockPatternUtils,
815                mUpdateMonitor,
816                mKeyguardScreenCallback);
817        initializeTransportControlView(lockView);
818        return lockView;
819    }
820
821    View createUnlockScreenFor(UnlockMode unlockMode) {
822        View unlockView = null;
823
824        if (DEBUG) Log.d(TAG,
825                "createUnlockScreenFor(" + unlockMode + "): mEnableFallback=" + mEnableFallback);
826
827        if (unlockMode == UnlockMode.Pattern) {
828            PatternUnlockScreen view = new PatternUnlockScreen(
829                    mContext,
830                    mConfiguration,
831                    mLockPatternUtils,
832                    mUpdateMonitor,
833                    mKeyguardScreenCallback,
834                    mUpdateMonitor.getFailedAttempts());
835            view.setEnableFallback(mEnableFallback);
836            unlockView = view;
837        } else if (unlockMode == UnlockMode.SimPuk) {
838            unlockView = new SimPukUnlockScreen(
839                    mContext,
840                    mConfiguration,
841                    mUpdateMonitor,
842                    mKeyguardScreenCallback,
843                    mLockPatternUtils);
844        } else if (unlockMode == UnlockMode.SimPin) {
845            unlockView = new SimUnlockScreen(
846                    mContext,
847                    mConfiguration,
848                    mUpdateMonitor,
849                    mKeyguardScreenCallback,
850                    mLockPatternUtils);
851        } else if (unlockMode == UnlockMode.Account) {
852            try {
853                unlockView = new AccountUnlockScreen(
854                        mContext,
855                        mConfiguration,
856                        mUpdateMonitor,
857                        mKeyguardScreenCallback,
858                        mLockPatternUtils);
859            } catch (IllegalStateException e) {
860                Log.i(TAG, "Couldn't instantiate AccountUnlockScreen"
861                      + " (IAccountsService isn't available)");
862                // TODO: Need a more general way to provide a
863                // platform-specific fallback UI here.
864                // For now, if we can't display the account login
865                // unlock UI, just bring back the regular "Pattern" unlock mode.
866
867                // (We do this by simply returning a regular UnlockScreen
868                // here.  This means that the user will still see the
869                // regular pattern unlock UI, regardless of the value of
870                // mUnlockScreenMode or whether or not we're in the
871                // "permanently locked" state.)
872                return createUnlockScreenFor(UnlockMode.Pattern);
873            }
874        } else if (unlockMode == UnlockMode.Password) {
875            unlockView = new PasswordUnlockScreen(
876                    mContext,
877                    mConfiguration,
878                    mLockPatternUtils,
879                    mUpdateMonitor,
880                    mKeyguardScreenCallback);
881        } else {
882            throw new IllegalArgumentException("unknown unlock mode " + unlockMode);
883        }
884        initializeTransportControlView(unlockView);
885        initializeFaceLockAreaView(unlockView); // Only shows view if FaceLock is enabled
886
887        mUnlockScreenMode = unlockMode;
888        return unlockView;
889    }
890
891    private void initializeTransportControlView(View view) {
892        mTransportControlView = (TransportControlView) view.findViewById(R.id.transport);
893        if (mTransportControlView == null) {
894            if (DEBUG) Log.w(TAG, "Couldn't find transport control widget");
895        } else {
896            mUpdateMonitor.reportClockVisible(true);
897            mTransportControlView.setVisibility(View.GONE); // hide until it requests being shown.
898            mTransportControlView.setCallback(mWidgetCallback);
899        }
900    }
901
902    /**
903     * Given the current state of things, what should be the initial mode of
904     * the lock screen (lock or unlock).
905     */
906    private Mode getInitialMode() {
907        final IccCard.State simState = mUpdateMonitor.getSimState();
908        if (stuckOnLockScreenBecauseSimMissing() ||
909                (simState == IccCard.State.PUK_REQUIRED &&
910                        !mLockPatternUtils.isPukUnlockScreenEnable())) {
911            return Mode.LockScreen;
912        } else {
913            if (!isSecure() || mShowLockBeforeUnlock) {
914                return Mode.LockScreen;
915            } else {
916                return Mode.UnlockScreen;
917            }
918        }
919    }
920
921    /**
922     * Given the current state of things, what should the unlock screen be?
923     */
924    private UnlockMode getUnlockMode() {
925        final IccCard.State simState = mUpdateMonitor.getSimState();
926        UnlockMode currentMode;
927        if (simState == IccCard.State.PIN_REQUIRED) {
928            currentMode = UnlockMode.SimPin;
929        } else if (simState == IccCard.State.PUK_REQUIRED) {
930            currentMode = UnlockMode.SimPuk;
931        } else {
932            final int mode = mLockPatternUtils.getKeyguardStoredPasswordQuality();
933            switch (mode) {
934                case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC:
935                case DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC:
936                case DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC:
937                case DevicePolicyManager.PASSWORD_QUALITY_COMPLEX:
938                    currentMode = UnlockMode.Password;
939                    break;
940                case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING:
941                case DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED:
942                    // "forgot pattern" button is only available in the pattern mode...
943                    if (mForgotPattern || mLockPatternUtils.isPermanentlyLocked()) {
944                        currentMode = UnlockMode.Account;
945                    } else {
946                        currentMode = UnlockMode.Pattern;
947                    }
948                    break;
949                default:
950                   throw new IllegalStateException("Unknown unlock mode:" + mode);
951            }
952        }
953        return currentMode;
954    }
955
956    private void showDialog(String title, String message) {
957        final AlertDialog dialog = new AlertDialog.Builder(mContext)
958            .setTitle(title)
959            .setMessage(message)
960            .setNeutralButton(R.string.ok, null)
961            .create();
962        dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
963        dialog.show();
964    }
965
966    private void showTimeoutDialog() {
967        int timeoutInSeconds = (int) LockPatternUtils.FAILED_ATTEMPT_TIMEOUT_MS / 1000;
968        int messageId = R.string.lockscreen_too_many_failed_attempts_dialog_message;
969        if (getUnlockMode() == UnlockMode.Password) {
970            if(mLockPatternUtils.getKeyguardStoredPasswordQuality() ==
971                DevicePolicyManager.PASSWORD_QUALITY_NUMERIC) {
972                messageId = R.string.lockscreen_too_many_failed_pin_attempts_dialog_message;
973            } else {
974                messageId = R.string.lockscreen_too_many_failed_password_attempts_dialog_message;
975            }
976        }
977        String message = mContext.getString(messageId, mUpdateMonitor.getFailedAttempts(),
978                timeoutInSeconds);
979
980        showDialog(null, message);
981    }
982
983    private void showAlmostAtAccountLoginDialog() {
984        final int timeoutInSeconds = (int) LockPatternUtils.FAILED_ATTEMPT_TIMEOUT_MS / 1000;
985        final int count = LockPatternUtils.FAILED_ATTEMPTS_BEFORE_RESET
986                - LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT;
987        String message = mContext.getString(R.string.lockscreen_failed_attempts_almost_glogin,
988                count, LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT, timeoutInSeconds);
989        showDialog(null, message);
990    }
991
992    private void showAlmostAtWipeDialog(int attempts, int remaining) {
993        int timeoutInSeconds = (int) LockPatternUtils.FAILED_ATTEMPT_TIMEOUT_MS / 1000;
994        String message = mContext.getString(
995                R.string.lockscreen_failed_attempts_almost_at_wipe, attempts, remaining);
996        showDialog(null, message);
997    }
998
999    private void showWipeDialog(int attempts) {
1000        String message = mContext.getString(
1001                R.string.lockscreen_failed_attempts_now_wiping, attempts);
1002        showDialog(null, message);
1003    }
1004
1005    /**
1006     * Used to put wallpaper on the background of the lock screen.  Centers it
1007     * Horizontally and pins the bottom (assuming that the lock screen is aligned
1008     * with the bottom, so the wallpaper should extend above the top into the
1009     * status bar).
1010     */
1011    static private class FastBitmapDrawable extends Drawable {
1012        private Bitmap mBitmap;
1013        private int mOpacity;
1014
1015        private FastBitmapDrawable(Bitmap bitmap) {
1016            mBitmap = bitmap;
1017            mOpacity = mBitmap.hasAlpha() ? PixelFormat.TRANSLUCENT : PixelFormat.OPAQUE;
1018        }
1019
1020        @Override
1021        public void draw(Canvas canvas) {
1022            canvas.drawBitmap(
1023                    mBitmap,
1024                    (getBounds().width() - mBitmap.getWidth()) / 2,
1025                    (getBounds().height() - mBitmap.getHeight()),
1026                    null);
1027        }
1028
1029        @Override
1030        public int getOpacity() {
1031            return mOpacity;
1032        }
1033
1034        @Override
1035        public void setAlpha(int alpha) {
1036        }
1037
1038        @Override
1039        public void setColorFilter(ColorFilter cf) {
1040        }
1041
1042        @Override
1043        public int getIntrinsicWidth() {
1044            return mBitmap.getWidth();
1045        }
1046
1047        @Override
1048        public int getIntrinsicHeight() {
1049            return mBitmap.getHeight();
1050        }
1051
1052        @Override
1053        public int getMinimumWidth() {
1054            return mBitmap.getWidth();
1055        }
1056
1057        @Override
1058        public int getMinimumHeight() {
1059            return mBitmap.getHeight();
1060        }
1061    }
1062
1063    // Everything below pertains to FaceLock - might want to separate this out
1064
1065    // Only pattern and pin unlock screens actually have a view for the FaceLock area, so it's not
1066    // uncommon for it to not exist.  But if it does exist, we need to make sure it's shown (hiding
1067    // the fallback) if FaceLock is enabled, and make sure it's hidden (showing the unlock) if
1068    // FaceLock is disabled
1069    private void initializeFaceLockAreaView(View view) {
1070        mFaceLockAreaView = view.findViewById(R.id.faceLockAreaView);
1071        if (mFaceLockAreaView == null) {
1072            if (DEBUG) Log.d(TAG, "Layout does not have faceLockAreaView");
1073        }
1074    }
1075
1076    // Handles covering or exposing FaceLock area on the client side when FaceLock starts or stops
1077    // This needs to be done in a handler because the call could be coming from a callback from the
1078    // FaceLock service that is in a thread that can't modify the UI
1079    @Override
1080    public boolean handleMessage(Message msg) {
1081        switch (msg.what) {
1082        case MSG_SHOW_FACELOCK_AREA_VIEW:
1083            if (mFaceLockAreaView != null) {
1084                mFaceLockAreaView.setVisibility(View.VISIBLE);
1085            }
1086            break;
1087        case MSG_HIDE_FACELOCK_AREA_VIEW:
1088            if (mFaceLockAreaView != null) {
1089                mFaceLockAreaView.setVisibility(View.GONE);
1090            }
1091            break;
1092        default:
1093            Log.w(TAG, "Unhandled message");
1094            return false;
1095        }
1096        return true;
1097    }
1098
1099    // Removes show and hide messages from the message queue
1100    private void removeFaceLockAreaDisplayMessages() {
1101        mHandler.removeMessages(MSG_SHOW_FACELOCK_AREA_VIEW);
1102        mHandler.removeMessages(MSG_HIDE_FACELOCK_AREA_VIEW);
1103    }
1104
1105    // Shows the FaceLock area immediately
1106    private void showFaceLockArea() {
1107        // Remove messages to prevent a delayed hide message from undo-ing the show
1108        removeFaceLockAreaDisplayMessages();
1109        mHandler.sendEmptyMessage(MSG_SHOW_FACELOCK_AREA_VIEW);
1110    }
1111
1112    // Hides the FaceLock area immediately
1113    private void hideFaceLockArea() {
1114        // Remove messages to prevent a delayed show message from undo-ing the hide
1115        removeFaceLockAreaDisplayMessages();
1116        mHandler.sendEmptyMessage(MSG_HIDE_FACELOCK_AREA_VIEW);
1117    }
1118
1119    // Shows the FaceLock area for a period of time
1120    private void showFaceLockAreaWithTimeout(long timeoutMillis) {
1121        showFaceLockArea();
1122        mHandler.sendEmptyMessageDelayed(MSG_HIDE_FACELOCK_AREA_VIEW, timeoutMillis);
1123    }
1124
1125    // Binds to FaceLock service, but does not tell it to start
1126    public void bindToFaceLock() {
1127        if (mLockPatternUtils.usingBiometricWeak() &&
1128                mLockPatternUtils.isBiometricWeakInstalled()) {
1129            if (!mBoundToFaceLockService) {
1130                if (DEBUG) Log.d(TAG, "before bind to FaceLock service");
1131                mContext.bindService(new Intent(IFaceLockInterface.class.getName()),
1132                        mFaceLockConnection,
1133                        Context.BIND_AUTO_CREATE);
1134                if (DEBUG) Log.d(TAG, "after bind to FaceLock service");
1135                mBoundToFaceLockService = true;
1136            } else {
1137                Log.w(TAG, "Attempt to bind to FaceLock when already bound");
1138            }
1139        }
1140    }
1141
1142    // Tells FaceLock to stop and then unbinds from the FaceLock service
1143    public void stopAndUnbindFromFaceLock() {
1144        if (mLockPatternUtils.usingBiometricWeak() &&
1145                mLockPatternUtils.isBiometricWeakInstalled()) {
1146            stopFaceLock();
1147
1148            if (mBoundToFaceLockService) {
1149                if (DEBUG) Log.d(TAG, "before unbind from FaceLock service");
1150                mContext.unbindService(mFaceLockConnection);
1151                if (DEBUG) Log.d(TAG, "after unbind from FaceLock service");
1152                mBoundToFaceLockService = false;
1153            } else {
1154                // This could probably happen after the session when someone activates FaceLock
1155                // because it wasn't active when the phone was turned on
1156                Log.w(TAG, "Attempt to unbind from FaceLock when not bound");
1157            }
1158        }
1159    }
1160
1161    private ServiceConnection mFaceLockConnection = new ServiceConnection() {
1162        // Completes connection, registers callback and starts FaceLock when service is bound
1163        @Override
1164        public void onServiceConnected(ComponentName className, IBinder iservice) {
1165            mFaceLockService = IFaceLockInterface.Stub.asInterface(iservice);
1166            if (DEBUG) Log.d(TAG, "Connected to FaceLock service");
1167            try {
1168                mFaceLockService.registerCallback(mFaceLockCallback);
1169            } catch (RemoteException e) {
1170                Log.e(TAG, "Caught exception connecting to FaceLock: " + e.toString());
1171                mFaceLockService = null;
1172                mBoundToFaceLockService = false;
1173                return;
1174            }
1175
1176            if (mFaceLockAreaView != null) {
1177                startFaceLock(mFaceLockAreaView.getWindowToken(),
1178                        mFaceLockAreaView.getLeft(), mFaceLockAreaView.getTop(),
1179                        mFaceLockAreaView.getWidth(), mFaceLockAreaView.getHeight());
1180            }
1181        }
1182
1183        // Cleans up if FaceLock service unexpectedly disconnects
1184        @Override
1185        public void onServiceDisconnected(ComponentName className) {
1186            synchronized(mFaceLockServiceRunningLock) {
1187                mFaceLockService = null;
1188                mFaceLockServiceRunning = false;
1189            }
1190            mBoundToFaceLockService = false;
1191            Log.w(TAG, "Unexpected disconnect from FaceLock service");
1192        }
1193    };
1194
1195    // Tells the FaceLock service to start displaying its UI and perform recognition
1196    public void startFaceLock(IBinder windowToken, int x, int y, int h, int w)
1197    {
1198        if (mLockPatternUtils.usingBiometricWeak() &&
1199                mLockPatternUtils.isBiometricWeakInstalled()) {
1200            synchronized (mFaceLockServiceRunningLock) {
1201                if (!mFaceLockServiceRunning) {
1202                    if (DEBUG) Log.d(TAG, "Starting FaceLock");
1203                    try {
1204                        mFaceLockService.startUi(windowToken, x, y, h, w);
1205                    } catch (RemoteException e) {
1206                        Log.e(TAG, "Caught exception starting FaceLock: " + e.toString());
1207                        return;
1208                    }
1209                    mFaceLockServiceRunning = true;
1210                } else {
1211                    if (DEBUG) Log.w(TAG, "startFaceLock() attempted while running");
1212                }
1213            }
1214        }
1215    }
1216
1217    // Tells the FaceLock service to stop displaying its UI and stop recognition
1218    public void stopFaceLock()
1219    {
1220        if (mLockPatternUtils.usingBiometricWeak() &&
1221                mLockPatternUtils.isBiometricWeakInstalled()) {
1222            // Note that attempting to stop FaceLock when it's not running is not an issue.
1223            // FaceLock can return, which stops it and then we try to stop it when the
1224            // screen is turned off.  That's why we check.
1225            synchronized (mFaceLockServiceRunningLock) {
1226                if (mFaceLockServiceRunning) {
1227                    try {
1228                        if (DEBUG) Log.d(TAG, "Stopping FaceLock");
1229                        mFaceLockService.stopUi();
1230                    } catch (RemoteException e) {
1231                        Log.e(TAG, "Caught exception stopping FaceLock: " + e.toString());
1232                    }
1233                    mFaceLockServiceRunning = false;
1234                }
1235            }
1236        }
1237    }
1238
1239    // Implements the FaceLock service callback interface defined in AIDL
1240    private final IFaceLockCallback mFaceLockCallback = new IFaceLockCallback.Stub() {
1241
1242        // Stops the FaceLock UI and indicates that the phone should be unlocked
1243        @Override
1244        public void unlock() {
1245            if (DEBUG) Log.d(TAG, "FaceLock unlock()");
1246            showFaceLockArea(); // Keep fallback covered
1247            stopFaceLock();
1248
1249            mKeyguardScreenCallback.keyguardDone(true);
1250            mKeyguardScreenCallback.reportSuccessfulUnlockAttempt();
1251        }
1252
1253        // Stops the FaceLock UI and exposes the backup method without unlocking
1254        // This means either the user has cancelled out or FaceLock failed to recognize them
1255        @Override
1256        public void cancel() {
1257            if (DEBUG) Log.d(TAG, "FaceLock cancel()");
1258            hideFaceLockArea(); // Expose fallback
1259            stopFaceLock();
1260            mKeyguardScreenCallback.pokeWakelock(BACKUP_LOCK_TIMEOUT);
1261        }
1262
1263        // Allows the Face Unlock service to poke the wake lock to keep the lockscreen alive
1264        @Override
1265        public void pokeWakelock() {
1266            if (DEBUG) Log.d(TAG, "FaceLock pokeWakelock()");
1267            mKeyguardScreenCallback.pokeWakelock();
1268        }
1269    };
1270}
1271