DialpadFragment.java revision 2c083a837265238b14580b20c4c327122b11a431
15b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen/*
25b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen * Copyright (C) 2013 The Android Open Source Project
35b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen *
45b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen * Licensed under the Apache License, Version 2.0 (the "License");
55b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen * you may not use this file except in compliance with the License.
65b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen * You may obtain a copy of the License at
75b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen *
85b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen *      http://www.apache.org/licenses/LICENSE-2.0
95b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen *
105b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen * Unless required by applicable law or agreed to in writing, software
115b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen * distributed under the License is distributed on an "AS IS" BASIS,
125b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
135b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen * See the License for the specific language governing permissions and
145b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen * limitations under the License
155b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen */
165b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen
175b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chenpackage com.android.incallui;
185b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen
195b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chenimport android.content.Context;
205b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chenimport android.os.Bundle;
212c083a837265238b14580b20c4c327122b11a431Christine Chenimport android.text.Editable;
222c083a837265238b14580b20c4c327122b11a431Christine Chenimport android.text.method.DialerKeyListener;
235b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chenimport android.view.KeyEvent;
245b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chenimport android.view.LayoutInflater;
255b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chenimport android.view.MotionEvent;
265b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chenimport android.view.View;
275b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chenimport android.view.ViewGroup;
285b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chenimport android.view.accessibility.AccessibilityManager;
295b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chenimport android.widget.EditText;
305b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen
315b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chenimport java.util.HashMap;
325b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen
335b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen/**
345b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen * Fragment for call control buttons
355b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen */
361fa0782281ef7774ddcdfdf8efb7d8f65cf589e7Chiao Chengpublic class DialpadFragment extends BaseFragment<DialpadPresenter, DialpadPresenter.DialpadUi>
375b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen        implements DialpadPresenter.DialpadUi, View.OnTouchListener, View.OnKeyListener,
385b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen        View.OnHoverListener, View.OnClickListener {
395b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen
405b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen    private EditText mDtmfDialerField;
415b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen
425b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen    /** Hash Map to map a view id to a character*/
435b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen    private static final HashMap<Integer, Character> mDisplayMap =
445b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen        new HashMap<Integer, Character>();
455b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen
465b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen    /** Set up the static maps*/
475b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen    static {
485b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen        // Map the buttons to the display characters
495b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen        mDisplayMap.put(R.id.one, '1');
505b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen        mDisplayMap.put(R.id.two, '2');
515b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen        mDisplayMap.put(R.id.three, '3');
525b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen        mDisplayMap.put(R.id.four, '4');
535b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen        mDisplayMap.put(R.id.five, '5');
545b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen        mDisplayMap.put(R.id.six, '6');
555b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen        mDisplayMap.put(R.id.seven, '7');
565b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen        mDisplayMap.put(R.id.eight, '8');
575b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen        mDisplayMap.put(R.id.nine, '9');
585b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen        mDisplayMap.put(R.id.zero, '0');
595b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen        mDisplayMap.put(R.id.pound, '#');
605b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen        mDisplayMap.put(R.id.star, '*');
615b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen    }
625b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen
632c083a837265238b14580b20c4c327122b11a431Christine Chen    // KeyListener used with the "dialpad digits" EditText widget.
642c083a837265238b14580b20c4c327122b11a431Christine Chen    private DTMFKeyListener mDialerKeyListener;
652c083a837265238b14580b20c4c327122b11a431Christine Chen
662c083a837265238b14580b20c4c327122b11a431Christine Chen    /**
672c083a837265238b14580b20c4c327122b11a431Christine Chen     * Our own key listener, specialized for dealing with DTMF codes.
682c083a837265238b14580b20c4c327122b11a431Christine Chen     *   1. Ignore the backspace since it is irrelevant.
692c083a837265238b14580b20c4c327122b11a431Christine Chen     *   2. Allow ONLY valid DTMF characters to generate a tone and be
702c083a837265238b14580b20c4c327122b11a431Christine Chen     *      sent as a DTMF code.
712c083a837265238b14580b20c4c327122b11a431Christine Chen     *   3. All other remaining characters are handled by the superclass.
722c083a837265238b14580b20c4c327122b11a431Christine Chen     *
732c083a837265238b14580b20c4c327122b11a431Christine Chen     * This code is purely here to handle events from the hardware keyboard
742c083a837265238b14580b20c4c327122b11a431Christine Chen     * while the DTMF dialpad is up.
752c083a837265238b14580b20c4c327122b11a431Christine Chen     */
762c083a837265238b14580b20c4c327122b11a431Christine Chen    private class DTMFKeyListener extends DialerKeyListener {
772c083a837265238b14580b20c4c327122b11a431Christine Chen
782c083a837265238b14580b20c4c327122b11a431Christine Chen        private DTMFKeyListener() {
792c083a837265238b14580b20c4c327122b11a431Christine Chen            super();
802c083a837265238b14580b20c4c327122b11a431Christine Chen        }
812c083a837265238b14580b20c4c327122b11a431Christine Chen
822c083a837265238b14580b20c4c327122b11a431Christine Chen        /**
832c083a837265238b14580b20c4c327122b11a431Christine Chen         * Overriden to return correct DTMF-dialable characters.
842c083a837265238b14580b20c4c327122b11a431Christine Chen         */
852c083a837265238b14580b20c4c327122b11a431Christine Chen        @Override
862c083a837265238b14580b20c4c327122b11a431Christine Chen        protected char[] getAcceptedChars(){
872c083a837265238b14580b20c4c327122b11a431Christine Chen            return DTMF_CHARACTERS;
882c083a837265238b14580b20c4c327122b11a431Christine Chen        }
892c083a837265238b14580b20c4c327122b11a431Christine Chen
902c083a837265238b14580b20c4c327122b11a431Christine Chen        /** special key listener ignores backspace. */
912c083a837265238b14580b20c4c327122b11a431Christine Chen        @Override
922c083a837265238b14580b20c4c327122b11a431Christine Chen        public boolean backspace(View view, Editable content, int keyCode,
932c083a837265238b14580b20c4c327122b11a431Christine Chen                KeyEvent event) {
942c083a837265238b14580b20c4c327122b11a431Christine Chen            return false;
952c083a837265238b14580b20c4c327122b11a431Christine Chen        }
962c083a837265238b14580b20c4c327122b11a431Christine Chen
972c083a837265238b14580b20c4c327122b11a431Christine Chen        /**
982c083a837265238b14580b20c4c327122b11a431Christine Chen         * Return true if the keyCode is an accepted modifier key for the
992c083a837265238b14580b20c4c327122b11a431Christine Chen         * dialer (ALT or SHIFT).
1002c083a837265238b14580b20c4c327122b11a431Christine Chen         */
1012c083a837265238b14580b20c4c327122b11a431Christine Chen        private boolean isAcceptableModifierKey(int keyCode) {
1022c083a837265238b14580b20c4c327122b11a431Christine Chen            switch (keyCode) {
1032c083a837265238b14580b20c4c327122b11a431Christine Chen                case KeyEvent.KEYCODE_ALT_LEFT:
1042c083a837265238b14580b20c4c327122b11a431Christine Chen                case KeyEvent.KEYCODE_ALT_RIGHT:
1052c083a837265238b14580b20c4c327122b11a431Christine Chen                case KeyEvent.KEYCODE_SHIFT_LEFT:
1062c083a837265238b14580b20c4c327122b11a431Christine Chen                case KeyEvent.KEYCODE_SHIFT_RIGHT:
1072c083a837265238b14580b20c4c327122b11a431Christine Chen                    return true;
1082c083a837265238b14580b20c4c327122b11a431Christine Chen                default:
1092c083a837265238b14580b20c4c327122b11a431Christine Chen                    return false;
1102c083a837265238b14580b20c4c327122b11a431Christine Chen            }
1112c083a837265238b14580b20c4c327122b11a431Christine Chen        }
1122c083a837265238b14580b20c4c327122b11a431Christine Chen
1132c083a837265238b14580b20c4c327122b11a431Christine Chen        /**
1142c083a837265238b14580b20c4c327122b11a431Christine Chen         * Overriden so that with each valid button press, we start sending
1152c083a837265238b14580b20c4c327122b11a431Christine Chen         * a dtmf code and play a local dtmf tone.
1162c083a837265238b14580b20c4c327122b11a431Christine Chen         */
1172c083a837265238b14580b20c4c327122b11a431Christine Chen        @Override
1182c083a837265238b14580b20c4c327122b11a431Christine Chen        public boolean onKeyDown(View view, Editable content,
1192c083a837265238b14580b20c4c327122b11a431Christine Chen                                 int keyCode, KeyEvent event) {
1202c083a837265238b14580b20c4c327122b11a431Christine Chen            // if (DBG) log("DTMFKeyListener.onKeyDown, keyCode " + keyCode + ", view " + view);
1212c083a837265238b14580b20c4c327122b11a431Christine Chen
1222c083a837265238b14580b20c4c327122b11a431Christine Chen            // find the character
1232c083a837265238b14580b20c4c327122b11a431Christine Chen            char c = (char) lookup(event, content);
1242c083a837265238b14580b20c4c327122b11a431Christine Chen
1252c083a837265238b14580b20c4c327122b11a431Christine Chen            // if not a long press, and parent onKeyDown accepts the input
1262c083a837265238b14580b20c4c327122b11a431Christine Chen            if (event.getRepeatCount() == 0 && super.onKeyDown(view, content, keyCode, event)) {
1272c083a837265238b14580b20c4c327122b11a431Christine Chen
1282c083a837265238b14580b20c4c327122b11a431Christine Chen                boolean keyOK = ok(getAcceptedChars(), c);
1292c083a837265238b14580b20c4c327122b11a431Christine Chen
1302c083a837265238b14580b20c4c327122b11a431Christine Chen                // if the character is a valid dtmf code, start playing the tone and send the
1312c083a837265238b14580b20c4c327122b11a431Christine Chen                // code.
1322c083a837265238b14580b20c4c327122b11a431Christine Chen                if (keyOK) {
1332c083a837265238b14580b20c4c327122b11a431Christine Chen                    Log.d(this, "DTMFKeyListener reading '" + c + "' from input.");
1342c083a837265238b14580b20c4c327122b11a431Christine Chen                    getPresenter().processDtmf(c);
1352c083a837265238b14580b20c4c327122b11a431Christine Chen                } else {
1362c083a837265238b14580b20c4c327122b11a431Christine Chen                    Log.d(this, "DTMFKeyListener rejecting '" + c + "' from input.");
1372c083a837265238b14580b20c4c327122b11a431Christine Chen                }
1382c083a837265238b14580b20c4c327122b11a431Christine Chen                return true;
1392c083a837265238b14580b20c4c327122b11a431Christine Chen            }
1402c083a837265238b14580b20c4c327122b11a431Christine Chen            return false;
1412c083a837265238b14580b20c4c327122b11a431Christine Chen        }
1422c083a837265238b14580b20c4c327122b11a431Christine Chen
1432c083a837265238b14580b20c4c327122b11a431Christine Chen        /**
1442c083a837265238b14580b20c4c327122b11a431Christine Chen         * Overriden so that with each valid button up, we stop sending
1452c083a837265238b14580b20c4c327122b11a431Christine Chen         * a dtmf code and the dtmf tone.
1462c083a837265238b14580b20c4c327122b11a431Christine Chen         */
1472c083a837265238b14580b20c4c327122b11a431Christine Chen        @Override
1482c083a837265238b14580b20c4c327122b11a431Christine Chen        public boolean onKeyUp(View view, Editable content,
1492c083a837265238b14580b20c4c327122b11a431Christine Chen                                 int keyCode, KeyEvent event) {
1502c083a837265238b14580b20c4c327122b11a431Christine Chen            // if (DBG) log("DTMFKeyListener.onKeyUp, keyCode " + keyCode + ", view " + view);
1512c083a837265238b14580b20c4c327122b11a431Christine Chen
1522c083a837265238b14580b20c4c327122b11a431Christine Chen            super.onKeyUp(view, content, keyCode, event);
1532c083a837265238b14580b20c4c327122b11a431Christine Chen
1542c083a837265238b14580b20c4c327122b11a431Christine Chen            // find the character
1552c083a837265238b14580b20c4c327122b11a431Christine Chen            char c = (char) lookup(event, content);
1562c083a837265238b14580b20c4c327122b11a431Christine Chen
1572c083a837265238b14580b20c4c327122b11a431Christine Chen            boolean keyOK = ok(getAcceptedChars(), c);
1582c083a837265238b14580b20c4c327122b11a431Christine Chen
1592c083a837265238b14580b20c4c327122b11a431Christine Chen            if (keyOK) {
1602c083a837265238b14580b20c4c327122b11a431Christine Chen                Log.d(this, "Stopping the tone for '" + c + "'");
1612c083a837265238b14580b20c4c327122b11a431Christine Chen                getPresenter().stopTone();
1622c083a837265238b14580b20c4c327122b11a431Christine Chen                return true;
1632c083a837265238b14580b20c4c327122b11a431Christine Chen            }
1642c083a837265238b14580b20c4c327122b11a431Christine Chen
1652c083a837265238b14580b20c4c327122b11a431Christine Chen            return false;
1662c083a837265238b14580b20c4c327122b11a431Christine Chen        }
1672c083a837265238b14580b20c4c327122b11a431Christine Chen
1682c083a837265238b14580b20c4c327122b11a431Christine Chen        /**
1692c083a837265238b14580b20c4c327122b11a431Christine Chen         * Handle individual keydown events when we DO NOT have an Editable handy.
1702c083a837265238b14580b20c4c327122b11a431Christine Chen         */
1712c083a837265238b14580b20c4c327122b11a431Christine Chen        public boolean onKeyDown(KeyEvent event) {
1722c083a837265238b14580b20c4c327122b11a431Christine Chen            char c = lookup(event);
1732c083a837265238b14580b20c4c327122b11a431Christine Chen            Log.d(this, "DTMFKeyListener.onKeyDown: event '" + c + "'");
1742c083a837265238b14580b20c4c327122b11a431Christine Chen
1752c083a837265238b14580b20c4c327122b11a431Christine Chen            // if not a long press, and parent onKeyDown accepts the input
1762c083a837265238b14580b20c4c327122b11a431Christine Chen            if (event.getRepeatCount() == 0 && c != 0) {
1772c083a837265238b14580b20c4c327122b11a431Christine Chen                // if the character is a valid dtmf code, start playing the tone and send the
1782c083a837265238b14580b20c4c327122b11a431Christine Chen                // code.
1792c083a837265238b14580b20c4c327122b11a431Christine Chen                if (ok(getAcceptedChars(), c)) {
1802c083a837265238b14580b20c4c327122b11a431Christine Chen                    Log.d(this, "DTMFKeyListener reading '" + c + "' from input.");
1812c083a837265238b14580b20c4c327122b11a431Christine Chen                    getPresenter().processDtmf(c);
1822c083a837265238b14580b20c4c327122b11a431Christine Chen                    return true;
1832c083a837265238b14580b20c4c327122b11a431Christine Chen                } else {
1842c083a837265238b14580b20c4c327122b11a431Christine Chen                    Log.d(this, "DTMFKeyListener rejecting '" + c + "' from input.");
1852c083a837265238b14580b20c4c327122b11a431Christine Chen                }
1862c083a837265238b14580b20c4c327122b11a431Christine Chen            }
1872c083a837265238b14580b20c4c327122b11a431Christine Chen            return false;
1882c083a837265238b14580b20c4c327122b11a431Christine Chen        }
1892c083a837265238b14580b20c4c327122b11a431Christine Chen
1902c083a837265238b14580b20c4c327122b11a431Christine Chen        /**
1912c083a837265238b14580b20c4c327122b11a431Christine Chen         * Handle individual keyup events.
1922c083a837265238b14580b20c4c327122b11a431Christine Chen         *
1932c083a837265238b14580b20c4c327122b11a431Christine Chen         * @param event is the event we are trying to stop.  If this is null,
1942c083a837265238b14580b20c4c327122b11a431Christine Chen         * then we just force-stop the last tone without checking if the event
1952c083a837265238b14580b20c4c327122b11a431Christine Chen         * is an acceptable dialer event.
1962c083a837265238b14580b20c4c327122b11a431Christine Chen         */
1972c083a837265238b14580b20c4c327122b11a431Christine Chen        public boolean onKeyUp(KeyEvent event) {
1982c083a837265238b14580b20c4c327122b11a431Christine Chen            if (event == null) {
1992c083a837265238b14580b20c4c327122b11a431Christine Chen                //the below piece of code sends stopDTMF event unnecessarily even when a null event
2002c083a837265238b14580b20c4c327122b11a431Christine Chen                //is received, hence commenting it.
2012c083a837265238b14580b20c4c327122b11a431Christine Chen                /*if (DBG) log("Stopping the last played tone.");
2022c083a837265238b14580b20c4c327122b11a431Christine Chen                stopTone();*/
2032c083a837265238b14580b20c4c327122b11a431Christine Chen                return true;
2042c083a837265238b14580b20c4c327122b11a431Christine Chen            }
2052c083a837265238b14580b20c4c327122b11a431Christine Chen
2062c083a837265238b14580b20c4c327122b11a431Christine Chen            char c = lookup(event);
2072c083a837265238b14580b20c4c327122b11a431Christine Chen            Log.d(this, "DTMFKeyListener.onKeyUp: event '" + c + "'");
2082c083a837265238b14580b20c4c327122b11a431Christine Chen
2092c083a837265238b14580b20c4c327122b11a431Christine Chen            // TODO: stopTone does not take in character input, we may want to
2102c083a837265238b14580b20c4c327122b11a431Christine Chen            // consider checking for this ourselves.
2112c083a837265238b14580b20c4c327122b11a431Christine Chen            if (ok(getAcceptedChars(), c)) {
2122c083a837265238b14580b20c4c327122b11a431Christine Chen                Log.d(this, "Stopping the tone for '" + c + "'");
2132c083a837265238b14580b20c4c327122b11a431Christine Chen                getPresenter().stopTone();
2142c083a837265238b14580b20c4c327122b11a431Christine Chen                return true;
2152c083a837265238b14580b20c4c327122b11a431Christine Chen            }
2162c083a837265238b14580b20c4c327122b11a431Christine Chen
2172c083a837265238b14580b20c4c327122b11a431Christine Chen            return false;
2182c083a837265238b14580b20c4c327122b11a431Christine Chen        }
2192c083a837265238b14580b20c4c327122b11a431Christine Chen
2202c083a837265238b14580b20c4c327122b11a431Christine Chen        /**
2212c083a837265238b14580b20c4c327122b11a431Christine Chen         * Find the Dialer Key mapped to this event.
2222c083a837265238b14580b20c4c327122b11a431Christine Chen         *
2232c083a837265238b14580b20c4c327122b11a431Christine Chen         * @return The char value of the input event, otherwise
2242c083a837265238b14580b20c4c327122b11a431Christine Chen         * 0 if no matching character was found.
2252c083a837265238b14580b20c4c327122b11a431Christine Chen         */
2262c083a837265238b14580b20c4c327122b11a431Christine Chen        private char lookup(KeyEvent event) {
2272c083a837265238b14580b20c4c327122b11a431Christine Chen            // This code is similar to {@link DialerKeyListener#lookup(KeyEvent, Spannable) lookup}
2282c083a837265238b14580b20c4c327122b11a431Christine Chen            int meta = event.getMetaState();
2292c083a837265238b14580b20c4c327122b11a431Christine Chen            int number = event.getNumber();
2302c083a837265238b14580b20c4c327122b11a431Christine Chen
2312c083a837265238b14580b20c4c327122b11a431Christine Chen            if (!((meta & (KeyEvent.META_ALT_ON | KeyEvent.META_SHIFT_ON)) == 0) || (number == 0)) {
2322c083a837265238b14580b20c4c327122b11a431Christine Chen                int match = event.getMatch(getAcceptedChars(), meta);
2332c083a837265238b14580b20c4c327122b11a431Christine Chen                number = (match != 0) ? match : number;
2342c083a837265238b14580b20c4c327122b11a431Christine Chen            }
2352c083a837265238b14580b20c4c327122b11a431Christine Chen
2362c083a837265238b14580b20c4c327122b11a431Christine Chen            return (char) number;
2372c083a837265238b14580b20c4c327122b11a431Christine Chen        }
2382c083a837265238b14580b20c4c327122b11a431Christine Chen
2392c083a837265238b14580b20c4c327122b11a431Christine Chen        /**
2402c083a837265238b14580b20c4c327122b11a431Christine Chen         * Check to see if the keyEvent is dialable.
2412c083a837265238b14580b20c4c327122b11a431Christine Chen         */
2422c083a837265238b14580b20c4c327122b11a431Christine Chen        boolean isKeyEventAcceptable (KeyEvent event) {
2432c083a837265238b14580b20c4c327122b11a431Christine Chen            return (ok(getAcceptedChars(), lookup(event)));
2442c083a837265238b14580b20c4c327122b11a431Christine Chen        }
2452c083a837265238b14580b20c4c327122b11a431Christine Chen
2462c083a837265238b14580b20c4c327122b11a431Christine Chen        /**
2472c083a837265238b14580b20c4c327122b11a431Christine Chen         * Overrides the characters used in {@link DialerKeyListener#CHARACTERS}
2482c083a837265238b14580b20c4c327122b11a431Christine Chen         * These are the valid dtmf characters.
2492c083a837265238b14580b20c4c327122b11a431Christine Chen         */
2502c083a837265238b14580b20c4c327122b11a431Christine Chen        public final char[] DTMF_CHARACTERS = new char[] {
2512c083a837265238b14580b20c4c327122b11a431Christine Chen            '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '#', '*'
2522c083a837265238b14580b20c4c327122b11a431Christine Chen        };
2532c083a837265238b14580b20c4c327122b11a431Christine Chen    }
2542c083a837265238b14580b20c4c327122b11a431Christine Chen
2555b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen    @Override
2565b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen    public void onClick(View v) {
2571a7f2bcab2d2023f2ee4cfb0bc57bc265b5aab87Chiao Cheng        Log.d(this, "onClick");
2585b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen        final AccessibilityManager accessibilityManager = (AccessibilityManager)
2595b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen            getActivity().getSystemService(Context.ACCESSIBILITY_SERVICE);
2605b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen        // When accessibility is on, simulate press and release to preserve the
2615b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen        // semantic meaning of performClick(). Required for Braille support.
2625b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen        if (accessibilityManager.isEnabled()) {
2635b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen            final int id = v.getId();
2645b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen            // Checking the press state prevents double activation.
2655b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen            if (!v.isPressed() && mDisplayMap.containsKey(id)) {
2665b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen                getPresenter().processDtmf(mDisplayMap.get(id), true /* timedShortTone */);
2675b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen            }
2685b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen        }
2695b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen    }
2705b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen
2715b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen    @Override
2725b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen    public boolean onHover(View v, MotionEvent event) {
2735b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen        // When touch exploration is turned on, lifting a finger while inside
2745b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen        // the button's hover target bounds should perform a click action.
2755b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen        final AccessibilityManager accessibilityManager = (AccessibilityManager)
2765b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen            getActivity().getSystemService(Context.ACCESSIBILITY_SERVICE);
2775b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen
2785b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen        if (accessibilityManager.isEnabled()
2795b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen                && accessibilityManager.isTouchExplorationEnabled()) {
2805b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen            final int left = v.getPaddingLeft();
2815b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen            final int right = (v.getWidth() - v.getPaddingRight());
2825b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen            final int top = v.getPaddingTop();
2835b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen            final int bottom = (v.getHeight() - v.getPaddingBottom());
2845b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen
2855b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen            switch (event.getActionMasked()) {
2865b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen                case MotionEvent.ACTION_HOVER_ENTER:
2875b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen                    // Lift-to-type temporarily disables double-tap activation.
2885b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen                    v.setClickable(false);
2895b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen                    break;
2905b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen                case MotionEvent.ACTION_HOVER_EXIT:
2915b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen                    final int x = (int) event.getX();
2925b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen                    final int y = (int) event.getY();
2935b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen                    if ((x > left) && (x < right) && (y > top) && (y < bottom)) {
2945b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen                        v.performClick();
2955b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen                    }
2965b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen                    v.setClickable(true);
2975b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen                    break;
2985b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen            }
2995b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen        }
3005b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen
3015b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen        return false;
3025b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen    }
3035b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen
3045b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen    @Override
3055b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen    public boolean onKey(View v, int keyCode, KeyEvent event) {
3061a7f2bcab2d2023f2ee4cfb0bc57bc265b5aab87Chiao Cheng        Log.d(this, "onKey:  keyCode " + keyCode + ", view " + v);
3075b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen
3085b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen        if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER) {
3095b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen            int viewId = v.getId();
3105b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen            if (mDisplayMap.containsKey(viewId)) {
3115b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen                switch (event.getAction()) {
3125b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen                case KeyEvent.ACTION_DOWN:
3135b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen                    if (event.getRepeatCount() == 0) {
3145b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen                        getPresenter().processDtmf(mDisplayMap.get(viewId));
3155b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen                    }
3165b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen                    break;
3175b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen                case KeyEvent.ACTION_UP:
3185b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen                    getPresenter().stopTone();
3195b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen                    break;
3205b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen                }
3215b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen                // do not return true [handled] here, since we want the
3225b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen                // press / click animation to be handled by the framework.
3235b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen            }
3245b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen        }
3255b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen        return false;
3265b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen    }
3275b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen
3285b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen    @Override
3295b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen    public boolean onTouch(View v, MotionEvent event) {
3301a7f2bcab2d2023f2ee4cfb0bc57bc265b5aab87Chiao Cheng        Log.d(this, "onTouch");
3315b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen        int viewId = v.getId();
3325b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen
3335b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen        // if the button is recognized
3345b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen        if (mDisplayMap.containsKey(viewId)) {
3355b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen            switch (event.getAction()) {
3365b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen                case MotionEvent.ACTION_DOWN:
3375b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen                    // Append the character mapped to this button, to the display.
3385b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen                    // start the tone
3395b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen                    getPresenter().processDtmf(mDisplayMap.get(viewId));
3405b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen                    break;
3415b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen                case MotionEvent.ACTION_UP:
3425b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen                case MotionEvent.ACTION_CANCEL:
3435b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen                    // stop the tone on ANY other event, except for MOVE.
3445b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen                    getPresenter().stopTone();
3455b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen                    break;
3465b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen            }
3475b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen            // do not return true [handled] here, since we want the
3485b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen            // press / click animation to be handled by the framework.
3495b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen        }
3505b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen        return false;
3515b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen    }
3525b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen
3535b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen    // TODO(klp) Adds hardware keyboard listener
3545b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen
3555b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen    @Override
3565b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen    DialpadPresenter createPresenter() {
3575b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen        return new DialpadPresenter();
3585b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen    }
3595b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen
3605b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen    @Override
3611fa0782281ef7774ddcdfdf8efb7d8f65cf589e7Chiao Cheng    DialpadPresenter.DialpadUi getUi() {
3621fa0782281ef7774ddcdfdf8efb7d8f65cf589e7Chiao Cheng        return this;
3631fa0782281ef7774ddcdfdf8efb7d8f65cf589e7Chiao Cheng    }
3641fa0782281ef7774ddcdfdf8efb7d8f65cf589e7Chiao Cheng
3651fa0782281ef7774ddcdfdf8efb7d8f65cf589e7Chiao Cheng    @Override
3665b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen    public void onCreate(Bundle savedInstanceState) {
3675b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen        super.onCreate(savedInstanceState);
3685b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen    }
3695b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen
3705b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen    @Override
3715b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen    public View onCreateView(LayoutInflater inflater, ViewGroup container,
3725b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen            Bundle savedInstanceState) {
3735b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen        final View parent = inflater.inflate(
3745b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen                com.android.incallui.R.layout.dtmf_twelve_key_dialer_view, container, false);
3755b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen        mDtmfDialerField = (EditText) parent.findViewById(R.id.dtmfDialerField);
3765b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen        if (mDtmfDialerField != null) {
3772c083a837265238b14580b20c4c327122b11a431Christine Chen            mDialerKeyListener = new DTMFKeyListener();
3782c083a837265238b14580b20c4c327122b11a431Christine Chen            mDtmfDialerField.setKeyListener(mDialerKeyListener);
3795b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen            // remove the long-press context menus that support
3805b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen            // the edit (copy / paste / select) functions.
3815b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen            mDtmfDialerField.setLongClickable(false);
3825b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen
3835b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen            setupKeypad(parent);
3845b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen        }
3855b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen        return parent;
3865b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen    }
3875b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen
3885b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen    @Override
3892c083a837265238b14580b20c4c327122b11a431Christine Chen    public void onDestroyView() {
3902c083a837265238b14580b20c4c327122b11a431Christine Chen        mDialerKeyListener = null;
3912c083a837265238b14580b20c4c327122b11a431Christine Chen        super.onDestroyView();
3922c083a837265238b14580b20c4c327122b11a431Christine Chen    }
3932c083a837265238b14580b20c4c327122b11a431Christine Chen
3942c083a837265238b14580b20c4c327122b11a431Christine Chen    @Override
3955b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen    public void setVisible(boolean on) {
3965b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen        if (on) {
3975b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen            getView().setVisibility(View.VISIBLE);
3985b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen        } else {
3995b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen            getView().setVisibility(View.INVISIBLE);
4005b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen        }
4015b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen    }
4025b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen
4035b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen    @Override
4045b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen    public void appendDigitsToField(char digit) {
4055b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen        if (mDtmfDialerField != null) {
4065b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen            // TODO: maybe *don't* manually append this digit if
4075b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen            // mDialpadDigits is focused and this key came from the HW
4085b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen            // keyboard, since in that case the EditText field will
4095b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen            // get the key event directly and automatically appends
4105b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen            // whetever the user types.
4115b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen            // (Or, a cleaner fix would be to just make mDialpadDigits
4125b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen            // *not* handle HW key presses.  That seems to be more
4135b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen            // complicated than just setting focusable="false" on it,
4145b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen            // though.)
4155b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen            mDtmfDialerField.getText().append(digit);
4165b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen        }
4175b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen    }
4185b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen
4195b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen    /**
4202c083a837265238b14580b20c4c327122b11a431Christine Chen     * Called externally (from InCallScreen) to play a DTMF Tone.
4212c083a837265238b14580b20c4c327122b11a431Christine Chen     */
4222c083a837265238b14580b20c4c327122b11a431Christine Chen    /* package */ boolean onDialerKeyDown(KeyEvent event) {
4232c083a837265238b14580b20c4c327122b11a431Christine Chen        Log.d(this, "Notifying dtmf key down.");
4242c083a837265238b14580b20c4c327122b11a431Christine Chen        if (mDialerKeyListener != null) {
4252c083a837265238b14580b20c4c327122b11a431Christine Chen            return mDialerKeyListener.onKeyDown(event);
4262c083a837265238b14580b20c4c327122b11a431Christine Chen        } else {
4272c083a837265238b14580b20c4c327122b11a431Christine Chen            return false;
4282c083a837265238b14580b20c4c327122b11a431Christine Chen        }
4292c083a837265238b14580b20c4c327122b11a431Christine Chen    }
4302c083a837265238b14580b20c4c327122b11a431Christine Chen
4312c083a837265238b14580b20c4c327122b11a431Christine Chen    /**
4322c083a837265238b14580b20c4c327122b11a431Christine Chen     * Called externally (from InCallScreen) to cancel the last DTMF Tone played.
4332c083a837265238b14580b20c4c327122b11a431Christine Chen     */
4342c083a837265238b14580b20c4c327122b11a431Christine Chen    public boolean onDialerKeyUp(KeyEvent event) {
4352c083a837265238b14580b20c4c327122b11a431Christine Chen        Log.d(this, "Notifying dtmf key up.");
4362c083a837265238b14580b20c4c327122b11a431Christine Chen        if (mDialerKeyListener != null) {
4372c083a837265238b14580b20c4c327122b11a431Christine Chen            return mDialerKeyListener.onKeyUp(event);
4382c083a837265238b14580b20c4c327122b11a431Christine Chen        } else {
4392c083a837265238b14580b20c4c327122b11a431Christine Chen            return false;
4402c083a837265238b14580b20c4c327122b11a431Christine Chen        }
4412c083a837265238b14580b20c4c327122b11a431Christine Chen    }
4422c083a837265238b14580b20c4c327122b11a431Christine Chen
4432c083a837265238b14580b20c4c327122b11a431Christine Chen    /**
4445b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen     * setup the keys on the dialer activity, using the keymaps.
4455b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen     */
4465b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen    private void setupKeypad(View parent) {
4475b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen        // for each view id listed in the displaymap
4485b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen        View button;
4495b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen        for (int viewId : mDisplayMap.keySet()) {
4505b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen            // locate the view
4515b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen            button = parent.findViewById(viewId);
4525b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen            // Setup the listeners for the buttons
4535b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen            button.setOnTouchListener(this);
4545b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen            button.setClickable(true);
4555b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen            button.setOnKeyListener(this);
4565b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen            button.setOnHoverListener(this);
4575b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen            button.setOnClickListener(this);
4585b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen        }
4595b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen    }
4605b9034b5b1b48a4339dd2f893a851cc64d6279dfChristine Chen}
461