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

AccountUnlockScreen

public class AccountUnlockScreen extends android.widget.RelativeLayout implements android.content.ServiceConnection, KeyguardScreen, android.text.TextWatcher, View.OnClickListener
When the user forgets their password a bunch of times, we fall back on their account's login/password to unlock the phone (and reset their lock pattern).

This class is useful only on platforms that support the IAccountsService.

Fields Summary
private static final String
LOCK_PATTERN_PACKAGE
private static final String
LOCK_PATTERN_CLASS
private static final int
AWAKE_POKE_MILLIS
The amount of millis to stay awake once this screen detects activity
private final KeyguardScreenCallback
mCallback
private final com.android.internal.widget.LockPatternUtils
mLockPatternUtils
private android.accounts.IAccountsService
mAccountsService
private android.widget.TextView
mTopHeader
private android.widget.TextView
mInstructions
private android.widget.EditText
mLogin
private android.widget.EditText
mPassword
private android.widget.Button
mOk
private android.widget.Button
mEmergencyCall
Constructors Summary
public AccountUnlockScreen(android.content.Context context, KeyguardScreenCallback callback, com.android.internal.widget.LockPatternUtils lockPatternUtils)
AccountUnlockScreen constructor.

throws
IllegalStateException if the IAccountsService is not available on the current platform.


                       
      
             
              
        super(context);
        mCallback = callback;
        mLockPatternUtils = lockPatternUtils;

        LayoutInflater.from(context).inflate(
                R.layout.keyguard_screen_glogin_unlock, this, true);

        mTopHeader = (TextView) findViewById(R.id.topHeader);

        mInstructions = (TextView) findViewById(R.id.instructions);

        mLogin = (EditText) findViewById(R.id.login);
        mLogin.setFilters(new InputFilter[] { new LoginFilter.UsernameFilterGeneric() } );
        mLogin.addTextChangedListener(this);

        mPassword = (EditText) findViewById(R.id.password);
        mPassword.addTextChangedListener(this);

        mOk = (Button) findViewById(R.id.ok);
        mOk.setOnClickListener(this);

        mEmergencyCall = (Button) findViewById(R.id.emergencyCall);
        mEmergencyCall.setOnClickListener(this);

        Log.v("AccountUnlockScreen", "debug: Connecting to accounts service");
        final boolean connected = mContext.bindService(AccountsServiceConstants.SERVICE_INTENT,
                this, Context.BIND_AUTO_CREATE);
        if (!connected) {
            Log.v("AccountUnlockScreen", "debug: Couldn't connect to accounts service");
            throw new IllegalStateException("couldn't bind to accounts service");
        }
    
Methods Summary
public voidafterTextChanged(android.text.Editable s)

    
public voidbeforeTextChanged(java.lang.CharSequence s, int start, int count, int after)

    
private booleancheckPassword()

        final String login = mLogin.getText().toString();
        final String password = mPassword.getText().toString();
        try {
            String account = findIntendedAccount(login);
            if (account == null) {
                return false;
            }
            return mAccountsService.shouldUnlock(account, password);
        } catch (RemoteException e) {
            return false;
        }
    
public voidcleanUp()
{@inheritDoc}

        mContext.unbindService(this);
    
public booleandispatchKeyEvent(android.view.KeyEvent event)

        if (event.getAction() == KeyEvent.ACTION_DOWN
                && event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
            mCallback.goToLockScreen();
            return true;
        }
        return super.dispatchKeyEvent(event);
    
private java.lang.StringfindIntendedAccount(java.lang.String username)
Given the string the user entered in the 'username' field, find the stored account that they probably intended. Prefer, in order: - an exact match for what was typed, or - a case-insensitive match for what was typed, or - if they didn't include a domain, an exact match of the username, or - if they didn't include a domain, a case-insensitive match of the username. If there is a tie for the best match, choose neither -- the user needs to be more specific.

return
an account name from the database, or null if we can't find a single best match.

        String[] accounts = null;
        try {
            accounts = mAccountsService.getAccounts();
        } catch (RemoteException e) {
            return null;
        }
        if (accounts == null) {
            return null;
        }

        // Try to figure out which account they meant if they
        // typed only the username (and not the domain), or got
        // the case wrong.

        String bestAccount = null;
        int bestScore = 0;
        for (String a: accounts) {
            int score = 0;
            if (username.equals(a)) {
                score = 4;
            } else if (username.equalsIgnoreCase(a)) {
                score = 3;
            } else if (username.indexOf('@") < 0) {
                int i = a.indexOf('@");
                if (i >= 0) {
                    String aUsername = a.substring(0, i);
                    if (username.equals(aUsername)) {
                        score = 2;
                    } else if (username.equalsIgnoreCase(aUsername)) {
                        score = 1;
                    }
                }
            }
            if (score > bestScore) {
                bestAccount = a;
                bestScore = score;
            } else if (score == bestScore) {
                bestAccount = null;
            }
        }
        return bestAccount;
    
public booleanneedsInput()
{@inheritDoc}

        return true;
    
public voidonClick(android.view.View v)
{@inheritDoc}

        mCallback.pokeWakelock();
        if (v == mOk) {
            if (checkPassword()) {
                // clear out forgotten password
                mLockPatternUtils.setPermanentlyLocked(false);

                // launch the 'choose lock pattern' activity so
                // the user can pick a new one if they want to
                Intent intent = new Intent();
                intent.setClassName(LOCK_PATTERN_PACKAGE, LOCK_PATTERN_CLASS);
                intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                mContext.startActivity(intent);

                // close the keyguard
                mCallback.keyguardDone(true);
            } else {
                mInstructions.setText(R.string.lockscreen_glogin_invalid_input);
                mPassword.setText("");
            }
        }

        if (v == mEmergencyCall) {
            mCallback.takeEmergencyCallAction();
        }
    
public voidonPause()
{@inheritDoc}


    
protected booleanonRequestFocusInDescendants(int direction, android.graphics.Rect previouslyFocusedRect)

        // send focus to the login field
        return mLogin.requestFocus(direction, previouslyFocusedRect);
    
public voidonResume()
{@inheritDoc}

        // start fresh
        mLogin.setText("");
        mPassword.setText("");
        mLogin.requestFocus();
    
public voidonServiceConnected(android.content.ComponentName name, android.os.IBinder service)
{@inheritDoc}

        Log.v("AccountUnlockScreen", "debug: About to grab as interface");
        mAccountsService = IAccountsService.Stub.asInterface(service);
    
public voidonServiceDisconnected(android.content.ComponentName name)
{@inheritDoc}

        mAccountsService = null;
    
public voidonTextChanged(java.lang.CharSequence s, int start, int before, int count)

        mCallback.pokeWakelock(AWAKE_POKE_MILLIS);