FileDocCategorySizeDatePackage
LockPatternKeyguardView.javaAPI DocAndroid 1.5 API22647Wed May 06 22:42:06 BST 2009com.android.internal.policy.impl

LockPatternKeyguardView

public class LockPatternKeyguardView extends KeyguardViewBase
The host view for all of the screens of the pattern unlock screen. There are two {@link Mode}s of operation, lock and unlock. This will show the appropriate screen, and listen for callbacks via {@link com.android.internal.policy.impl.KeyguardScreenCallback from the current screen. This view, in turn, communicates back to {@link com.android.internal.policy.impl.KeyguardViewManager} via its {@link com.android.internal.policy.impl.KeyguardViewCallback}, as appropriate.

Fields Summary
static final String
ACTION_EMERGENCY_DIAL
private static final boolean
DEBUG
private static final String
TAG
private final KeyguardUpdateMonitor
mUpdateMonitor
private final KeyguardWindowController
mWindowController
private android.view.View
mLockScreen
private android.view.View
mUnlockScreen
private boolean
mScreenOn
private boolean
mHasAccount
KeyguardScreenCallback
mKeyguardScreenCallback
The current {@link KeyguardScreen} will use this to communicate back to us.
private boolean
mRequiresSim
private Mode
mMode
The current mode.
private UnlockMode
mUnlockScreenMode
Keeps track of what mode the current unlock screen is
private boolean
mIsVerifyUnlockOnly
If true, it means we are in the process of verifying that the user can get past the lock screen per {@link #verifyUnlock()}
private final com.android.internal.widget.LockPatternUtils
mLockPatternUtils
Used to lookup the state of the lock pattern
private android.content.ServiceConnection
mServiceConnection
Used to fetch accounts from GLS.
Constructors Summary
public LockPatternKeyguardView(android.content.Context context, KeyguardUpdateMonitor updateMonitor, com.android.internal.widget.LockPatternUtils lockPatternUtils, KeyguardWindowController controller)

param
context Used to inflate, and create views.
param
updateMonitor Knows the state of the world, and passed along to each screen so they can use the knowledge, and also register for callbacks on dynamic information.
param
lockPatternUtils Used to look up state of lock pattern.

        super(context);
        
        asyncCheckForAccount();
        
        mRequiresSim =
                TextUtils.isEmpty(SystemProperties.get("keyguard.no_require_sim"));

        mUpdateMonitor = updateMonitor;
        mLockPatternUtils = lockPatternUtils;
        mWindowController = controller;

        mMode = getInitialMode();
        
        mKeyguardScreenCallback = new KeyguardScreenCallback() {

            public void goToLockScreen() {
                if (mIsVerifyUnlockOnly) {
                    // navigating away from unlock screen during verify mode means
                    // we are done and the user failed to authenticate.
                    mIsVerifyUnlockOnly = false;
                    getCallback().keyguardDone(false);
                } else {
                    updateScreen(Mode.LockScreen);
                }
            }

            public void goToUnlockScreen() {
                final SimCard.State simState = mUpdateMonitor.getSimState();
                if (stuckOnLockScreenBecauseSimMissing()
                         || (simState == SimCard.State.PUK_REQUIRED)){
                    // stuck on lock screen when sim missing or puk'd
                    return;
                }
                if (!isSecure()) {
                    getCallback().keyguardDone(true);
                } else {
                    updateScreen(Mode.UnlockScreen);
                }
            }

            public boolean isSecure() {
                return LockPatternKeyguardView.this.isSecure();
            }

            public boolean isVerifyUnlockOnly() {
                return mIsVerifyUnlockOnly;
            }

            public void recreateMe() {
                recreateScreens();
            }

            public void takeEmergencyCallAction() {
                Intent intent = new Intent(ACTION_EMERGENCY_DIAL);
                intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
                        | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
                getContext().startActivity(intent);
            }

            public void pokeWakelock() {
                getCallback().pokeWakelock();
            }

            public void pokeWakelock(int millis) {
                getCallback().pokeWakelock(millis);
            }

            public void keyguardDone(boolean authenticated) {
                getCallback().keyguardDone(authenticated);
            }

            public void keyguardDoneDrawing() {
                // irrelevant to keyguard screen, they shouldn't be calling this
            }

            public void reportFailedPatternAttempt() {
                mUpdateMonitor.reportFailedAttempt();
                final int failedAttempts = mUpdateMonitor.getFailedAttempts();
                if (mHasAccount && failedAttempts ==
                        (LockPatternUtils.FAILED_ATTEMPTS_BEFORE_RESET 
                                - LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT)) {
                    showAlmostAtAccountLoginDialog();
                } else if (mHasAccount
                        && failedAttempts >= LockPatternUtils.FAILED_ATTEMPTS_BEFORE_RESET) {
                    mLockPatternUtils.setPermanentlyLocked(true);
                    updateScreen(mMode);
                } else if ((failedAttempts % LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT)
                        == 0) {
                    showTimeoutDialog();
                }
            }
            
            public boolean doesFallbackUnlockScreenExist() {
                return mHasAccount;
            }
        };

        /**
         * We'll get key events the current screen doesn't use. see
         * {@link KeyguardViewBase#onKeyDown(int, android.view.KeyEvent)}
         */
        setFocusableInTouchMode(true);
        setDescendantFocusability(FOCUS_AFTER_DESCENDANTS);

        // wall paper background
        final BitmapDrawable drawable = (BitmapDrawable) context.getWallpaper();
        setBackgroundDrawable(
                new FastBitmapDrawable(drawable.getBitmap()));

        // create both the lock and unlock screen so they are quickly available
        // when the screen turns on
        mLockScreen = createLockScreen();
        addView(mLockScreen);
        final UnlockMode unlockMode = getUnlockMode();
        mUnlockScreen = createUnlockScreenFor(unlockMode);
        mUnlockScreenMode = unlockMode;
        addView(mUnlockScreen);
        updateScreen(mMode);
    
Methods Summary
private voidasyncCheckForAccount()
Asynchronously checks for at least one account. This will set mHasAccount to true if an account is found.

        
        mServiceConnection = new ServiceConnection() {
            public void onServiceConnected(ComponentName className, IBinder service) {
                try {
                    IAccountsService accountsService = IAccountsService.Stub.asInterface(service);
                    String accounts[] = accountsService.getAccounts();
                    mHasAccount = (accounts.length > 0);
                } catch (RemoteException e) {
                    // Not much we can do here...
                    Log.e(TAG, "Gls died while attempting to get accounts: " + e);
                } finally {
                    getContext().unbindService(mServiceConnection);
                    mServiceConnection = null;
                }
            }

            public void onServiceDisconnected(ComponentName className) {
                // nothing to do here
            }
        };
        boolean status = getContext().bindService(AccountsServiceConstants.SERVICE_INTENT,
                mServiceConnection, Context.BIND_AUTO_CREATE);
        if (!status) Log.e(TAG, "Failed to bind to GLS while checking for account");
    
public voidcleanUp()

        ((KeyguardScreen) mLockScreen).onPause();
        ((KeyguardScreen) mLockScreen).cleanUp();
        ((KeyguardScreen) mUnlockScreen).onPause();
        ((KeyguardScreen) mUnlockScreen).cleanUp();
    
android.view.ViewcreateLockScreen()

        return new LockScreen(
                mContext,
                mLockPatternUtils,
                mUpdateMonitor,
                mKeyguardScreenCallback);
    
android.view.ViewcreateUnlockScreenFor(com.android.internal.policy.impl.LockPatternKeyguardView$UnlockMode unlockMode)

        if (unlockMode == UnlockMode.Pattern) {
            return new UnlockScreen(
                    mContext,
                    mLockPatternUtils,
                    mUpdateMonitor,
                    mKeyguardScreenCallback,
                    mUpdateMonitor.getFailedAttempts());
        } else if (unlockMode == UnlockMode.SimPin) {
            return new SimUnlockScreen(
                    mContext,
                    mUpdateMonitor,
                    mKeyguardScreenCallback);
        } else if (unlockMode == UnlockMode.Account) {
            try {
                return new AccountUnlockScreen(
                        mContext,
                        mKeyguardScreenCallback,
                        mLockPatternUtils);
            } catch (IllegalStateException e) {
                Log.i(TAG, "Couldn't instantiate AccountUnlockScreen"
                      + " (IAccountsService isn't available)");
                // TODO: Need a more general way to provide a
                // platform-specific fallback UI here.
                // For now, if we can't display the account login
                // unlock UI, just bring back the regular "Pattern" unlock mode.

                // (We do this by simply returning a regular UnlockScreen
                // here.  This means that the user will still see the
                // regular pattern unlock UI, regardless of the value of
                // mUnlockScreenMode or whether or not we're in the
                // "permanently locked" state.)
                return createUnlockScreenFor(UnlockMode.Pattern);
            }
        } else {
            throw new IllegalArgumentException("unknown unlock mode " + unlockMode);
        }
    
private com.android.internal.policy.impl.LockPatternKeyguardView$ModegetInitialMode()
Given the current state of things, what should be the initial mode of the lock screen (lock or unlock).

        final SimCard.State simState = mUpdateMonitor.getSimState();
        if (stuckOnLockScreenBecauseSimMissing() || (simState == SimCard.State.PUK_REQUIRED)) {
            return Mode.LockScreen;
        } else if (mUpdateMonitor.isKeyboardOpen() && isSecure()) {
            return Mode.UnlockScreen;
        } else {
            return Mode.LockScreen;
        }
    
private com.android.internal.policy.impl.LockPatternKeyguardView$UnlockModegetUnlockMode()
Given the current state of things, what should the unlock screen be?

        final SimCard.State simState = mUpdateMonitor.getSimState();
        if (simState == SimCard.State.PIN_REQUIRED || simState == SimCard.State.PUK_REQUIRED) {
            return UnlockMode.SimPin;
        } else {
            return mLockPatternUtils.isPermanentlyLocked() ?
                    UnlockMode.Account:
                    UnlockMode.Pattern;
        }
    
private android.view.ViewgetUnlockScreenForCurrentUnlockMode()

        final UnlockMode unlockMode = getUnlockMode();

        // if a screen exists for the correct mode, we're done
        if (unlockMode == mUnlockScreenMode) {
            return mUnlockScreen;
        }

        // remember the mode
        mUnlockScreenMode = unlockMode;

        // unlock mode has changed and we have an existing old unlock screen
        // to clean up
        if (mScreenOn && (mUnlockScreen.getVisibility() == View.VISIBLE)) {
            ((KeyguardScreen) mUnlockScreen).onPause();
        }
        ((KeyguardScreen) mUnlockScreen).cleanUp();
        removeViewInLayout(mUnlockScreen);

        // create the new one
        mUnlockScreen = createUnlockScreenFor(unlockMode);
        mUnlockScreen.setVisibility(View.INVISIBLE);
        addView(mUnlockScreen);
        return mUnlockScreen;
    
private booleanisSecure()

        UnlockMode unlockMode = getUnlockMode();
        if (unlockMode == UnlockMode.Pattern) {
            return mLockPatternUtils.isLockPatternEnabled();
        } else if (unlockMode == UnlockMode.SimPin) {
            return mUpdateMonitor.getSimState() == SimCard.State.PIN_REQUIRED
                        || mUpdateMonitor.getSimState() == SimCard.State.PUK_REQUIRED;
        } else if (unlockMode == UnlockMode.Account) {
            return true;
        } else {
            throw new IllegalStateException("unknown unlock mode " + unlockMode);
        }
    
public voidonScreenTurnedOff()

        mScreenOn = false;
        if (mMode == Mode.LockScreen) {
           ((KeyguardScreen) mLockScreen).onPause();
        } else {
            ((KeyguardScreen) mUnlockScreen).onPause();
        }
    
public voidonScreenTurnedOn()

        mScreenOn = true;
        if (mMode == Mode.LockScreen) {
           ((KeyguardScreen) mLockScreen).onResume();
        } else {
            ((KeyguardScreen) mUnlockScreen).onResume();
        }
    
private voidrecreateScreens()

        if (mLockScreen.getVisibility() == View.VISIBLE) {
            ((KeyguardScreen) mLockScreen).onPause();
        }
        ((KeyguardScreen) mLockScreen).cleanUp();
        removeViewInLayout(mLockScreen);

        mLockScreen = createLockScreen();
        mLockScreen.setVisibility(View.INVISIBLE);
        addView(mLockScreen);

        if (mUnlockScreen.getVisibility() == View.VISIBLE) {
            ((KeyguardScreen) mUnlockScreen).onPause();
        }
        ((KeyguardScreen) mUnlockScreen).cleanUp();
        removeViewInLayout(mUnlockScreen);

        final UnlockMode unlockMode = getUnlockMode();
        mUnlockScreen = createUnlockScreenFor(unlockMode);
        mUnlockScreen.setVisibility(View.INVISIBLE);
        mUnlockScreenMode = unlockMode;
        addView(mUnlockScreen);

        updateScreen(mMode);
    
public voidreset()

        mIsVerifyUnlockOnly = false;
        updateScreen(getInitialMode());
    
private voidshowAlmostAtAccountLoginDialog()

        int timeoutInSeconds = (int) LockPatternUtils.FAILED_ATTEMPT_TIMEOUT_MS / 1000;
        String message = mContext.getString(
                R.string.lockscreen_failed_attempts_almost_glogin,
                LockPatternUtils.FAILED_ATTEMPTS_BEFORE_RESET - LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT,
                LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT,
                timeoutInSeconds);
        final AlertDialog dialog = new AlertDialog.Builder(mContext)
                .setTitle(null)
                .setMessage(message)
                .setNeutralButton(R.string.ok, null)
                .create();
        dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
        dialog.getWindow().setFlags(
                WindowManager.LayoutParams.FLAG_BLUR_BEHIND,
                WindowManager.LayoutParams.FLAG_BLUR_BEHIND);
        dialog.show();
    
private voidshowTimeoutDialog()

        int timeoutInSeconds = (int) LockPatternUtils.FAILED_ATTEMPT_TIMEOUT_MS / 1000;
        String message = mContext.getString(
                R.string.lockscreen_too_many_failed_attempts_dialog_message,
                mUpdateMonitor.getFailedAttempts(),
                timeoutInSeconds);
        final AlertDialog dialog = new AlertDialog.Builder(mContext)
                .setTitle(null)
                .setMessage(message)
                .setNeutralButton(R.string.ok, null)
                .create();
        dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
        dialog.getWindow().setFlags(
                WindowManager.LayoutParams.FLAG_BLUR_BEHIND,
                WindowManager.LayoutParams.FLAG_BLUR_BEHIND);
        dialog.show();
    
private booleanstuckOnLockScreenBecauseSimMissing()

return
Whether we are stuck on the lock screen because the sim is missing.


                         
       
        return mRequiresSim
                && (!mUpdateMonitor.isDeviceProvisioned())
                && (mUpdateMonitor.getSimState() == SimCard.State.ABSENT);
    
private voidupdateScreen(com.android.internal.policy.impl.LockPatternKeyguardView$Mode mode)


        mMode = mode;

        final View goneScreen = (mode == Mode.LockScreen) ? mUnlockScreen : mLockScreen;
        final View visibleScreen = (mode == Mode.LockScreen)
                ? mLockScreen : getUnlockScreenForCurrentUnlockMode();

        // do this before changing visibility so focus isn't requested before the input
        // flag is set
        mWindowController.setNeedsInput(((KeyguardScreen)visibleScreen).needsInput());
        

        if (mScreenOn) {
            if (goneScreen.getVisibility() == View.VISIBLE) {
                ((KeyguardScreen) goneScreen).onPause();
            }
            if (visibleScreen.getVisibility() != View.VISIBLE) {
                ((KeyguardScreen) visibleScreen).onResume();
            }
        }

        goneScreen.setVisibility(View.GONE);
        visibleScreen.setVisibility(View.VISIBLE);


        if (!visibleScreen.requestFocus()) {
            throw new IllegalStateException("keyguard screen must be able to take "
                    + "focus when shown " + visibleScreen.getClass().getCanonicalName());
        }
    
public voidverifyUnlock()

        if (!isSecure()) {
            // non-secure keyguard screens are successfull by default
            getCallback().keyguardDone(true);
        } else if (mUnlockScreenMode != UnlockMode.Pattern) {
            // can only verify unlock when in pattern mode
            getCallback().keyguardDone(false);
        } else {
            // otherwise, go to the unlock screen, see if they can verify it
            mIsVerifyUnlockOnly = true;
            updateScreen(Mode.UnlockScreen);
        }
    
public voidwakeWhenReadyTq(int keyCode)

        if (DEBUG) Log.d(TAG, "onWakeKey");
        if (keyCode == KeyEvent.KEYCODE_MENU && isSecure() && (mMode == Mode.LockScreen)
                && (mUpdateMonitor.getSimState() != SimCard.State.PUK_REQUIRED)) {
            if (DEBUG) Log.d(TAG, "switching screens to unlock screen because wake key was MENU");
            updateScreen(Mode.UnlockScreen);
            getCallback().pokeWakelock();
        } else {
            if (DEBUG) Log.d(TAG, "poking wake lock immediately");
            getCallback().pokeWakelock();
        }