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
175ecd81154fa039961f65bb4e36d18ac555b0d1d6Jim Millerpackage com.android.keyguard;
1869bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler
1969bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandlerimport android.content.Context;
2069bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandlerimport android.content.res.TypedArray;
214e8b9ed30b67e5449d987e674b2966dc7f3ac224Selim Cinekimport android.os.PowerManager;
224e8b9ed30b67e5449d987e674b2966dc7f3ac224Selim Cinekimport android.os.SystemClock;
2369bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandlerimport android.util.AttributeSet;
24acb60fb57783b517e52fa60b1fa5f977141180c1Daniel Sandlerimport android.view.HapticFeedbackConstants;
254e8b9ed30b67e5449d987e674b2966dc7f3ac224Selim Cinekimport android.view.LayoutInflater;
2669bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandlerimport android.view.View;
274e8b9ed30b67e5449d987e674b2966dc7f3ac224Selim Cinekimport android.view.ViewGroup;
2869bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandlerimport android.widget.TextView;
2969bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler
30acb60fb57783b517e52fa60b1fa5f977141180c1Daniel Sandlerimport com.android.internal.widget.LockPatternUtils;
3169bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler
324e8b9ed30b67e5449d987e674b2966dc7f3ac224Selim Cinekpublic class NumPadKey extends ViewGroup {
33d5692742c1ff056e9fe55a495632229c86ed5384Daniel Sandler    // list of "ABC", etc per digit, starting with '0'
34d5692742c1ff056e9fe55a495632229c86ed5384Daniel Sandler    static String sKlondike[];
3569bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler
364e8b9ed30b67e5449d987e674b2966dc7f3ac224Selim Cinek    private int mDigit = -1;
374e8b9ed30b67e5449d987e674b2966dc7f3ac224Selim Cinek    private int mTextViewResId;
384e8b9ed30b67e5449d987e674b2966dc7f3ac224Selim Cinek    private PasswordTextView mTextView;
394e8b9ed30b67e5449d987e674b2966dc7f3ac224Selim Cinek    private TextView mDigitText;
404e8b9ed30b67e5449d987e674b2966dc7f3ac224Selim Cinek    private TextView mKlondikeText;
414e8b9ed30b67e5449d987e674b2966dc7f3ac224Selim Cinek    private boolean mEnableHaptics;
424e8b9ed30b67e5449d987e674b2966dc7f3ac224Selim Cinek    private PowerManager mPM;
4369bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler
4469bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler    private View.OnClickListener mListener = new View.OnClickListener() {
4569bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler        @Override
4669bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler        public void onClick(View thisView) {
474e8b9ed30b67e5449d987e674b2966dc7f3ac224Selim Cinek            if (mTextView == null && mTextViewResId > 0) {
484e8b9ed30b67e5449d987e674b2966dc7f3ac224Selim Cinek                final View v = NumPadKey.this.getRootView().findViewById(mTextViewResId);
494e8b9ed30b67e5449d987e674b2966dc7f3ac224Selim Cinek                if (v != null && v instanceof PasswordTextView) {
504e8b9ed30b67e5449d987e674b2966dc7f3ac224Selim Cinek                    mTextView = (PasswordTextView) v;
5169bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler                }
5269bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler            }
536a64ac56b7a8b81e6f24b5ad9856185488f4178dDaniel Sandler            if (mTextView != null && mTextView.isEnabled()) {
544e8b9ed30b67e5449d987e674b2966dc7f3ac224Selim Cinek                mTextView.append(Character.forDigit(mDigit, 10));
5569bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler            }
564e8b9ed30b67e5449d987e674b2966dc7f3ac224Selim Cinek            userActivity();
57acb60fb57783b517e52fa60b1fa5f977141180c1Daniel Sandler            doHapticKeyClick();
5869bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler        }
5969bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler    };
6069bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler
614e8b9ed30b67e5449d987e674b2966dc7f3ac224Selim Cinek    public void userActivity() {
624e8b9ed30b67e5449d987e674b2966dc7f3ac224Selim Cinek        mPM.userActivity(SystemClock.uptimeMillis(), false);
634e8b9ed30b67e5449d987e674b2966dc7f3ac224Selim Cinek    }
644e8b9ed30b67e5449d987e674b2966dc7f3ac224Selim Cinek
6569bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler    public NumPadKey(Context context) {
6669bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler        this(context, null);
6769bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler    }
6869bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler
6969bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler    public NumPadKey(Context context, AttributeSet attrs) {
7069bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler        this(context, attrs, 0);
7169bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler    }
7269bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler
7369bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler    public NumPadKey(Context context, AttributeSet attrs, int defStyle) {
7469bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler        super(context, attrs, defStyle);
754e8b9ed30b67e5449d987e674b2966dc7f3ac224Selim Cinek        setFocusable(true);
7669bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler
7769bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.NumPadKey);
784e8b9ed30b67e5449d987e674b2966dc7f3ac224Selim Cinek
794e8b9ed30b67e5449d987e674b2966dc7f3ac224Selim Cinek        try {
804e8b9ed30b67e5449d987e674b2966dc7f3ac224Selim Cinek            mDigit = a.getInt(R.styleable.NumPadKey_digit, mDigit);
814e8b9ed30b67e5449d987e674b2966dc7f3ac224Selim Cinek            mTextViewResId = a.getResourceId(R.styleable.NumPadKey_textView, 0);
824e8b9ed30b67e5449d987e674b2966dc7f3ac224Selim Cinek        } finally {
834e8b9ed30b67e5449d987e674b2966dc7f3ac224Selim Cinek            a.recycle();
844e8b9ed30b67e5449d987e674b2966dc7f3ac224Selim Cinek        }
8569bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler
8669bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler        setOnClickListener(mListener);
87c7375afef77b29b7fdb25f48dbe649b7b7fd487calanv        setOnHoverListener(new LiftToActivateListener(context));
880cbbc5766fb7c56c49ec55eece905fa7764a8b2balanv        setAccessibilityDelegate(new ObscureSpeechDelegate(context));
8969bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler
90acb60fb57783b517e52fa60b1fa5f977141180c1Daniel Sandler        mEnableHaptics = new LockPatternUtils(context).isTactileFeedbackEnabled();
91acb60fb57783b517e52fa60b1fa5f977141180c1Daniel Sandler
924e8b9ed30b67e5449d987e674b2966dc7f3ac224Selim Cinek        mPM = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
934e8b9ed30b67e5449d987e674b2966dc7f3ac224Selim Cinek        LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(
944e8b9ed30b67e5449d987e674b2966dc7f3ac224Selim Cinek                Context.LAYOUT_INFLATER_SERVICE);
954e8b9ed30b67e5449d987e674b2966dc7f3ac224Selim Cinek        inflater.inflate(R.layout.keyguard_num_pad_key, this, true);
964e8b9ed30b67e5449d987e674b2966dc7f3ac224Selim Cinek
974e8b9ed30b67e5449d987e674b2966dc7f3ac224Selim Cinek        mDigitText = (TextView) findViewById(R.id.digit_text);
984e8b9ed30b67e5449d987e674b2966dc7f3ac224Selim Cinek        mDigitText.setText(Integer.toString(mDigit));
994e8b9ed30b67e5449d987e674b2966dc7f3ac224Selim Cinek        mKlondikeText = (TextView) findViewById(R.id.klondike_text);
1004e8b9ed30b67e5449d987e674b2966dc7f3ac224Selim Cinek
10169bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler        if (mDigit >= 0) {
102d5692742c1ff056e9fe55a495632229c86ed5384Daniel Sandler            if (sKlondike == null) {
1034e8b9ed30b67e5449d987e674b2966dc7f3ac224Selim Cinek                sKlondike = getResources().getStringArray(R.array.lockscreen_num_pad_klondike);
104d5692742c1ff056e9fe55a495632229c86ed5384Daniel Sandler            }
105d5692742c1ff056e9fe55a495632229c86ed5384Daniel Sandler            if (sKlondike != null && sKlondike.length > mDigit) {
1064e8b9ed30b67e5449d987e674b2966dc7f3ac224Selim Cinek                String klondike = sKlondike[mDigit];
1074e8b9ed30b67e5449d987e674b2966dc7f3ac224Selim Cinek                final int len = klondike.length();
1084e8b9ed30b67e5449d987e674b2966dc7f3ac224Selim Cinek                if (len > 0) {
1094e8b9ed30b67e5449d987e674b2966dc7f3ac224Selim Cinek                    mKlondikeText.setText(klondike);
1104e8b9ed30b67e5449d987e674b2966dc7f3ac224Selim Cinek                } else {
1114e8b9ed30b67e5449d987e674b2966dc7f3ac224Selim Cinek                    mKlondikeText.setVisibility(View.INVISIBLE);
112d5692742c1ff056e9fe55a495632229c86ed5384Daniel Sandler                }
11369bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler            }
11469bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler        }
1154e8b9ed30b67e5449d987e674b2966dc7f3ac224Selim Cinek
1164e8b9ed30b67e5449d987e674b2966dc7f3ac224Selim Cinek        setBackground(mContext.getDrawable(R.drawable.ripple_drawable));
11742661cba30aaf9a0945a9edede1b18a64fb8b8f9Adrian Roos        setContentDescription(mDigitText.getText().toString());
11869bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler    }
11969bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler
1200cbbc5766fb7c56c49ec55eece905fa7764a8b2balanv    @Override
1210cbbc5766fb7c56c49ec55eece905fa7764a8b2balanv    public void onDetachedFromWindow() {
1220cbbc5766fb7c56c49ec55eece905fa7764a8b2balanv        super.onDetachedFromWindow();
1230cbbc5766fb7c56c49ec55eece905fa7764a8b2balanv
1240cbbc5766fb7c56c49ec55eece905fa7764a8b2balanv        // Reset the "announced headset" flag when detached.
1250cbbc5766fb7c56c49ec55eece905fa7764a8b2balanv        ObscureSpeechDelegate.sAnnouncedHeadset = false;
1260cbbc5766fb7c56c49ec55eece905fa7764a8b2balanv    }
1270cbbc5766fb7c56c49ec55eece905fa7764a8b2balanv
1284e8b9ed30b67e5449d987e674b2966dc7f3ac224Selim Cinek    @Override
1294e8b9ed30b67e5449d987e674b2966dc7f3ac224Selim Cinek    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
1304e8b9ed30b67e5449d987e674b2966dc7f3ac224Selim Cinek        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
1314e8b9ed30b67e5449d987e674b2966dc7f3ac224Selim Cinek        measureChildren(widthMeasureSpec, heightMeasureSpec);
13269bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler    }
13369bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler
1344e8b9ed30b67e5449d987e674b2966dc7f3ac224Selim Cinek    @Override
1354e8b9ed30b67e5449d987e674b2966dc7f3ac224Selim Cinek    protected void onLayout(boolean changed, int l, int t, int r, int b) {
1364e8b9ed30b67e5449d987e674b2966dc7f3ac224Selim Cinek        int digitHeight = mDigitText.getMeasuredHeight();
1374e8b9ed30b67e5449d987e674b2966dc7f3ac224Selim Cinek        int klondikeHeight = mKlondikeText.getMeasuredHeight();
1384e8b9ed30b67e5449d987e674b2966dc7f3ac224Selim Cinek        int totalHeight = digitHeight + klondikeHeight;
1394e8b9ed30b67e5449d987e674b2966dc7f3ac224Selim Cinek        int top = getHeight() / 2 - totalHeight / 2;
1404e8b9ed30b67e5449d987e674b2966dc7f3ac224Selim Cinek        int centerX = getWidth() / 2;
1414e8b9ed30b67e5449d987e674b2966dc7f3ac224Selim Cinek        int left = centerX - mDigitText.getMeasuredWidth() / 2;
1424e8b9ed30b67e5449d987e674b2966dc7f3ac224Selim Cinek        int bottom = top + digitHeight;
1434e8b9ed30b67e5449d987e674b2966dc7f3ac224Selim Cinek        mDigitText.layout(left, top, left + mDigitText.getMeasuredWidth(), bottom);
1444e8b9ed30b67e5449d987e674b2966dc7f3ac224Selim Cinek        top = (int) (bottom - klondikeHeight * 0.35f);
1454e8b9ed30b67e5449d987e674b2966dc7f3ac224Selim Cinek        bottom = top + klondikeHeight;
1464e8b9ed30b67e5449d987e674b2966dc7f3ac224Selim Cinek
1474e8b9ed30b67e5449d987e674b2966dc7f3ac224Selim Cinek        left = centerX - mKlondikeText.getMeasuredWidth() / 2;
1484e8b9ed30b67e5449d987e674b2966dc7f3ac224Selim Cinek        mKlondikeText.layout(left, top, left + mKlondikeText.getMeasuredWidth(), bottom);
14969bdee7c873c4a2295651efda2d0e79c515acc17Daniel Sandler    }
150acb60fb57783b517e52fa60b1fa5f977141180c1Daniel Sandler
1516380482d081e557164393417370e0c5da22a5bdaSelim Cinek    @Override
1526380482d081e557164393417370e0c5da22a5bdaSelim Cinek    public boolean hasOverlappingRendering() {
1536380482d081e557164393417370e0c5da22a5bdaSelim Cinek        return false;
1546380482d081e557164393417370e0c5da22a5bdaSelim Cinek    }
1556380482d081e557164393417370e0c5da22a5bdaSelim Cinek
156acb60fb57783b517e52fa60b1fa5f977141180c1Daniel Sandler    // Cause a VIRTUAL_KEY vibration
157acb60fb57783b517e52fa60b1fa5f977141180c1Daniel Sandler    public void doHapticKeyClick() {
158acb60fb57783b517e52fa60b1fa5f977141180c1Daniel Sandler        if (mEnableHaptics) {
159acb60fb57783b517e52fa60b1fa5f977141180c1Daniel Sandler            performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY,
160acb60fb57783b517e52fa60b1fa5f977141180c1Daniel Sandler                    HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING
161acb60fb57783b517e52fa60b1fa5f977141180c1Daniel Sandler                    | HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING);
162acb60fb57783b517e52fa60b1fa5f977141180c1Daniel Sandler        }
163acb60fb57783b517e52fa60b1fa5f977141180c1Daniel Sandler    }
164d5692742c1ff056e9fe55a495632229c86ed5384Daniel Sandler}
165