KeyguardAbsKeyInputView.java revision 0b728244dc87b4a453f2191c2cb37a86e91aee0a
169bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler/*
269bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler * Copyright (C) 2012 The Android Open Source Project
369bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler *
469bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler * Licensed under the Apache License, Version 2.0 (the "License");
569bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler * you may not use this file except in compliance with the License.
669bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler * You may obtain a copy of the License at
769bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler *
869bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler *      http://www.apache.org/licenses/LICENSE-2.0
969bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler *
1069bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler * Unless required by applicable law or agreed to in writing, software
1169bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler * distributed under the License is distributed on an "AS IS" BASIS,
1269bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1369bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler * See the License for the specific language governing permissions and
1469bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler * limitations under the License.
1569bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler */
1669bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler
1769bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandlerpackage com.android.internal.policy.impl.keyguard;
1869bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler
1969bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandlerimport android.content.Context;
2069bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandlerimport android.graphics.Rect;
2169bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandlerimport android.os.CountDownTimer;
2269bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandlerimport android.os.SystemClock;
2369bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandlerimport android.text.Editable;
2469bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandlerimport android.text.TextWatcher;
251254f2f42f7173ef51d0034975ab5cb7d44f8209Michael Jurkaimport android.util.AttributeSet;
261254f2f42f7173ef51d0034975ab5cb7d44f8209Michael Jurkaimport android.view.HapticFeedbackConstants;
2769bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandlerimport android.view.KeyEvent;
281254f2f42f7173ef51d0034975ab5cb7d44f8209Michael Jurkaimport android.view.View;
2969bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandlerimport android.view.inputmethod.EditorInfo;
3069bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandlerimport android.widget.LinearLayout;
3169bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandlerimport android.widget.TextView;
3269bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandlerimport android.widget.TextView.OnEditorActionListener;
3369bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler
3469bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandlerimport com.android.internal.R;
351254f2f42f7173ef51d0034975ab5cb7d44f8209Michael Jurkaimport com.android.internal.widget.LockPatternUtils;
3669bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler
3769bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler/**
3869bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler * Base class for PIN and password unlock screens.
3969bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler */
4069bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandlerpublic abstract class KeyguardAbsKeyInputView extends LinearLayout
4169bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler        implements KeyguardSecurityView, OnEditorActionListener, TextWatcher {
4269bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler    protected KeyguardSecurityCallback mCallback;
43d5692742c1ff056e9fe55a495632229c86ed5384Daniel Sandler    protected TextView mPasswordEntry;
4469bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler    protected LockPatternUtils mLockPatternUtils;
4569bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler    protected SecurityMessageDisplay mSecurityMessageDisplay;
46acb60fb57783b517e52fa60b1fa5f977141180c1Daniel Sandler    protected boolean mEnableHaptics;
4769bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler
4869bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler    // To avoid accidental lockout due to events while the device in in the pocket, ignore
4969bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler    // any passwords with length less than or equal to this length.
5069bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler    protected static final int MINIMUM_PASSWORD_LENGTH_BEFORE_REPORT = 3;
5169bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler
5269bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler    public KeyguardAbsKeyInputView(Context context) {
5369bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler        this(context, null);
5469bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler    }
5569bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler
5669bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler    public KeyguardAbsKeyInputView(Context context, AttributeSet attrs) {
5769bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler        super(context, attrs);
5869bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler    }
5969bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler
6069bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler    public void setKeyguardCallback(KeyguardSecurityCallback callback) {
6169bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler        mCallback = callback;
6269bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler    }
6369bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler
6469bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler    public void setLockPatternUtils(LockPatternUtils utils) {
6569bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler        mLockPatternUtils = utils;
66acb60fb57783b517e52fa60b1fa5f977141180c1Daniel Sandler        mEnableHaptics = mLockPatternUtils.isTactileFeedbackEnabled();
6769bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler    }
6869bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler
6969bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler    @Override
7069bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler    public void onWindowFocusChanged(boolean hasWindowFocus) {
7169bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler        if (hasWindowFocus) {
7269bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler            reset();
7369bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler        }
7469bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler    }
7569bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler
7669bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler    public void reset() {
7769bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler        // start fresh
7869bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler        mPasswordEntry.setText("");
7969bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler        mPasswordEntry.requestFocus();
8069bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler
8169bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler        // if the user is currently locked out, enforce it.
8269bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler        long deadline = mLockPatternUtils.getLockoutAttemptDeadline();
8369bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler        if (deadline != 0) {
8469bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler            handleAttemptLockout(deadline);
8569bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler        } else {
8669bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler            resetState();
8769bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler        }
8869bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler    }
8969bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler
9069bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler    protected abstract void resetState();
9169bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler
9269bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler    @Override
9369bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler    protected void onFinishInflate() {
94acb60fb57783b517e52fa60b1fa5f977141180c1Daniel Sandler        mLockPatternUtils = new LockPatternUtils(mContext);
9569bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler
96d5692742c1ff056e9fe55a495632229c86ed5384Daniel Sandler        mPasswordEntry = (TextView) findViewById(R.id.passwordEntry);
9769bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler        mPasswordEntry.setOnEditorActionListener(this);
9869bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler        mPasswordEntry.addTextChangedListener(this);
9969bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler
10069bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler        // Poke the wakelock any time the text is selected or modified
10169bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler        mPasswordEntry.setOnClickListener(new OnClickListener() {
10269bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler            public void onClick(View v) {
10369bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler                mCallback.userActivity(0); // TODO: customize timeout for text?
10469bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler            }
10569bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler        });
10669bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler
10769bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler        mPasswordEntry.addTextChangedListener(new TextWatcher() {
10869bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler            public void onTextChanged(CharSequence s, int start, int before, int count) {
10969bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler            }
11069bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler
11169bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler            public void beforeTextChanged(CharSequence s, int start, int count, int after) {
11269bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler            }
11369bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler
11469bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler            public void afterTextChanged(Editable s) {
11569bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler                if (mCallback != null) {
11669bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler                    mCallback.userActivity(0);
11769bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler                }
11869bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler            }
11969bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler        });
1200b728244dc87b4a453f2191c2cb37a86e91aee0aJim Miller        mSecurityMessageDisplay = new KeyguardMessageArea.Helper(this);
12169bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler    }
12269bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler
12369bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler    @Override
12469bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler    protected boolean onRequestFocusInDescendants(int direction, Rect previouslyFocusedRect) {
12569bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler        // send focus to the password field
12669bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler        return mPasswordEntry.requestFocus(direction, previouslyFocusedRect);
12769bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler    }
12869bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler
12969bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler    protected void verifyPasswordAndUnlock() {
13069bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler        String entry = mPasswordEntry.getText().toString();
13169bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler        if (mLockPatternUtils.checkPassword(entry)) {
13269bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler            mCallback.reportSuccessfulUnlockAttempt();
13369bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler            mCallback.dismiss(true);
13469bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler        } else if (entry.length() > MINIMUM_PASSWORD_LENGTH_BEFORE_REPORT ) {
13569bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler            // to avoid accidental lockout, only count attempts that are long enough to be a
13669bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler            // real password. This may require some tweaking.
13769bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler            mCallback.reportFailedUnlockAttempt();
13869bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler            if (0 == (mCallback.getFailedAttempts()
13969bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler                    % LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT)) {
14069bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler                long deadline = mLockPatternUtils.setLockoutAttemptDeadline();
14169bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler                handleAttemptLockout(deadline);
14269bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler            }
14369bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler            mSecurityMessageDisplay.setMessage(R.string.kg_wrong_pin, true);
14469bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler        }
14569bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler        mPasswordEntry.setText("");
14669bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler    }
14769bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler
14869bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler    // Prevent user from using the PIN/Password entry until scheduled deadline.
14969bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler    protected void handleAttemptLockout(long elapsedRealtimeDeadline) {
15069bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler        mPasswordEntry.setEnabled(false);
15169bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler        long elapsedRealtime = SystemClock.elapsedRealtime();
15269bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler        new CountDownTimer(elapsedRealtimeDeadline - elapsedRealtime, 1000) {
15369bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler
15469bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler            @Override
15569bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler            public void onTick(long millisUntilFinished) {
15669bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler                int secondsRemaining = (int) (millisUntilFinished / 1000);
15769bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler                mSecurityMessageDisplay.setMessage(
15869bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler                        R.string.kg_too_many_failed_attempts_countdown, true, secondsRemaining);
15969bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler            }
16069bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler
16169bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler            @Override
16269bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler            public void onFinish() {
16369bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler                resetState();
16469bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler            }
16569bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler        }.start();
16669bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler    }
16769bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler
16869bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler    @Override
16969bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler    public boolean onKeyDown(int keyCode, KeyEvent event) {
17069bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler        mCallback.userActivity(0);
17169bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler        return false;
17269bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler    }
17369bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler
17469bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler    @Override
17569bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler    public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
17669bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler        // Check if this was the result of hitting the enter key
17769bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler        if (actionId == EditorInfo.IME_NULL || actionId == EditorInfo.IME_ACTION_DONE
17869bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler                || actionId == EditorInfo.IME_ACTION_NEXT) {
17969bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler            verifyPasswordAndUnlock();
18069bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler            return true;
18169bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler        }
18269bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler        return false;
18369bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler    }
18469bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler
18569bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler    @Override
18669bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler    public boolean needsInput() {
18769bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler        return false;
18869bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler    }
18969bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler
19069bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler    @Override
19169bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler    public void onPause() {
19269bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler
19369bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler    }
19469bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler
19569bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler    @Override
19669bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler    public void onResume() {
19769bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler        reset();
19869bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler    }
19969bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler
20069bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler    @Override
20169bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler    public KeyguardSecurityCallback getCallback() {
20269bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler        return mCallback;
20369bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler    }
20469bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler
20569bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler    @Override
20669bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler    public void beforeTextChanged(CharSequence s, int start, int count, int after) {
20769bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler        if (mCallback != null) {
20869bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler            mCallback.userActivity(KeyguardViewManager.DIGIT_PRESS_WAKE_MILLIS);
20969bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler        }
21069bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler    }
21169bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler
21269bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler    @Override
21369bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler    public void onTextChanged(CharSequence s, int start, int before, int count) {
21469bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler    }
21569bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler
21669bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler    @Override
21769bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler    public void afterTextChanged(Editable s) {
21869bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler    }
21969bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler
220acb60fb57783b517e52fa60b1fa5f977141180c1Daniel Sandler    // Cause a VIRTUAL_KEY vibration
221acb60fb57783b517e52fa60b1fa5f977141180c1Daniel Sandler    public void doHapticKeyClick() {
222acb60fb57783b517e52fa60b1fa5f977141180c1Daniel Sandler        if (mEnableHaptics) {
223acb60fb57783b517e52fa60b1fa5f977141180c1Daniel Sandler            performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY,
224acb60fb57783b517e52fa60b1fa5f977141180c1Daniel Sandler                    HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING
225acb60fb57783b517e52fa60b1fa5f977141180c1Daniel Sandler                    | HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING);
226acb60fb57783b517e52fa60b1fa5f977141180c1Daniel Sandler        }
227acb60fb57783b517e52fa60b1fa5f977141180c1Daniel Sandler    }
22869bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler}
22969bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler
230