Home | History | Annotate | Download | only in keyguard
      1 /*
      2  * Copyright (C) 2012 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.keyguard;
     18 
     19 import android.content.Context;
     20 import android.content.res.TypedArray;
     21 import android.graphics.drawable.Drawable;
     22 import android.os.Debug;
     23 import android.os.PowerManager;
     24 import android.os.SystemClock;
     25 import android.util.AttributeSet;
     26 import android.view.HapticFeedbackConstants;
     27 import android.view.KeyEvent;
     28 import android.view.LayoutInflater;
     29 import android.view.View;
     30 import android.view.ViewGroup;
     31 import android.view.accessibility.AccessibilityEvent;
     32 import android.widget.TextView;
     33 
     34 import com.android.internal.widget.LockPatternUtils;
     35 
     36 public class NumPadKey extends ViewGroup {
     37     // list of "ABC", etc per digit, starting with '0'
     38     static String sKlondike[];
     39 
     40     private int mDigit = -1;
     41     private int mTextViewResId;
     42     private PasswordTextView mTextView;
     43     private TextView mDigitText;
     44     private TextView mKlondikeText;
     45     private boolean mEnableHaptics;
     46     private PowerManager mPM;
     47 
     48     private View.OnClickListener mListener = new View.OnClickListener() {
     49         @Override
     50         public void onClick(View thisView) {
     51             if (mTextView == null && mTextViewResId > 0) {
     52                 final View v = NumPadKey.this.getRootView().findViewById(mTextViewResId);
     53                 if (v != null && v instanceof PasswordTextView) {
     54                     mTextView = (PasswordTextView) v;
     55                 }
     56             }
     57             if (mTextView != null && mTextView.isEnabled()) {
     58                 mTextView.append(Character.forDigit(mDigit, 10));
     59             }
     60             userActivity();
     61             doHapticKeyClick();
     62         }
     63     };
     64 
     65     public void userActivity() {
     66         mPM.userActivity(SystemClock.uptimeMillis(), false);
     67     }
     68 
     69     public NumPadKey(Context context) {
     70         this(context, null);
     71     }
     72 
     73     public NumPadKey(Context context, AttributeSet attrs) {
     74         this(context, attrs, 0);
     75     }
     76 
     77     public NumPadKey(Context context, AttributeSet attrs, int defStyle) {
     78         super(context, attrs, defStyle);
     79         setFocusable(true);
     80 
     81         TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.NumPadKey);
     82 
     83         try {
     84             mDigit = a.getInt(R.styleable.NumPadKey_digit, mDigit);
     85             mTextViewResId = a.getResourceId(R.styleable.NumPadKey_textView, 0);
     86         } finally {
     87             a.recycle();
     88         }
     89 
     90         setOnClickListener(mListener);
     91         setOnHoverListener(new LiftToActivateListener(context));
     92         setAccessibilityDelegate(new ObscureSpeechDelegate(context));
     93 
     94         mEnableHaptics = new LockPatternUtils(context).isTactileFeedbackEnabled();
     95 
     96         mPM = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
     97         LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(
     98                 Context.LAYOUT_INFLATER_SERVICE);
     99         inflater.inflate(R.layout.keyguard_num_pad_key, this, true);
    100 
    101         mDigitText = (TextView) findViewById(R.id.digit_text);
    102         mDigitText.setText(Integer.toString(mDigit));
    103         mKlondikeText = (TextView) findViewById(R.id.klondike_text);
    104 
    105         if (mDigit >= 0) {
    106             if (sKlondike == null) {
    107                 sKlondike = getResources().getStringArray(R.array.lockscreen_num_pad_klondike);
    108             }
    109             if (sKlondike != null && sKlondike.length > mDigit) {
    110                 String klondike = sKlondike[mDigit];
    111                 final int len = klondike.length();
    112                 if (len > 0) {
    113                     mKlondikeText.setText(klondike);
    114                 } else {
    115                     mKlondikeText.setVisibility(View.INVISIBLE);
    116                 }
    117             }
    118         }
    119 
    120         setBackground(mContext.getDrawable(R.drawable.ripple_drawable));
    121         setContentDescription(mDigitText.getText().toString());
    122     }
    123 
    124     @Override
    125     public void onDetachedFromWindow() {
    126         super.onDetachedFromWindow();
    127 
    128         // Reset the "announced headset" flag when detached.
    129         ObscureSpeechDelegate.sAnnouncedHeadset = false;
    130     }
    131 
    132     @Override
    133     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    134         super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    135         measureChildren(widthMeasureSpec, heightMeasureSpec);
    136     }
    137 
    138     @Override
    139     protected void onLayout(boolean changed, int l, int t, int r, int b) {
    140         int digitHeight = mDigitText.getMeasuredHeight();
    141         int klondikeHeight = mKlondikeText.getMeasuredHeight();
    142         int totalHeight = digitHeight + klondikeHeight;
    143         int top = getHeight() / 2 - totalHeight / 2;
    144         int centerX = getWidth() / 2;
    145         int left = centerX - mDigitText.getMeasuredWidth() / 2;
    146         int bottom = top + digitHeight;
    147         mDigitText.layout(left, top, left + mDigitText.getMeasuredWidth(), bottom);
    148         top = (int) (bottom - klondikeHeight * 0.35f);
    149         bottom = top + klondikeHeight;
    150 
    151         left = centerX - mKlondikeText.getMeasuredWidth() / 2;
    152         mKlondikeText.layout(left, top, left + mKlondikeText.getMeasuredWidth(), bottom);
    153     }
    154 
    155     @Override
    156     public boolean hasOverlappingRendering() {
    157         return false;
    158     }
    159 
    160     // Cause a VIRTUAL_KEY vibration
    161     public void doHapticKeyClick() {
    162         if (mEnableHaptics) {
    163             performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY,
    164                     HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING
    165                     | HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING);
    166         }
    167     }
    168 }
    169