1dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller/*
2dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller * Copyright (C) 2012 The Android Open Source Project
3dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller *
4dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller * Licensed under the Apache License, Version 2.0 (the "License");
5dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller * you may not use this file except in compliance with the License.
6dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller * You may obtain a copy of the License at
7dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller *
8dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller *      http://www.apache.org/licenses/LICENSE-2.0
9dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller *
10dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller * Unless required by applicable law or agreed to in writing, software
11dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller * distributed under the License is distributed on an "AS IS" BASIS,
12dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller * See the License for the specific language governing permissions and
14dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller * limitations under the License.
15dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller */
165ecd81154fa039961f65bb4e36d18ac555b0d1d6Jim Millerpackage com.android.keyguard;
17dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller
18dcb3d84b82cc2448d04e73359a716581bfb657dbJim Millerimport android.accounts.Account;
19dcb3d84b82cc2448d04e73359a716581bfb657dbJim Millerimport android.accounts.AccountManager;
20dcb3d84b82cc2448d04e73359a716581bfb657dbJim Millerimport android.accounts.AccountManagerCallback;
21dcb3d84b82cc2448d04e73359a716581bfb657dbJim Millerimport android.accounts.AccountManagerFuture;
22dcb3d84b82cc2448d04e73359a716581bfb657dbJim Millerimport android.accounts.AuthenticatorException;
23dcb3d84b82cc2448d04e73359a716581bfb657dbJim Millerimport android.accounts.OperationCanceledException;
24dcb3d84b82cc2448d04e73359a716581bfb657dbJim Millerimport android.content.Context;
255737534abab477cf32b4dd0aa7a72f70ede0502cJim Millerimport android.graphics.Rect;
26c0ae9e67ebe6f1298800feaed1b43e867139a904Chris Wrenimport android.graphics.drawable.Drawable;
27dcb3d84b82cc2448d04e73359a716581bfb657dbJim Millerimport android.os.Bundle;
28dcb3d84b82cc2448d04e73359a716581bfb657dbJim Millerimport android.os.CountDownTimer;
29dcb3d84b82cc2448d04e73359a716581bfb657dbJim Millerimport android.os.SystemClock;
302c7bc26a7447e6ac9eadcf328259aa3bb1be2949Amith Yamasaniimport android.os.UserHandle;
31dcb3d84b82cc2448d04e73359a716581bfb657dbJim Millerimport android.util.AttributeSet;
32dcb3d84b82cc2448d04e73359a716581bfb657dbJim Millerimport android.util.Log;
33dcb3d84b82cc2448d04e73359a716581bfb657dbJim Millerimport android.view.MotionEvent;
34dcb3d84b82cc2448d04e73359a716581bfb657dbJim Millerimport android.view.View;
35dcb3d84b82cc2448d04e73359a716581bfb657dbJim Millerimport android.widget.Button;
363af630c8d18bcf4b23a5a308917319dd04cc8ed2Jim Millerimport android.widget.LinearLayout;
37dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller
38dcb3d84b82cc2448d04e73359a716581bfb657dbJim Millerimport com.android.internal.widget.LockPatternUtils;
39dcb3d84b82cc2448d04e73359a716581bfb657dbJim Millerimport com.android.internal.widget.LockPatternView;
40dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller
41dcb3d84b82cc2448d04e73359a716581bfb657dbJim Millerimport java.io.IOException;
42dcb3d84b82cc2448d04e73359a716581bfb657dbJim Millerimport java.util.List;
43dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller
443af630c8d18bcf4b23a5a308917319dd04cc8ed2Jim Millerpublic class KeyguardPatternView extends LinearLayout implements KeyguardSecurityView {
45dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller
46dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller    private static final String TAG = "SecurityPatternView";
47dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller    private static final boolean DEBUG = false;
48dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller
49dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller    // how long before we clear the wrong pattern
50dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller    private static final int PATTERN_CLEAR_TIMEOUT_MS = 2000;
51dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller
52dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller    // how long we stay awake after each key beyond MIN_PATTERN_BEFORE_POKE_WAKELOCK
53dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller    private static final int UNLOCK_PATTERN_WAKE_INTERVAL_MS = 7000;
54dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller
55dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller    // how long we stay awake after the user hits the first dot.
56dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller    private static final int UNLOCK_PATTERN_WAKE_INTERVAL_FIRST_DOTS_MS = 2000;
57dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller
58dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller    // how many cells the user has to cross before we poke the wakelock
59dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller    private static final int MIN_PATTERN_BEFORE_POKE_WAKELOCK = 2;
60dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller
61dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller    private int mFailedPatternAttemptsSinceLastTimeout = 0;
62dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller    private int mTotalFailedPatternAttempts = 0;
63dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller    private CountDownTimer mCountdownTimer = null;
64dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller    private LockPatternUtils mLockPatternUtils;
65dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller    private LockPatternView mLockPatternView;
66dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller    private Button mForgotPatternButton;
67dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller    private KeyguardSecurityCallback mCallback;
68dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller    private boolean mEnableFallback;
69dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller
70dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller    /**
71dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller     * Keeps track of the last time we poked the wake lock during dispatching of the touch event.
72dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller     * Initialized to something guaranteed to make us poke the wakelock when the user starts
73dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller     * drawing the pattern.
74dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller     * @see #dispatchTouchEvent(android.view.MotionEvent)
75dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller     */
76dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller    private long mLastPokeTime = -UNLOCK_PATTERN_WAKE_INTERVAL_MS;
77dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller
78dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller    /**
79dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller     * Useful for clearing out the wrong pattern after a delay
80dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller     */
81dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller    private Runnable mCancelPatternRunnable = new Runnable() {
82dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller        public void run() {
83dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller            mLockPatternView.clearPattern();
84dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller        }
85dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller    };
865737534abab477cf32b4dd0aa7a72f70ede0502cJim Miller    private Rect mTempRect = new Rect();
870ff7f010f8bfd011f0915031b02739ae3bee401eJim Miller    private SecurityMessageDisplay mSecurityMessageDisplay;
88c0ae9e67ebe6f1298800feaed1b43e867139a904Chris Wren    private View mEcaView;
89c0ae9e67ebe6f1298800feaed1b43e867139a904Chris Wren    private Drawable mBouncerFrame;
90dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller
91dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller    enum FooterMode {
92dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller        Normal,
93dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller        ForgotLockPattern,
94dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller        VerifyUnlocked
95dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller    }
96dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller
97dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller    public KeyguardPatternView(Context context) {
98dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller        this(context, null);
99dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller    }
100dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller
101dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller    public KeyguardPatternView(Context context, AttributeSet attrs) {
102dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller        super(context, attrs);
103dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller    }
104dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller
105dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller    public void setKeyguardCallback(KeyguardSecurityCallback callback) {
106dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller        mCallback = callback;
107dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller    }
108dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller
109dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller    public void setLockPatternUtils(LockPatternUtils utils) {
110dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller        mLockPatternUtils = utils;
111dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller    }
112dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller
113dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller    @Override
114dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller    protected void onFinishInflate() {
115dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller        super.onFinishInflate();
116dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller        mLockPatternUtils = mLockPatternUtils == null
117dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller                ? new LockPatternUtils(mContext) : mLockPatternUtils;
118dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller
119dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller        mLockPatternView = (LockPatternView) findViewById(R.id.lockPatternView);
120dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller        mLockPatternView.setSaveEnabled(false);
121dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller        mLockPatternView.setFocusable(false);
122dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller        mLockPatternView.setOnPatternListener(new UnlockPatternListener());
123dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller
124dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller        // stealth mode will be the same for the life of this screen
125dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller        mLockPatternView.setInStealthMode(!mLockPatternUtils.isVisiblePatternEnabled());
126dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller
127dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller        // vibrate mode will be the same for the life of this screen
128dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller        mLockPatternView.setTactileFeedbackEnabled(mLockPatternUtils.isTactileFeedbackEnabled());
129dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller
130dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller        mForgotPatternButton = (Button) findViewById(R.id.forgot_password_button);
131b499b1fa082147ad37e1211f32210b44bdbc0750Daniel Sandler        // note: some configurations don't have an emergency call area
132b499b1fa082147ad37e1211f32210b44bdbc0750Daniel Sandler        if (mForgotPatternButton != null) {
133b499b1fa082147ad37e1211f32210b44bdbc0750Daniel Sandler            mForgotPatternButton.setText(R.string.kg_forgot_pattern_button_text);
134b499b1fa082147ad37e1211f32210b44bdbc0750Daniel Sandler            mForgotPatternButton.setOnClickListener(new OnClickListener() {
135b499b1fa082147ad37e1211f32210b44bdbc0750Daniel Sandler                public void onClick(View v) {
136b499b1fa082147ad37e1211f32210b44bdbc0750Daniel Sandler                    mCallback.showBackupSecurity();
137b499b1fa082147ad37e1211f32210b44bdbc0750Daniel Sandler                }
138b499b1fa082147ad37e1211f32210b44bdbc0750Daniel Sandler            });
139b499b1fa082147ad37e1211f32210b44bdbc0750Daniel Sandler        }
140dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller
141dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller        setFocusableInTouchMode(true);
142dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller
143dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller        maybeEnableFallback(mContext);
1440b728244dc87b4a453f2191c2cb37a86e91aee0aJim Miller        mSecurityMessageDisplay = new KeyguardMessageArea.Helper(this);
145c0ae9e67ebe6f1298800feaed1b43e867139a904Chris Wren        mEcaView = findViewById(R.id.keyguard_selector_fade_container);
146c0ae9e67ebe6f1298800feaed1b43e867139a904Chris Wren        View bouncerFrameView = findViewById(R.id.keyguard_bouncer_frame);
147c0ae9e67ebe6f1298800feaed1b43e867139a904Chris Wren        if (bouncerFrameView != null) {
148c0ae9e67ebe6f1298800feaed1b43e867139a904Chris Wren            mBouncerFrame = bouncerFrameView.getBackground();
149c0ae9e67ebe6f1298800feaed1b43e867139a904Chris Wren        }
150dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller    }
151dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller
152dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller    private void updateFooter(FooterMode mode) {
153b499b1fa082147ad37e1211f32210b44bdbc0750Daniel Sandler        if (mForgotPatternButton == null) return; // no ECA? no footer
154b499b1fa082147ad37e1211f32210b44bdbc0750Daniel Sandler
155dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller        switch (mode) {
156dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller            case Normal:
157dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller                if (DEBUG) Log.d(TAG, "mode normal");
158dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller                mForgotPatternButton.setVisibility(View.GONE);
159dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller                break;
160dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller            case ForgotLockPattern:
161dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller                if (DEBUG) Log.d(TAG, "mode ForgotLockPattern");
162dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller                mForgotPatternButton.setVisibility(View.VISIBLE);
163dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller                break;
164dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller            case VerifyUnlocked:
165dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller                if (DEBUG) Log.d(TAG, "mode VerifyUnlocked");
166dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller                mForgotPatternButton.setVisibility(View.GONE);
167dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller        }
168dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller    }
169dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller
170dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller    @Override
171d2b82f70fede8c2ec4de34d8e6462ed4ece13c56Jim Miller    public boolean onTouchEvent(MotionEvent ev) {
172d2b82f70fede8c2ec4de34d8e6462ed4ece13c56Jim Miller        boolean result = super.onTouchEvent(ev);
173dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller        // as long as the user is entering a pattern (i.e sending a touch event that was handled
174dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller        // by this screen), keep poking the wake lock so that the screen will stay on.
175dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller        final long elapsed = SystemClock.elapsedRealtime() - mLastPokeTime;
176dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller        if (result && (elapsed > (UNLOCK_PATTERN_WAKE_INTERVAL_MS - 100))) {
177dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller            mLastPokeTime = SystemClock.elapsedRealtime();
178dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller        }
1795737534abab477cf32b4dd0aa7a72f70ede0502cJim Miller        mTempRect.set(0, 0, 0, 0);
1805737534abab477cf32b4dd0aa7a72f70ede0502cJim Miller        offsetRectIntoDescendantCoords(mLockPatternView, mTempRect);
1815737534abab477cf32b4dd0aa7a72f70ede0502cJim Miller        ev.offsetLocation(mTempRect.left, mTempRect.top);
1825737534abab477cf32b4dd0aa7a72f70ede0502cJim Miller        result = mLockPatternView.dispatchTouchEvent(ev) || result;
1835737534abab477cf32b4dd0aa7a72f70ede0502cJim Miller        ev.offsetLocation(-mTempRect.left, -mTempRect.top);
184dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller        return result;
185dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller    }
186dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller
187dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller    public void reset() {
188dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller        // reset lock pattern
189dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller        mLockPatternView.enableInput();
190dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller        mLockPatternView.setEnabled(true);
191dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller        mLockPatternView.clearPattern();
192dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller
193dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller        // if the user is currently locked out, enforce it.
194dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller        long deadline = mLockPatternUtils.getLockoutAttemptDeadline();
195dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller        if (deadline != 0) {
196dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller            handleAttemptLockout(deadline);
197dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller        } else {
1981625e87e600e8d0752d2f5e1318151a694f1be3eDanielle Millett            displayDefaultSecurityMessage();
199dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller        }
200dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller
201dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller        // the footer depends on how many total attempts the user has failed
202dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller        if (mCallback.isVerifyUnlockOnly()) {
203dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller            updateFooter(FooterMode.VerifyUnlocked);
204dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller        } else if (mEnableFallback &&
205dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller                (mTotalFailedPatternAttempts >= LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT)) {
206dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller            updateFooter(FooterMode.ForgotLockPattern);
207dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller        } else {
208dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller            updateFooter(FooterMode.Normal);
209dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller        }
210dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller
211dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller    }
212dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller
2131625e87e600e8d0752d2f5e1318151a694f1be3eDanielle Millett    private void displayDefaultSecurityMessage() {
2141625e87e600e8d0752d2f5e1318151a694f1be3eDanielle Millett        if (KeyguardUpdateMonitor.getInstance(mContext).getMaxBiometricUnlockAttemptsReached()) {
2151625e87e600e8d0752d2f5e1318151a694f1be3eDanielle Millett            mSecurityMessageDisplay.setMessage(R.string.faceunlock_multiple_failures, true);
2161625e87e600e8d0752d2f5e1318151a694f1be3eDanielle Millett        } else {
2171625e87e600e8d0752d2f5e1318151a694f1be3eDanielle Millett            mSecurityMessageDisplay.setMessage(R.string.kg_pattern_instructions, false);
2181625e87e600e8d0752d2f5e1318151a694f1be3eDanielle Millett        }
2191625e87e600e8d0752d2f5e1318151a694f1be3eDanielle Millett    }
2201625e87e600e8d0752d2f5e1318151a694f1be3eDanielle Millett
2216fb841fa219eaae3e87f2fdc05e105d7a1813c42Adam Cohen    @Override
2226fb841fa219eaae3e87f2fdc05e105d7a1813c42Adam Cohen    public void showUsabilityHint() {
2236fb841fa219eaae3e87f2fdc05e105d7a1813c42Adam Cohen    }
2246fb841fa219eaae3e87f2fdc05e105d7a1813c42Adam Cohen
225dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller    /** TODO: hook this up */
226dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller    public void cleanUp() {
227dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller        if (DEBUG) Log.v(TAG, "Cleanup() called on " + this);
228dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller        mLockPatternUtils = null;
229dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller        mLockPatternView.setOnPatternListener(null);
230dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller    }
231dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller
232dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller    @Override
233dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller    public void onWindowFocusChanged(boolean hasWindowFocus) {
234dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller        super.onWindowFocusChanged(hasWindowFocus);
235dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller        if (hasWindowFocus) {
236dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller            // when timeout dialog closes we want to update our state
237dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller            reset();
238dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller        }
239dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller    }
240dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller
241dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller    private class UnlockPatternListener implements LockPatternView.OnPatternListener {
242dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller
243dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller        public void onPatternStart() {
244dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller            mLockPatternView.removeCallbacks(mCancelPatternRunnable);
245dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller        }
246dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller
247dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller        public void onPatternCleared() {
248dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller        }
249dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller
250dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller        public void onPatternCellAdded(List<LockPatternView.Cell> pattern) {
251dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller            // To guard against accidental poking of the wakelock, look for
252dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller            // the user actually trying to draw a pattern of some minimal length.
253dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller            if (pattern.size() > MIN_PATTERN_BEFORE_POKE_WAKELOCK) {
254dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller                mCallback.userActivity(UNLOCK_PATTERN_WAKE_INTERVAL_MS);
255dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller            } else {
256dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller                // Give just a little extra time if they hit one of the first few dots
257dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller                mCallback.userActivity(UNLOCK_PATTERN_WAKE_INTERVAL_FIRST_DOTS_MS);
258dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller            }
259dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller        }
260dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller
261dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller        public void onPatternDetected(List<LockPatternView.Cell> pattern) {
262dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller            if (mLockPatternUtils.checkPattern(pattern)) {
263d2b82f70fede8c2ec4de34d8e6462ed4ece13c56Jim Miller                mCallback.reportSuccessfulUnlockAttempt();
264dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller                mLockPatternView.setDisplayMode(LockPatternView.DisplayMode.Correct);
265258341c377b6aa9f1bd29a9b507a97967e432dfeJim Miller                mTotalFailedPatternAttempts = 0;
266d2b82f70fede8c2ec4de34d8e6462ed4ece13c56Jim Miller                mCallback.dismiss(true);
267dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller            } else {
268dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller                if (pattern.size() > MIN_PATTERN_BEFORE_POKE_WAKELOCK) {
269dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller                    mCallback.userActivity(UNLOCK_PATTERN_WAKE_INTERVAL_MS);
270dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller                }
271dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller                mLockPatternView.setDisplayMode(LockPatternView.DisplayMode.Wrong);
272dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller                if (pattern.size() >= LockPatternUtils.MIN_PATTERN_REGISTER_FAIL) {
273dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller                    mTotalFailedPatternAttempts++;
274dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller                    mFailedPatternAttemptsSinceLastTimeout++;
275dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller                    mCallback.reportFailedUnlockAttempt();
276dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller                }
277dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller                if (mFailedPatternAttemptsSinceLastTimeout
278dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller                        >= LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT) {
279dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller                    long deadline = mLockPatternUtils.setLockoutAttemptDeadline();
280dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller                    handleAttemptLockout(deadline);
281dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller                } else {
2820a4f900463024908220d0c9bf4b291a6e1284846Adam Cohen                    mSecurityMessageDisplay.setMessage(R.string.kg_wrong_pattern, true);
283dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller                    mLockPatternView.postDelayed(mCancelPatternRunnable, PATTERN_CLEAR_TIMEOUT_MS);
284dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller                }
285dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller            }
286dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller        }
287dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller    }
288dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller
289dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller    private void maybeEnableFallback(Context context) {
290dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller        // Ask the account manager if we have an account that can be used as a
291dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller        // fallback in case the user forgets his pattern.
292dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller        AccountAnalyzer accountAnalyzer = new AccountAnalyzer(AccountManager.get(context));
293dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller        accountAnalyzer.start();
294dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller    }
295dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller
296dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller    private class AccountAnalyzer implements AccountManagerCallback<Bundle> {
297dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller        private final AccountManager mAccountManager;
298dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller        private final Account[] mAccounts;
299dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller        private int mAccountIndex;
300dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller
301dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller        private AccountAnalyzer(AccountManager accountManager) {
302dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller            mAccountManager = accountManager;
3032c7bc26a7447e6ac9eadcf328259aa3bb1be2949Amith Yamasani            mAccounts = accountManager.getAccountsByTypeAsUser("com.google",
3042c7bc26a7447e6ac9eadcf328259aa3bb1be2949Amith Yamasani                    new UserHandle(mLockPatternUtils.getCurrentUser()));
305dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller        }
306dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller
307dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller        private void next() {
308dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller            // if we are ready to enable the fallback or if we depleted the list of accounts
309dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller            // then finish and get out
3106f131416ba4ff48067dc4e627971391a6b6778c4Adam Cohen            if (mEnableFallback || mAccountIndex >= mAccounts.length) {
311dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller                return;
312dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller            }
313dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller
314dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller            // lookup the confirmCredentials intent for the current account
3152c7bc26a7447e6ac9eadcf328259aa3bb1be2949Amith Yamasani            mAccountManager.confirmCredentialsAsUser(mAccounts[mAccountIndex], null, null, this,
3162c7bc26a7447e6ac9eadcf328259aa3bb1be2949Amith Yamasani                    null, new UserHandle(mLockPatternUtils.getCurrentUser()));
317dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller        }
318dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller
319dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller        public void start() {
320dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller            mEnableFallback = false;
321dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller            mAccountIndex = 0;
322dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller            next();
323dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller        }
324dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller
325dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller        public void run(AccountManagerFuture<Bundle> future) {
326dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller            try {
327dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller                Bundle result = future.getResult();
328dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller                if (result.getParcelable(AccountManager.KEY_INTENT) != null) {
329dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller                    mEnableFallback = true;
330dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller                }
331dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller            } catch (OperationCanceledException e) {
332dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller                // just skip the account if we are unable to query it
333dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller            } catch (IOException e) {
334dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller                // just skip the account if we are unable to query it
335dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller            } catch (AuthenticatorException e) {
336dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller                // just skip the account if we are unable to query it
337dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller            } finally {
338dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller                mAccountIndex++;
339dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller                next();
340dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller            }
341dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller        }
342dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller    }
343dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller
344dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller    private void handleAttemptLockout(long elapsedRealtimeDeadline) {
345dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller        mLockPatternView.clearPattern();
346dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller        mLockPatternView.setEnabled(false);
347dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller        final long elapsedRealtime = SystemClock.elapsedRealtime();
3486f131416ba4ff48067dc4e627971391a6b6778c4Adam Cohen        if (mEnableFallback) {
3496f131416ba4ff48067dc4e627971391a6b6778c4Adam Cohen            updateFooter(FooterMode.ForgotLockPattern);
3506f131416ba4ff48067dc4e627971391a6b6778c4Adam Cohen        }
351258341c377b6aa9f1bd29a9b507a97967e432dfeJim Miller
352dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller        mCountdownTimer = new CountDownTimer(elapsedRealtimeDeadline - elapsedRealtime, 1000) {
353dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller
354dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller            @Override
355dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller            public void onTick(long millisUntilFinished) {
356dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller                final int secondsRemaining = (int) (millisUntilFinished / 1000);
3570ff7f010f8bfd011f0915031b02739ae3bee401eJim Miller                mSecurityMessageDisplay.setMessage(
3580a4f900463024908220d0c9bf4b291a6e1284846Adam Cohen                        R.string.kg_too_many_failed_attempts_countdown, true, secondsRemaining);
359dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller            }
360dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller
361dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller            @Override
362dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller            public void onFinish() {
363dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller                mLockPatternView.setEnabled(true);
3641625e87e600e8d0752d2f5e1318151a694f1be3eDanielle Millett                displayDefaultSecurityMessage();
365dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller                // TODO mUnlockIcon.setVisibility(View.VISIBLE);
366dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller                mFailedPatternAttemptsSinceLastTimeout = 0;
367dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller                if (mEnableFallback) {
368dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller                    updateFooter(FooterMode.ForgotLockPattern);
369dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller                } else {
370dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller                    updateFooter(FooterMode.Normal);
371dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller                }
372dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller            }
373dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller
374dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller        }.start();
375dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller    }
376dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller
377dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller    @Override
378dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller    public boolean needsInput() {
379dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller        return false;
380dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller    }
381dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller
382dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller    @Override
383dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller    public void onPause() {
384dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller        if (mCountdownTimer != null) {
385dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller            mCountdownTimer.cancel();
386dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller            mCountdownTimer = null;
387dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller        }
388dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller    }
389dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller
390dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller    @Override
391a042ac90640c0c3fd3c5349083b86bbfd6319b64Chris Wren    public void onResume(int reason) {
392dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller        reset();
393dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller    }
394dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller
395dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller    @Override
396dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller    public KeyguardSecurityCallback getCallback() {
397dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller        return mCallback;
398dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller    }
399dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller
400c0ae9e67ebe6f1298800feaed1b43e867139a904Chris Wren    @Override
401c0ae9e67ebe6f1298800feaed1b43e867139a904Chris Wren    public void showBouncer(int duration) {
402c0ae9e67ebe6f1298800feaed1b43e867139a904Chris Wren        KeyguardSecurityViewHelper.
403c0ae9e67ebe6f1298800feaed1b43e867139a904Chris Wren                showBouncer(mSecurityMessageDisplay, mEcaView, mBouncerFrame, duration);
404c0ae9e67ebe6f1298800feaed1b43e867139a904Chris Wren    }
405dcb3d84b82cc2448d04e73359a716581bfb657dbJim Miller
406c0ae9e67ebe6f1298800feaed1b43e867139a904Chris Wren    @Override
407c0ae9e67ebe6f1298800feaed1b43e867139a904Chris Wren    public void hideBouncer(int duration) {
408c0ae9e67ebe6f1298800feaed1b43e867139a904Chris Wren        KeyguardSecurityViewHelper.
409c0ae9e67ebe6f1298800feaed1b43e867139a904Chris Wren                hideBouncer(mSecurityMessageDisplay, mEcaView, mBouncerFrame, duration);
410c0ae9e67ebe6f1298800feaed1b43e867139a904Chris Wren    }
411c0ae9e67ebe6f1298800feaed1b43e867139a904Chris Wren}
412