• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
17 package com.android.internal.policy.impl;
18 
19 import com.android.internal.R;
20 import com.android.internal.telephony.IccCard;
21 import com.android.internal.widget.LockPatternUtils;
22 
23 import android.accounts.Account;
24 import android.accounts.AccountManager;
25 import android.accounts.AccountManagerCallback;
26 import android.accounts.AccountManagerFuture;
27 import android.accounts.AuthenticatorException;
28 import android.accounts.OperationCanceledException;
29 import android.app.AlertDialog;
30 import android.app.admin.DevicePolicyManager;
31 import android.content.Context;
32 import android.content.Intent;
33 import android.content.res.Configuration;
34 import android.graphics.Bitmap;
35 import android.graphics.Canvas;
36 import android.graphics.ColorFilter;
37 import android.graphics.PixelFormat;
38 import android.graphics.drawable.Drawable;
39 import android.os.Bundle;
40 import android.os.SystemClock;
41 import android.os.SystemProperties;
42 import android.telephony.TelephonyManager;
43 import android.text.TextUtils;
44 import android.util.Log;
45 import android.view.KeyEvent;
46 import android.view.View;
47 import android.view.WindowManager;
48 
49 import java.io.IOException;
50 
51 /**
52  * The host view for all of the screens of the pattern unlock screen.  There are
53  * two {@link Mode}s of operation, lock and unlock.  This will show the appropriate
54  * screen, and listen for callbacks via
55  * {@link com.android.internal.policy.impl.KeyguardScreenCallback}
56  * from the current screen.
57  *
58  * This view, in turn, communicates back to
59  * {@link com.android.internal.policy.impl.KeyguardViewManager}
60  * via its {@link com.android.internal.policy.impl.KeyguardViewCallback}, as appropriate.
61  */
62 public class LockPatternKeyguardView extends KeyguardViewBase {
63 
64     static final boolean DEBUG_CONFIGURATION = false;
65 
66     // time after launching EmergencyDialer before the screen goes blank.
67     private static final int EMERGENCY_CALL_TIMEOUT = 10000;
68 
69     // intent action for launching emergency dialer activity.
70     static final String ACTION_EMERGENCY_DIAL = "com.android.phone.EmergencyDialer.DIAL";
71 
72     private static final boolean DEBUG = false;
73     private static final String TAG = "LockPatternKeyguardView";
74 
75     private final KeyguardUpdateMonitor mUpdateMonitor;
76     private final KeyguardWindowController mWindowController;
77 
78     private View mLockScreen;
79     private View mUnlockScreen;
80 
81     private boolean mScreenOn = false;
82     private boolean mEnableFallback = false; // assume no fallback UI until we know better
83 
84     /**
85      * The current {@link KeyguardScreen} will use this to communicate back to us.
86      */
87     KeyguardScreenCallback mKeyguardScreenCallback;
88 
89 
90     private boolean mRequiresSim;
91 
92 
93     /**
94      * Either a lock screen (an informational keyguard screen), or an unlock
95      * screen (a means for unlocking the device) is shown at any given time.
96      */
97     enum Mode {
98         LockScreen,
99         UnlockScreen
100     }
101 
102     /**
103      * The different types screens available for {@link Mode#UnlockScreen}.
104      * @see com.android.internal.policy.impl.LockPatternKeyguardView#getUnlockMode()
105      */
106     enum UnlockMode {
107 
108         /**
109          * Unlock by drawing a pattern.
110          */
111         Pattern,
112 
113         /**
114          * Unlock by entering a sim pin.
115          */
116         SimPin,
117 
118         /**
119          * Unlock by entering an account's login and password.
120          */
121         Account,
122 
123         /**
124          * Unlock by entering a password or PIN
125          */
126         Password,
127 
128         /**
129          * Unknown (uninitialized) value
130          */
131         Unknown
132     }
133 
134     /**
135      * The current mode.
136      */
137     private Mode mMode = Mode.LockScreen;
138 
139     /**
140      * Keeps track of what mode the current unlock screen is (cached from most recent computation in
141      * {@link #getUnlockMode}).
142      */
143     private UnlockMode mUnlockScreenMode;
144 
145     private boolean mForgotPattern;
146 
147     /**
148      * If true, it means we are in the process of verifying that the user
149      * can get past the lock screen per {@link #verifyUnlock()}
150      */
151     private boolean mIsVerifyUnlockOnly = false;
152 
153 
154     /**
155      * Used to lookup the state of the lock pattern
156      */
157     private final LockPatternUtils mLockPatternUtils;
158 
159     private UnlockMode mCurrentUnlockMode = UnlockMode.Unknown;
160 
161     /**
162      * The current configuration.
163      */
164     private Configuration mConfiguration;
165 
166     /**
167      * @return Whether we are stuck on the lock screen because the sim is
168      *   missing.
169      */
stuckOnLockScreenBecauseSimMissing()170     private boolean stuckOnLockScreenBecauseSimMissing() {
171         return mRequiresSim
172                 && (!mUpdateMonitor.isDeviceProvisioned())
173                 && (mUpdateMonitor.getSimState() == IccCard.State.ABSENT);
174     }
175 
176     /**
177      * @param context Used to inflate, and create views.
178      * @param updateMonitor Knows the state of the world, and passed along to each
179      *   screen so they can use the knowledge, and also register for callbacks
180      *   on dynamic information.
181      * @param lockPatternUtils Used to look up state of lock pattern.
182      */
LockPatternKeyguardView( Context context, KeyguardUpdateMonitor updateMonitor, LockPatternUtils lockPatternUtils, KeyguardWindowController controller)183     public LockPatternKeyguardView(
184             Context context,
185             KeyguardUpdateMonitor updateMonitor,
186             LockPatternUtils lockPatternUtils,
187             KeyguardWindowController controller) {
188         super(context);
189 
190         mConfiguration = context.getResources().getConfiguration();
191         mEnableFallback = false;
192 
193         mRequiresSim =
194                 TextUtils.isEmpty(SystemProperties.get("keyguard.no_require_sim"));
195 
196         mUpdateMonitor = updateMonitor;
197         mLockPatternUtils = lockPatternUtils;
198         mWindowController = controller;
199 
200         mMode = getInitialMode();
201 
202         mKeyguardScreenCallback = new KeyguardScreenCallback() {
203 
204             public void goToLockScreen() {
205                 mForgotPattern = false;
206                 if (mIsVerifyUnlockOnly) {
207                     // navigating away from unlock screen during verify mode means
208                     // we are done and the user failed to authenticate.
209                     mIsVerifyUnlockOnly = false;
210                     getCallback().keyguardDone(false);
211                 } else {
212                     updateScreen(Mode.LockScreen);
213                 }
214             }
215 
216             public void goToUnlockScreen() {
217                 final IccCard.State simState = mUpdateMonitor.getSimState();
218                 if (stuckOnLockScreenBecauseSimMissing()
219                          || (simState == IccCard.State.PUK_REQUIRED)){
220                     // stuck on lock screen when sim missing or puk'd
221                     return;
222                 }
223                 if (!isSecure()) {
224                     getCallback().keyguardDone(true);
225                 } else {
226                     updateScreen(Mode.UnlockScreen);
227                 }
228             }
229 
230             public void forgotPattern(boolean isForgotten) {
231                 if (mEnableFallback) {
232                     mForgotPattern = isForgotten;
233                     updateScreen(Mode.UnlockScreen);
234                 }
235             }
236 
237             public boolean isSecure() {
238                 return LockPatternKeyguardView.this.isSecure();
239             }
240 
241             public boolean isVerifyUnlockOnly() {
242                 return mIsVerifyUnlockOnly;
243             }
244 
245             public void recreateMe(Configuration config) {
246                 mConfiguration = config;
247                 recreateScreens();
248             }
249 
250             public void takeEmergencyCallAction() {
251                 pokeWakelock(EMERGENCY_CALL_TIMEOUT);
252                 if (TelephonyManager.getDefault().getCallState()
253                         == TelephonyManager.CALL_STATE_OFFHOOK) {
254                     mLockPatternUtils.resumeCall();
255                 } else {
256                     Intent intent = new Intent(ACTION_EMERGENCY_DIAL);
257                     intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
258                             | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
259                     getContext().startActivity(intent);
260                 }
261             }
262 
263             public void pokeWakelock() {
264                 getCallback().pokeWakelock();
265             }
266 
267             public void pokeWakelock(int millis) {
268                 getCallback().pokeWakelock(millis);
269             }
270 
271             public void keyguardDone(boolean authenticated) {
272                 getCallback().keyguardDone(authenticated);
273             }
274 
275             public void keyguardDoneDrawing() {
276                 // irrelevant to keyguard screen, they shouldn't be calling this
277             }
278 
279             public void reportFailedUnlockAttempt() {
280                 mUpdateMonitor.reportFailedAttempt();
281                 final int failedAttempts = mUpdateMonitor.getFailedAttempts();
282                 if (DEBUG) Log.d(TAG,
283                     "reportFailedPatternAttempt: #" + failedAttempts +
284                     " (enableFallback=" + mEnableFallback + ")");
285                 final boolean usingLockPattern = mLockPatternUtils.getKeyguardStoredPasswordQuality()
286                         == DevicePolicyManager.PASSWORD_QUALITY_SOMETHING;
287                 if (usingLockPattern && mEnableFallback && failedAttempts ==
288                         (LockPatternUtils.FAILED_ATTEMPTS_BEFORE_RESET
289                                 - LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT)) {
290                     showAlmostAtAccountLoginDialog();
291                 } else if (usingLockPattern && mEnableFallback
292                         && failedAttempts >= LockPatternUtils.FAILED_ATTEMPTS_BEFORE_RESET) {
293                     mLockPatternUtils.setPermanentlyLocked(true);
294                     updateScreen(mMode);
295                 } else if ((failedAttempts % LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT)
296                         == 0) {
297                     showTimeoutDialog();
298                 }
299                 mLockPatternUtils.reportFailedPasswordAttempt();
300             }
301 
302             public boolean doesFallbackUnlockScreenExist() {
303                 return mEnableFallback;
304             }
305 
306             public void reportSuccessfulUnlockAttempt() {
307                 mLockPatternUtils.reportSuccessfulPasswordAttempt();
308             }
309         };
310 
311         /**
312          * We'll get key events the current screen doesn't use. see
313          * {@link KeyguardViewBase#onKeyDown(int, android.view.KeyEvent)}
314          */
315         setFocusableInTouchMode(true);
316         setDescendantFocusability(FOCUS_AFTER_DESCENDANTS);
317 
318         // create both the lock and unlock screen so they are quickly available
319         // when the screen turns on
320         mLockScreen = createLockScreen();
321         addView(mLockScreen);
322         final UnlockMode unlockMode = getUnlockMode();
323         if (DEBUG) Log.d(TAG,
324             "LockPatternKeyguardView ctor: about to createUnlockScreenFor; mEnableFallback="
325             + mEnableFallback);
326         mUnlockScreen = createUnlockScreenFor(unlockMode);
327         mUnlockScreenMode = unlockMode;
328 
329         maybeEnableFallback(context);
330 
331         addView(mUnlockScreen);
332         updateScreen(mMode);
333     }
334 
335     private class AccountAnalyzer implements AccountManagerCallback<Bundle> {
336         private final AccountManager mAccountManager;
337         private final Account[] mAccounts;
338         private int mAccountIndex;
339 
AccountAnalyzer(AccountManager accountManager)340         private AccountAnalyzer(AccountManager accountManager) {
341             mAccountManager = accountManager;
342             mAccounts = accountManager.getAccountsByType("com.google");
343         }
344 
next()345         private void next() {
346             // if we are ready to enable the fallback or if we depleted the list of accounts
347             // then finish and get out
348             if (mEnableFallback || mAccountIndex >= mAccounts.length) {
349                 if (mUnlockScreen == null) {
350                     Log.w(TAG, "no unlock screen when trying to enable fallback");
351                 } else if (mUnlockScreen instanceof PatternUnlockScreen) {
352                     ((PatternUnlockScreen)mUnlockScreen).setEnableFallback(mEnableFallback);
353                 }
354                 return;
355             }
356 
357             // lookup the confirmCredentials intent for the current account
358             mAccountManager.confirmCredentials(mAccounts[mAccountIndex], null, null, this, null);
359         }
360 
start()361         public void start() {
362             mEnableFallback = false;
363             mAccountIndex = 0;
364             next();
365         }
366 
run(AccountManagerFuture<Bundle> future)367         public void run(AccountManagerFuture<Bundle> future) {
368             try {
369                 Bundle result = future.getResult();
370                 if (result.getParcelable(AccountManager.KEY_INTENT) != null) {
371                     mEnableFallback = true;
372                 }
373             } catch (OperationCanceledException e) {
374                 // just skip the account if we are unable to query it
375             } catch (IOException e) {
376                 // just skip the account if we are unable to query it
377             } catch (AuthenticatorException e) {
378                 // just skip the account if we are unable to query it
379             } finally {
380                 mAccountIndex++;
381                 next();
382             }
383         }
384     }
385 
maybeEnableFallback(Context context)386     private void maybeEnableFallback(Context context) {
387         // Ask the account manager if we have an account that can be used as a
388         // fallback in case the user forgets his pattern.
389         AccountAnalyzer accountAnalyzer = new AccountAnalyzer(AccountManager.get(context));
390         accountAnalyzer.start();
391     }
392 
393 
394     // TODO:
395     // This overloaded method was added to workaround a race condition in the framework between
396     // notification for orientation changed, layout() and switching resources.  This code attempts
397     // to avoid drawing the incorrect layout while things are in transition.  The method can just
398     // be removed once the race condition is fixed. See bugs 2262578 and 2292713.
399     @Override
dispatchDraw(Canvas canvas)400     protected void dispatchDraw(Canvas canvas) {
401         if (DEBUG) Log.v(TAG, "*** dispatchDraw() time: " + SystemClock.elapsedRealtime());
402         super.dispatchDraw(canvas);
403     }
404 
405     @Override
reset()406     public void reset() {
407         mIsVerifyUnlockOnly = false;
408         mForgotPattern = false;
409         updateScreen(getInitialMode());
410     }
411 
412     @Override
onScreenTurnedOff()413     public void onScreenTurnedOff() {
414         mScreenOn = false;
415         mForgotPattern = false;
416         if (mMode == Mode.LockScreen) {
417            ((KeyguardScreen) mLockScreen).onPause();
418         } else {
419             ((KeyguardScreen) mUnlockScreen).onPause();
420         }
421     }
422 
423     @Override
onScreenTurnedOn()424     public void onScreenTurnedOn() {
425         mScreenOn = true;
426         if (mMode == Mode.LockScreen) {
427            ((KeyguardScreen) mLockScreen).onResume();
428         } else {
429             ((KeyguardScreen) mUnlockScreen).onResume();
430         }
431     }
432 
recreateLockScreen()433     private void recreateLockScreen() {
434         if (mLockScreen.getVisibility() == View.VISIBLE) {
435             ((KeyguardScreen) mLockScreen).onPause();
436         }
437         ((KeyguardScreen) mLockScreen).cleanUp();
438         removeView(mLockScreen);
439 
440         mLockScreen = createLockScreen();
441         mLockScreen.setVisibility(View.INVISIBLE);
442         addView(mLockScreen);
443     }
444 
recreateUnlockScreen()445     private void recreateUnlockScreen() {
446         if (mUnlockScreen.getVisibility() == View.VISIBLE) {
447             ((KeyguardScreen) mUnlockScreen).onPause();
448         }
449         ((KeyguardScreen) mUnlockScreen).cleanUp();
450         removeView(mUnlockScreen);
451 
452         final UnlockMode unlockMode = getUnlockMode();
453         mUnlockScreen = createUnlockScreenFor(unlockMode);
454         mUnlockScreen.setVisibility(View.INVISIBLE);
455         mUnlockScreenMode = unlockMode;
456         addView(mUnlockScreen);
457     }
458 
recreateScreens()459     private void recreateScreens() {
460         recreateLockScreen();
461         recreateUnlockScreen();
462         updateScreen(mMode);
463     }
464 
465     @Override
wakeWhenReadyTq(int keyCode)466     public void wakeWhenReadyTq(int keyCode) {
467         if (DEBUG) Log.d(TAG, "onWakeKey");
468         if (keyCode == KeyEvent.KEYCODE_MENU && isSecure() && (mMode == Mode.LockScreen)
469                 && (mUpdateMonitor.getSimState() != IccCard.State.PUK_REQUIRED)) {
470             if (DEBUG) Log.d(TAG, "switching screens to unlock screen because wake key was MENU");
471             updateScreen(Mode.UnlockScreen);
472             getCallback().pokeWakelock();
473         } else {
474             if (DEBUG) Log.d(TAG, "poking wake lock immediately");
475             getCallback().pokeWakelock();
476         }
477     }
478 
479     @Override
verifyUnlock()480     public void verifyUnlock() {
481         if (!isSecure()) {
482             // non-secure keyguard screens are successfull by default
483             getCallback().keyguardDone(true);
484         } else if (mUnlockScreenMode != UnlockMode.Pattern) {
485             // can only verify unlock when in pattern mode
486             getCallback().keyguardDone(false);
487         } else {
488             // otherwise, go to the unlock screen, see if they can verify it
489             mIsVerifyUnlockOnly = true;
490             updateScreen(Mode.UnlockScreen);
491         }
492     }
493 
494     @Override
cleanUp()495     public void cleanUp() {
496         ((KeyguardScreen) mLockScreen).onPause();
497         ((KeyguardScreen) mLockScreen).cleanUp();
498         this.removeView(mLockScreen);
499         ((KeyguardScreen) mUnlockScreen).onPause();
500         ((KeyguardScreen) mUnlockScreen).cleanUp();
501         this.removeView(mUnlockScreen);
502     }
503 
isSecure()504     private boolean isSecure() {
505         UnlockMode unlockMode = getUnlockMode();
506         boolean secure = false;
507         switch (unlockMode) {
508             case Pattern:
509                 secure = mLockPatternUtils.isLockPatternEnabled();
510                 break;
511             case SimPin:
512                 secure = mUpdateMonitor.getSimState() == IccCard.State.PIN_REQUIRED
513                             || mUpdateMonitor.getSimState() == IccCard.State.PUK_REQUIRED;
514                 break;
515             case Account:
516                 secure = true;
517                 break;
518             case Password:
519                 secure = mLockPatternUtils.isLockPasswordEnabled();
520                 break;
521             default:
522                 throw new IllegalStateException("unknown unlock mode " + unlockMode);
523         }
524         return secure;
525     }
526 
updateScreen(final Mode mode)527     private void updateScreen(final Mode mode) {
528 
529         if (DEBUG_CONFIGURATION) Log.v(TAG, "**** UPDATE SCREEN: mode=" + mode
530                 + " last mode=" + mMode, new RuntimeException());
531 
532         mMode = mode;
533 
534         // Re-create the unlock screen if necessary. This is primarily required to properly handle
535         // SIM state changes. This typically happens when this method is called by reset()
536         if (mode == Mode.UnlockScreen && mCurrentUnlockMode != getUnlockMode()) {
537             recreateUnlockScreen();
538         }
539 
540         final View goneScreen = (mode == Mode.LockScreen) ? mUnlockScreen : mLockScreen;
541         final View visibleScreen = (mode == Mode.LockScreen) ? mLockScreen : mUnlockScreen;
542 
543         // do this before changing visibility so focus isn't requested before the input
544         // flag is set
545         mWindowController.setNeedsInput(((KeyguardScreen)visibleScreen).needsInput());
546 
547         if (DEBUG_CONFIGURATION) {
548             Log.v(TAG, "Gone=" + goneScreen);
549             Log.v(TAG, "Visible=" + visibleScreen);
550         }
551 
552         if (mScreenOn) {
553             if (goneScreen.getVisibility() == View.VISIBLE) {
554                 ((KeyguardScreen) goneScreen).onPause();
555             }
556             if (visibleScreen.getVisibility() != View.VISIBLE) {
557                 ((KeyguardScreen) visibleScreen).onResume();
558             }
559         }
560 
561         goneScreen.setVisibility(View.GONE);
562         visibleScreen.setVisibility(View.VISIBLE);
563         requestLayout();
564 
565         if (!visibleScreen.requestFocus()) {
566             throw new IllegalStateException("keyguard screen must be able to take "
567                     + "focus when shown " + visibleScreen.getClass().getCanonicalName());
568         }
569     }
570 
createLockScreen()571     View createLockScreen() {
572         return new LockScreen(
573                 mContext,
574                 mConfiguration,
575                 mLockPatternUtils,
576                 mUpdateMonitor,
577                 mKeyguardScreenCallback);
578     }
579 
createUnlockScreenFor(UnlockMode unlockMode)580     View createUnlockScreenFor(UnlockMode unlockMode) {
581         View unlockView = null;
582         if (unlockMode == UnlockMode.Pattern) {
583             PatternUnlockScreen view = new PatternUnlockScreen(
584                     mContext,
585                     mConfiguration,
586                     mLockPatternUtils,
587                     mUpdateMonitor,
588                     mKeyguardScreenCallback,
589                     mUpdateMonitor.getFailedAttempts());
590             if (DEBUG) Log.d(TAG,
591                 "createUnlockScreenFor(" + unlockMode + "): mEnableFallback=" + mEnableFallback);
592             view.setEnableFallback(mEnableFallback);
593             unlockView = view;
594         } else if (unlockMode == UnlockMode.SimPin) {
595             unlockView = new SimUnlockScreen(
596                     mContext,
597                     mConfiguration,
598                     mUpdateMonitor,
599                     mKeyguardScreenCallback,
600                     mLockPatternUtils);
601         } else if (unlockMode == UnlockMode.Account) {
602             try {
603                 unlockView = new AccountUnlockScreen(
604                         mContext,
605                         mConfiguration,
606                         mUpdateMonitor,
607                         mKeyguardScreenCallback,
608                         mLockPatternUtils);
609             } catch (IllegalStateException e) {
610                 Log.i(TAG, "Couldn't instantiate AccountUnlockScreen"
611                       + " (IAccountsService isn't available)");
612                 // TODO: Need a more general way to provide a
613                 // platform-specific fallback UI here.
614                 // For now, if we can't display the account login
615                 // unlock UI, just bring back the regular "Pattern" unlock mode.
616 
617                 // (We do this by simply returning a regular UnlockScreen
618                 // here.  This means that the user will still see the
619                 // regular pattern unlock UI, regardless of the value of
620                 // mUnlockScreenMode or whether or not we're in the
621                 // "permanently locked" state.)
622                 unlockView = createUnlockScreenFor(UnlockMode.Pattern);
623             }
624         } else if (unlockMode == UnlockMode.Password) {
625             unlockView = new PasswordUnlockScreen(
626                     mContext,
627                     mConfiguration,
628                     mLockPatternUtils,
629                     mUpdateMonitor,
630                     mKeyguardScreenCallback);
631         } else {
632             throw new IllegalArgumentException("unknown unlock mode " + unlockMode);
633         }
634         mCurrentUnlockMode = unlockMode;
635         return unlockView;
636     }
637 
638     /**
639      * Given the current state of things, what should be the initial mode of
640      * the lock screen (lock or unlock).
641      */
getInitialMode()642     private Mode getInitialMode() {
643         final IccCard.State simState = mUpdateMonitor.getSimState();
644         if (stuckOnLockScreenBecauseSimMissing() || (simState == IccCard.State.PUK_REQUIRED)) {
645             return Mode.LockScreen;
646         } else {
647             // Show LockScreen first for any screen other than Pattern unlock.
648             final boolean usingLockPattern = mLockPatternUtils.getKeyguardStoredPasswordQuality()
649                     == DevicePolicyManager.PASSWORD_QUALITY_SOMETHING;
650             if (isSecure() && usingLockPattern) {
651                 return Mode.UnlockScreen;
652             } else {
653                 return Mode.LockScreen;
654             }
655         }
656     }
657 
658     /**
659      * Given the current state of things, what should the unlock screen be?
660      */
getUnlockMode()661     private UnlockMode getUnlockMode() {
662         final IccCard.State simState = mUpdateMonitor.getSimState();
663         UnlockMode currentMode;
664         if (simState == IccCard.State.PIN_REQUIRED || simState == IccCard.State.PUK_REQUIRED) {
665             currentMode = UnlockMode.SimPin;
666         } else {
667             final int mode = mLockPatternUtils.getKeyguardStoredPasswordQuality();
668             switch (mode) {
669                 case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC:
670                 case DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC:
671                 case DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC:
672                     currentMode = UnlockMode.Password;
673                     break;
674                 case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING:
675                 case DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED:
676                     // "forgot pattern" button is only available in the pattern mode...
677                     if (mForgotPattern || mLockPatternUtils.isPermanentlyLocked()) {
678                         currentMode = UnlockMode.Account;
679                     } else {
680                         currentMode = UnlockMode.Pattern;
681                     }
682                     break;
683                 default:
684                    throw new IllegalStateException("Unknown unlock mode:" + mode);
685             }
686         }
687         return currentMode;
688     }
689 
showTimeoutDialog()690     private void showTimeoutDialog() {
691         int timeoutInSeconds = (int) LockPatternUtils.FAILED_ATTEMPT_TIMEOUT_MS / 1000;
692         String message = mContext.getString(
693                 R.string.lockscreen_too_many_failed_attempts_dialog_message,
694                 mUpdateMonitor.getFailedAttempts(),
695                 timeoutInSeconds);
696         final AlertDialog dialog = new AlertDialog.Builder(mContext)
697                 .setTitle(null)
698                 .setMessage(message)
699                 .setNeutralButton(R.string.ok, null)
700                 .create();
701         dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
702         if (!mContext.getResources().getBoolean(
703                 com.android.internal.R.bool.config_sf_slowBlur)) {
704             dialog.getWindow().setFlags(
705                     WindowManager.LayoutParams.FLAG_BLUR_BEHIND,
706                     WindowManager.LayoutParams.FLAG_BLUR_BEHIND);
707         }
708         dialog.show();
709     }
710 
showAlmostAtAccountLoginDialog()711     private void showAlmostAtAccountLoginDialog() {
712         int timeoutInSeconds = (int) LockPatternUtils.FAILED_ATTEMPT_TIMEOUT_MS / 1000;
713         String message = mContext.getString(
714                 R.string.lockscreen_failed_attempts_almost_glogin,
715                 LockPatternUtils.FAILED_ATTEMPTS_BEFORE_RESET
716                 - LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT,
717                 LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT,
718                 timeoutInSeconds);
719         final AlertDialog dialog = new AlertDialog.Builder(mContext)
720                 .setTitle(null)
721                 .setMessage(message)
722                 .setNeutralButton(R.string.ok, null)
723                 .create();
724         dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
725         if (!mContext.getResources().getBoolean(
726                 com.android.internal.R.bool.config_sf_slowBlur)) {
727             dialog.getWindow().setFlags(
728                     WindowManager.LayoutParams.FLAG_BLUR_BEHIND,
729                     WindowManager.LayoutParams.FLAG_BLUR_BEHIND);
730         }
731         dialog.show();
732     }
733 
734     /**
735      * Used to put wallpaper on the background of the lock screen.  Centers it
736      * Horizontally and pins the bottom (assuming that the lock screen is aligned
737      * with the bottom, so the wallpaper should extend above the top into the
738      * status bar).
739      */
740     static private class FastBitmapDrawable extends Drawable {
741         private Bitmap mBitmap;
742         private int mOpacity;
743 
FastBitmapDrawable(Bitmap bitmap)744         private FastBitmapDrawable(Bitmap bitmap) {
745             mBitmap = bitmap;
746             mOpacity = mBitmap.hasAlpha() ? PixelFormat.TRANSLUCENT : PixelFormat.OPAQUE;
747         }
748 
749         @Override
draw(Canvas canvas)750         public void draw(Canvas canvas) {
751             canvas.drawBitmap(
752                     mBitmap,
753                     (getBounds().width() - mBitmap.getWidth()) / 2,
754                     (getBounds().height() - mBitmap.getHeight()),
755                     null);
756         }
757 
758         @Override
getOpacity()759         public int getOpacity() {
760             return mOpacity;
761         }
762 
763         @Override
setAlpha(int alpha)764         public void setAlpha(int alpha) {
765         }
766 
767         @Override
setColorFilter(ColorFilter cf)768         public void setColorFilter(ColorFilter cf) {
769         }
770 
771         @Override
getIntrinsicWidth()772         public int getIntrinsicWidth() {
773             return mBitmap.getWidth();
774         }
775 
776         @Override
getIntrinsicHeight()777         public int getIntrinsicHeight() {
778             return mBitmap.getHeight();
779         }
780 
781         @Override
getMinimumWidth()782         public int getMinimumWidth() {
783             return mBitmap.getWidth();
784         }
785 
786         @Override
getMinimumHeight()787         public int getMinimumHeight() {
788             return mBitmap.getHeight();
789         }
790     }
791 }
792 
793