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