1b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project/*
2b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project * Copyright (C) 2008 The Android Open Source Project
3b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project *
4b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
5b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project * you may not use this file except in compliance with the License.
6b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project * You may obtain a copy of the License at
7b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project *
8b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
9b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project *
10b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
11b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
12b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project * See the License for the specific language governing permissions and
14b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project * limitations under the License.
15b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project */
16b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
17b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectpackage com.android.phone;
18b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
19b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.media.AudioManager;
20b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.media.ToneGenerator;
21b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.os.Handler;
22b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.os.Message;
23b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.provider.Settings;
24b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.telephony.PhoneNumberUtils;
25b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.text.Editable;
26b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.text.Spannable;
27b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.text.method.DialerKeyListener;
28b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.text.method.MovementMethod;
29b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.util.Log;
30b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.view.KeyEvent;
31b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.view.MotionEvent;
32b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.view.View;
33b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.widget.EditText;
34b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.widget.TextView;
35b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
36fa08be2879b66dc61a8e0b5a85dfdd7ef942570bHung-ying Tyanimport com.android.internal.telephony.CallManager;
37b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport com.android.internal.telephony.Phone;
38b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
39b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport java.util.HashMap;
40d533a71d64507e33d78dc65aa2521eacb5f8bb25Wink Savilleimport java.util.LinkedList;
41d533a71d64507e33d78dc65aa2521eacb5f8bb25Wink Savilleimport java.util.Queue;
42d533a71d64507e33d78dc65aa2521eacb5f8bb25Wink Saville
43b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
44b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project/**
45b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project * Dialer class that encapsulates the DTMF twelve key behaviour.
46b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project * This model backs up the UI behaviour in DTMFTwelveKeyDialerView.java.
47b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project */
484ba332e62c4d54b2623ccdc59fafd46ecba08cf0David Brownpublic class DTMFTwelveKeyDialer implements View.OnTouchListener, View.OnKeyListener {
49b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private static final String LOG_TAG = "DTMFTwelveKeyDialer";
501e8a3579f8e49fd1f1a078d6be6864a6a8bac306David Brown    private static final boolean DBG = (PhoneApp.DBG_LEVEL >= 2);
51b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
52b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    // events
53b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private static final int PHONE_DISCONNECT = 100;
54d533a71d64507e33d78dc65aa2521eacb5f8bb25Wink Saville    private static final int DTMF_SEND_CNF = 101;
55d533a71d64507e33d78dc65aa2521eacb5f8bb25Wink Saville
56fa08be2879b66dc61a8e0b5a85dfdd7ef942570bHung-ying Tyan    private CallManager mCM;
57b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private ToneGenerator mToneGenerator;
58b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private Object mToneGeneratorLock = new Object();
59b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
6051eaa15edd6953b961a502bd517bcdec59d15d13Martin Hibdon    // indicate if we want to enable the local tone playback.
6151eaa15edd6953b961a502bd517bcdec59d15d13Martin Hibdon    private boolean mLocalToneEnabled;
62b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
6351eaa15edd6953b961a502bd517bcdec59d15d13Martin Hibdon    // indicates that we are using automatically shortened DTMF tones
6451eaa15edd6953b961a502bd517bcdec59d15d13Martin Hibdon    boolean mShortTone;
65d533a71d64507e33d78dc65aa2521eacb5f8bb25Wink Saville
66d533a71d64507e33d78dc65aa2521eacb5f8bb25Wink Saville    // indicate if the confirmation from TelephonyFW is pending.
67d533a71d64507e33d78dc65aa2521eacb5f8bb25Wink Saville    private boolean mDTMFBurstCnfPending = false;
68d533a71d64507e33d78dc65aa2521eacb5f8bb25Wink Saville
69d533a71d64507e33d78dc65aa2521eacb5f8bb25Wink Saville    // Queue to queue the short dtmf characters.
70d533a71d64507e33d78dc65aa2521eacb5f8bb25Wink Saville    private Queue<Character> mDTMFQueue = new LinkedList<Character>();
71d533a71d64507e33d78dc65aa2521eacb5f8bb25Wink Saville
72d533a71d64507e33d78dc65aa2521eacb5f8bb25Wink Saville    //  Short Dtmf tone duration
73d533a71d64507e33d78dc65aa2521eacb5f8bb25Wink Saville    private static final int DTMF_DURATION_MS = 120;
74d533a71d64507e33d78dc65aa2521eacb5f8bb25Wink Saville
75d533a71d64507e33d78dc65aa2521eacb5f8bb25Wink Saville
76b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /** Hash Map to map a character to a tone*/
77b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private static final HashMap<Character, Integer> mToneMap =
78b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        new HashMap<Character, Integer>();
79b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /** Hash Map to map a view id to a character*/
80b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private static final HashMap<Integer, Character> mDisplayMap =
81b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        new HashMap<Integer, Character>();
82b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /** Set up the static maps*/
83b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    static {
84b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // Map the key characters to tones
85b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        mToneMap.put('1', ToneGenerator.TONE_DTMF_1);
86b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        mToneMap.put('2', ToneGenerator.TONE_DTMF_2);
87b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        mToneMap.put('3', ToneGenerator.TONE_DTMF_3);
88b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        mToneMap.put('4', ToneGenerator.TONE_DTMF_4);
89b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        mToneMap.put('5', ToneGenerator.TONE_DTMF_5);
90b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        mToneMap.put('6', ToneGenerator.TONE_DTMF_6);
91b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        mToneMap.put('7', ToneGenerator.TONE_DTMF_7);
92b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        mToneMap.put('8', ToneGenerator.TONE_DTMF_8);
93b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        mToneMap.put('9', ToneGenerator.TONE_DTMF_9);
94b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        mToneMap.put('0', ToneGenerator.TONE_DTMF_0);
95b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        mToneMap.put('#', ToneGenerator.TONE_DTMF_P);
96b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        mToneMap.put('*', ToneGenerator.TONE_DTMF_S);
97b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
98b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // Map the buttons to the display characters
99b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        mDisplayMap.put(R.id.one, '1');
100b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        mDisplayMap.put(R.id.two, '2');
101b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        mDisplayMap.put(R.id.three, '3');
102b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        mDisplayMap.put(R.id.four, '4');
103b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        mDisplayMap.put(R.id.five, '5');
104b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        mDisplayMap.put(R.id.six, '6');
105b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        mDisplayMap.put(R.id.seven, '7');
106b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        mDisplayMap.put(R.id.eight, '8');
107b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        mDisplayMap.put(R.id.nine, '9');
108b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        mDisplayMap.put(R.id.zero, '0');
109b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        mDisplayMap.put(R.id.pound, '#');
110b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        mDisplayMap.put(R.id.star, '*');
111b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
112b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
113b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    // EditText field used to display the DTMF digits sent so far.
114dfa83d531cdb88513f09e913424b7a16628b37d3David Brown    // Note this is null in some modes (like during the CDMA OTA call,
115dfa83d531cdb88513f09e913424b7a16628b37d3David Brown    // where there's no onscreen "digits" display.)
116b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private EditText mDialpadDigits;
117b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
118b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    // InCallScreen reference.
119b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private InCallScreen mInCallScreen;
120b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
1215aadc2633b13d6676598dc0954be25c108d05fcdDavid Brown    // The DTMFTwelveKeyDialerView we use to display the dialpad.
122b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private DTMFTwelveKeyDialerView mDialerView;
123b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
124dfa83d531cdb88513f09e913424b7a16628b37d3David Brown    // KeyListener used with the "dialpad digits" EditText widget.
125b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private DTMFKeyListener mDialerKeyListener;
126b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
127b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /**
128b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * Our own key listener, specialized for dealing with DTMF codes.
129b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     *   1. Ignore the backspace since it is irrelevant.
130b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     *   2. Allow ONLY valid DTMF characters to generate a tone and be
131b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     *      sent as a DTMF code.
132b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     *   3. All other remaining characters are handled by the superclass.
133dfa83d531cdb88513f09e913424b7a16628b37d3David Brown     *
134dfa83d531cdb88513f09e913424b7a16628b37d3David Brown     * This code is purely here to handle events from the hardware keyboard
135dfa83d531cdb88513f09e913424b7a16628b37d3David Brown     * while the DTMF dialpad is up.
136b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     */
137b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private class DTMFKeyListener extends DialerKeyListener {
138b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
139dfa83d531cdb88513f09e913424b7a16628b37d3David Brown        private DTMFKeyListener() {
140b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            super();
141b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
142b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
143b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        /**
144b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project         * Overriden to return correct DTMF-dialable characters.
145b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project         */
146b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        @Override
147b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        protected char[] getAcceptedChars(){
148b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            return DTMF_CHARACTERS;
149b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
150b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
151b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        /** special key listener ignores backspace. */
152b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        @Override
153b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        public boolean backspace(View view, Editable content, int keyCode,
154b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                KeyEvent event) {
155b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            return false;
156b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
157b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
158b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        /**
159b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project         * Return true if the keyCode is an accepted modifier key for the
160b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project         * dialer (ALT or SHIFT).
161b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project         */
162b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        private boolean isAcceptableModifierKey(int keyCode) {
163b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            switch (keyCode) {
164b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                case KeyEvent.KEYCODE_ALT_LEFT:
165b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                case KeyEvent.KEYCODE_ALT_RIGHT:
166b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                case KeyEvent.KEYCODE_SHIFT_LEFT:
167b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                case KeyEvent.KEYCODE_SHIFT_RIGHT:
168b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    return true;
169b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                default:
170b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    return false;
171b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
172b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
173b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
174b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        /**
175b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project         * Overriden so that with each valid button press, we start sending
176b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project         * a dtmf code and play a local dtmf tone.
177b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project         */
178b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        @Override
179b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        public boolean onKeyDown(View view, Editable content,
180b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                                 int keyCode, KeyEvent event) {
181b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            // if (DBG) log("DTMFKeyListener.onKeyDown, keyCode " + keyCode + ", view " + view);
182b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
183b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            // find the character
184b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            char c = (char) lookup(event, content);
185b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
186b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            // if not a long press, and parent onKeyDown accepts the input
187b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            if (event.getRepeatCount() == 0 && super.onKeyDown(view, content, keyCode, event)) {
188b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
189b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                boolean keyOK = ok(getAcceptedChars(), c);
190b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
191b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // if the character is a valid dtmf code, start playing the tone and send the
192b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // code.
193b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (keyOK) {
194b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    if (DBG) log("DTMFKeyListener reading '" + c + "' from input.");
195b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    processDtmf(c);
196b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                } else if (DBG) {
197b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    log("DTMFKeyListener rejecting '" + c + "' from input.");
198b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
199b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                return true;
200b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
201b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            return false;
202b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
203b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
204b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        /**
205b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project         * Overriden so that with each valid button up, we stop sending
206b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project         * a dtmf code and the dtmf tone.
207b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project         */
208b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        @Override
209b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        public boolean onKeyUp(View view, Editable content,
210b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                                 int keyCode, KeyEvent event) {
211b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            // if (DBG) log("DTMFKeyListener.onKeyUp, keyCode " + keyCode + ", view " + view);
212b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
213b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            super.onKeyUp(view, content, keyCode, event);
214b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
215b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            // find the character
216b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            char c = (char) lookup(event, content);
217b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
218b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            boolean keyOK = ok(getAcceptedChars(), c);
219b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
220b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            if (keyOK) {
221b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (DBG) log("Stopping the tone for '" + c + "'");
222b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                stopTone();
223b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                return true;
224b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
225b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
226b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            return false;
227b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
228b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
229b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        /**
230b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project         * Handle individual keydown events when we DO NOT have an Editable handy.
231b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project         */
232b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        public boolean onKeyDown(KeyEvent event) {
233dfa83d531cdb88513f09e913424b7a16628b37d3David Brown            char c = lookup(event);
234dfa83d531cdb88513f09e913424b7a16628b37d3David Brown            if (DBG) log("DTMFKeyListener.onKeyDown: event '" + c + "'");
235b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
236b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            // if not a long press, and parent onKeyDown accepts the input
237b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            if (event.getRepeatCount() == 0 && c != 0) {
238b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // if the character is a valid dtmf code, start playing the tone and send the
239b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // code.
240b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (ok(getAcceptedChars(), c)) {
241b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    if (DBG) log("DTMFKeyListener reading '" + c + "' from input.");
242b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    processDtmf(c);
243b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    return true;
244b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                } else if (DBG) {
245b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    log("DTMFKeyListener rejecting '" + c + "' from input.");
246b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
247b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
248b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            return false;
249b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
250b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
251b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        /**
252b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project         * Handle individual keyup events.
253b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project         *
254b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project         * @param event is the event we are trying to stop.  If this is null,
255b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project         * then we just force-stop the last tone without checking if the event
256b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project         * is an acceptable dialer event.
257b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project         */
258b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        public boolean onKeyUp(KeyEvent event) {
259b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            if (event == null) {
260404edc94de563aef5fd5ba48be9114a970cb93bbWink Saville                //the below piece of code sends stopDTMF event unnecessarily even when a null event
261404edc94de563aef5fd5ba48be9114a970cb93bbWink Saville                //is received, hence commenting it.
262404edc94de563aef5fd5ba48be9114a970cb93bbWink Saville                /*if (DBG) log("Stopping the last played tone.");
263404edc94de563aef5fd5ba48be9114a970cb93bbWink Saville                stopTone();*/
264b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                return true;
265b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
266b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
267dfa83d531cdb88513f09e913424b7a16628b37d3David Brown            char c = lookup(event);
268dfa83d531cdb88513f09e913424b7a16628b37d3David Brown            if (DBG) log("DTMFKeyListener.onKeyUp: event '" + c + "'");
269b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
270b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            // TODO: stopTone does not take in character input, we may want to
271b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            // consider checking for this ourselves.
272b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            if (ok(getAcceptedChars(), c)) {
273b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (DBG) log("Stopping the tone for '" + c + "'");
274b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                stopTone();
275b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                return true;
276b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
277b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
278b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            return false;
279b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
280b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
281b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        /**
282b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project         * Find the Dialer Key mapped to this event.
283b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project         *
284b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project         * @return The char value of the input event, otherwise
285b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project         * 0 if no matching character was found.
286b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project         */
287b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        private char lookup(KeyEvent event) {
288b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            // This code is similar to {@link DialerKeyListener#lookup(KeyEvent, Spannable) lookup}
289b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            int meta = event.getMetaState();
290b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            int number = event.getNumber();
291b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
292b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            if (!((meta & (KeyEvent.META_ALT_ON | KeyEvent.META_SHIFT_ON)) == 0) || (number == 0)) {
293b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                int match = event.getMatch(getAcceptedChars(), meta);
294b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                number = (match != 0) ? match : number;
295b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
296b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
297b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            return (char) number;
298b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
299b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
300b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        /**
301b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project         * Check to see if the keyEvent is dialable.
302b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project         */
303b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        boolean isKeyEventAcceptable (KeyEvent event) {
304b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            return (ok(getAcceptedChars(), lookup(event)));
305b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
306b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
307b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        /**
308b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project         * Overrides the characters used in {@link DialerKeyListener#CHARACTERS}
309b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project         * These are the valid dtmf characters.
310b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project         */
311b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        public final char[] DTMF_CHARACTERS = new char[] {
312b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '#', '*'
313b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        };
314b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
315b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
316b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /**
317b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * Our own handler to take care of the messages from the phone state changes
318b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     */
319b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private Handler mHandler = new Handler() {
320b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        @Override
321b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        public void handleMessage(Message msg) {
322b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            switch (msg.what) {
323b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // disconnect action
324b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // make sure to close the dialer on ALL disconnect actions.
325b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                case PHONE_DISCONNECT:
326b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    if (DBG) log("disconnect message recieved, shutting down.");
327b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    // unregister since we are closing.
328fa08be2879b66dc61a8e0b5a85dfdd7ef942570bHung-ying Tyan                    mCM.unregisterForDisconnect(this);
329b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    closeDialer(false);
330b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    break;
331d533a71d64507e33d78dc65aa2521eacb5f8bb25Wink Saville                case DTMF_SEND_CNF:
332d533a71d64507e33d78dc65aa2521eacb5f8bb25Wink Saville                    if (DBG) log("dtmf confirmation received from FW.");
333d533a71d64507e33d78dc65aa2521eacb5f8bb25Wink Saville                    // handle burst dtmf confirmation
334d533a71d64507e33d78dc65aa2521eacb5f8bb25Wink Saville                    handleBurstDtmfConfirmation();
335d533a71d64507e33d78dc65aa2521eacb5f8bb25Wink Saville                    break;
336b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
337b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
338b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    };
339b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
340dfa83d531cdb88513f09e913424b7a16628b37d3David Brown
341dfa83d531cdb88513f09e913424b7a16628b37d3David Brown    /**
342dfa83d531cdb88513f09e913424b7a16628b37d3David Brown     * DTMFTwelveKeyDialer constructor.
343dfa83d531cdb88513f09e913424b7a16628b37d3David Brown     *
344dfa83d531cdb88513f09e913424b7a16628b37d3David Brown     * @param parent the InCallScreen instance that owns us.
345dfa83d531cdb88513f09e913424b7a16628b37d3David Brown     * @param dialerView the DTMFTwelveKeyDialerView we should use to display the dialpad.
346dfa83d531cdb88513f09e913424b7a16628b37d3David Brown     */
347dfa83d531cdb88513f09e913424b7a16628b37d3David Brown    public DTMFTwelveKeyDialer(InCallScreen parent,
3484ba332e62c4d54b2623ccdc59fafd46ecba08cf0David Brown                               DTMFTwelveKeyDialerView dialerView) {
3492f22a9001166458ef4b04f6142b6d6a480af1c9dDavid Brown        if (DBG) log("DTMFTwelveKeyDialer constructor... this = " + this);
3508df5c508da2c836b841ee24120fa7c5cc92df387David Brown
351b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        mInCallScreen = parent;
352fa08be2879b66dc61a8e0b5a85dfdd7ef942570bHung-ying Tyan        mCM = PhoneApp.getInstance().mCM;
353dfa83d531cdb88513f09e913424b7a16628b37d3David Brown
354dfa83d531cdb88513f09e913424b7a16628b37d3David Brown        // The passed-in DTMFTwelveKeyDialerView *should* always be
355dfa83d531cdb88513f09e913424b7a16628b37d3David Brown        // non-null, now that the in-call UI uses only portrait mode.
356dfa83d531cdb88513f09e913424b7a16628b37d3David Brown        if (dialerView == null) {
357dfa83d531cdb88513f09e913424b7a16628b37d3David Brown            Log.e(LOG_TAG, "DTMFTwelveKeyDialer: null dialerView!", new IllegalStateException());
358dfa83d531cdb88513f09e913424b7a16628b37d3David Brown            // ...continue as best we can, although things will
359dfa83d531cdb88513f09e913424b7a16628b37d3David Brown            // be pretty broken without the mDialerView UI elements!
360dfa83d531cdb88513f09e913424b7a16628b37d3David Brown        }
361dfa83d531cdb88513f09e913424b7a16628b37d3David Brown        mDialerView = dialerView;
3628df5c508da2c836b841ee24120fa7c5cc92df387David Brown        if (DBG) log("- Got passed-in mDialerView: " + mDialerView);
3638df5c508da2c836b841ee24120fa7c5cc92df387David Brown
364dfa83d531cdb88513f09e913424b7a16628b37d3David Brown        if (mDialerView != null) {
365c8f1376d0d710a27390feb46ab810c2eae2c45f8Peng Zhu            mDialerView.setDialer(this);
366dfa83d531cdb88513f09e913424b7a16628b37d3David Brown
367dfa83d531cdb88513f09e913424b7a16628b37d3David Brown            // In the normal in-call DTMF dialpad, mDialpadDigits is an
368dfa83d531cdb88513f09e913424b7a16628b37d3David Brown            // EditText used to display the digits the user has typed so
369dfa83d531cdb88513f09e913424b7a16628b37d3David Brown            // far.  But some other modes (like the OTA call) have no
370dfa83d531cdb88513f09e913424b7a16628b37d3David Brown            // "digits" display at all, in which case mDialpadDigits will
371dfa83d531cdb88513f09e913424b7a16628b37d3David Brown            // be null.
372dfa83d531cdb88513f09e913424b7a16628b37d3David Brown            mDialpadDigits = (EditText) mDialerView.findViewById(R.id.dtmfDialerField);
373dfa83d531cdb88513f09e913424b7a16628b37d3David Brown            if (mDialpadDigits != null) {
374dfa83d531cdb88513f09e913424b7a16628b37d3David Brown                mDialerKeyListener = new DTMFKeyListener();
375dfa83d531cdb88513f09e913424b7a16628b37d3David Brown                mDialpadDigits.setKeyListener(mDialerKeyListener);
376dfa83d531cdb88513f09e913424b7a16628b37d3David Brown
377dfa83d531cdb88513f09e913424b7a16628b37d3David Brown                // remove the long-press context menus that support
378dfa83d531cdb88513f09e913424b7a16628b37d3David Brown                // the edit (copy / paste / select) functions.
379dfa83d531cdb88513f09e913424b7a16628b37d3David Brown                mDialpadDigits.setLongClickable(false);
380dfa83d531cdb88513f09e913424b7a16628b37d3David Brown            }
381dfa83d531cdb88513f09e913424b7a16628b37d3David Brown
382dfa83d531cdb88513f09e913424b7a16628b37d3David Brown            // Hook up touch / key listeners for the buttons in the onscreen
383dfa83d531cdb88513f09e913424b7a16628b37d3David Brown            // keypad.
384dfa83d531cdb88513f09e913424b7a16628b37d3David Brown            setupKeypad(mDialerView);
385c8f1376d0d710a27390feb46ab810c2eae2c45f8Peng Zhu        }
386b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
387b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
388b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /**
389b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * Null out our reference to the InCallScreen activity.
390b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * This indicates that the InCallScreen activity has been destroyed.
391b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * At the same time, get rid of listeners since we're not going to
392b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * be valid anymore.
393b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     */
394b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /* package */ void clearInCallScreenReference() {
395dfa83d531cdb88513f09e913424b7a16628b37d3David Brown        if (DBG) log("clearInCallScreenReference()...");
396b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        mInCallScreen = null;
397b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        mDialerKeyListener = null;
39851eaa15edd6953b961a502bd517bcdec59d15d13Martin Hibdon        mHandler.removeMessages(DTMF_SEND_CNF);
39951eaa15edd6953b961a502bd517bcdec59d15d13Martin Hibdon        synchronized (mDTMFQueue) {
40051eaa15edd6953b961a502bd517bcdec59d15d13Martin Hibdon            mDTMFBurstCnfPending = false;
40151eaa15edd6953b961a502bd517bcdec59d15d13Martin Hibdon            mDTMFQueue.clear();
402d533a71d64507e33d78dc65aa2521eacb5f8bb25Wink Saville        }
403b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        closeDialer(false);
404b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
405b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
406b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /**
407b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * Dialer code that runs when the dialer is brought up.
408b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * This includes layout changes, etc, and just prepares the dialer model for use.
409b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     */
410b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private void onDialerOpen() {
411b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (DBG) log("onDialerOpen()...");
412b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
413dfa83d531cdb88513f09e913424b7a16628b37d3David Brown        // Any time the dialer is open, listen for "disconnect" events (so
414dfa83d531cdb88513f09e913424b7a16628b37d3David Brown        // we can close ourself.)
415fa08be2879b66dc61a8e0b5a85dfdd7ef942570bHung-ying Tyan        mCM.registerForDisconnect(mHandler, PHONE_DISCONNECT, null);
416b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
417dfa83d531cdb88513f09e913424b7a16628b37d3David Brown        // On some devices the screen timeout is set to a special value
418dfa83d531cdb88513f09e913424b7a16628b37d3David Brown        // while the dialpad is up.
419986d2f46bd9572b563b89627fa60a9ea0853a91fJim Miller        PhoneApp.getInstance().updateWakeState();
420b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
421dfa83d531cdb88513f09e913424b7a16628b37d3David Brown        // Give the InCallScreen a chance to do any necessary UI updates.
422dfa83d531cdb88513f09e913424b7a16628b37d3David Brown        mInCallScreen.onDialerOpen();
423b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
424b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
425b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /**
4261066df0a541fb7b6a31fe2bea8a5b2e4e3e29f1aDavid Brown     * Allocates some resources we keep around during a "dialer session".
4271066df0a541fb7b6a31fe2bea8a5b2e4e3e29f1aDavid Brown     *
4281066df0a541fb7b6a31fe2bea8a5b2e4e3e29f1aDavid Brown     * (Currently, a "dialer session" just means any situation where we
4291066df0a541fb7b6a31fe2bea8a5b2e4e3e29f1aDavid Brown     * might need to play local DTMF tones, which means that we need to
4301066df0a541fb7b6a31fe2bea8a5b2e4e3e29f1aDavid Brown     * keep a ToneGenerator instance around.  A ToneGenerator instance
4311066df0a541fb7b6a31fe2bea8a5b2e4e3e29f1aDavid Brown     * keeps an AudioTrack resource busy in AudioFlinger, so we don't want
4321066df0a541fb7b6a31fe2bea8a5b2e4e3e29f1aDavid Brown     * to keep it around forever.)
4331066df0a541fb7b6a31fe2bea8a5b2e4e3e29f1aDavid Brown     *
4341066df0a541fb7b6a31fe2bea8a5b2e4e3e29f1aDavid Brown     * Call {@link stopDialerSession} to release the dialer session
4351066df0a541fb7b6a31fe2bea8a5b2e4e3e29f1aDavid Brown     * resources.
436b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     */
437b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    public void startDialerSession() {
4382f22a9001166458ef4b04f6142b6d6a480af1c9dDavid Brown        if (DBG) log("startDialerSession()... this = " + this);
4392f22a9001166458ef4b04f6142b6d6a480af1c9dDavid Brown
440b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // see if we need to play local tones.
441fa08be2879b66dc61a8e0b5a85dfdd7ef942570bHung-ying Tyan        if (PhoneApp.getInstance().getResources().getBoolean(R.bool.allow_local_dtmf_tones)) {
44251eaa15edd6953b961a502bd517bcdec59d15d13Martin Hibdon            mLocalToneEnabled = Settings.System.getInt(mInCallScreen.getContentResolver(),
443921814d9a5a90d4826d781dc70986ef82a786ad1Paul Berman                    Settings.System.DTMF_TONE_WHEN_DIALING, 1) == 1;
444921814d9a5a90d4826d781dc70986ef82a786ad1Paul Berman        } else {
44551eaa15edd6953b961a502bd517bcdec59d15d13Martin Hibdon            mLocalToneEnabled = false;
446921814d9a5a90d4826d781dc70986ef82a786ad1Paul Berman        }
44751eaa15edd6953b961a502bd517bcdec59d15d13Martin Hibdon        if (DBG) log("- startDialerSession: mLocalToneEnabled = " + mLocalToneEnabled);
448b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
449b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // create the tone generator
450b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // if the mToneGenerator creation fails, just continue without it.  It is
451b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // a local audio signal, and is not as important as the dtmf tone itself.
45251eaa15edd6953b961a502bd517bcdec59d15d13Martin Hibdon        if (mLocalToneEnabled) {
453b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            synchronized (mToneGeneratorLock) {
454b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (mToneGenerator == null) {
455b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    try {
456aa23e1c3c758bad23d8b6709147cc1ff7cd1e43cEric Laurent                        mToneGenerator = new ToneGenerator(AudioManager.STREAM_DTMF, 80);
457b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    } catch (RuntimeException e) {
458b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        if (DBG) log("Exception caught while creating local tone generator: " + e);
459b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        mToneGenerator = null;
460b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    }
461b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
462b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
463b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
464b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
465b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
466b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /**
467b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * Dialer code that runs when the dialer is closed.
468b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * This releases resources acquired when we start the dialer.
469b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     */
470b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private void onDialerClose() {
471b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (DBG) log("onDialerClose()...");
472b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
473b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // reset back to a short delay for the poke lock.
474b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        PhoneApp app = PhoneApp.getInstance();
475b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        app.updateWakeState();
476b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
477fa08be2879b66dc61a8e0b5a85dfdd7ef942570bHung-ying Tyan        mCM.unregisterForDisconnect(mHandler);
478b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
479b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // Give the InCallScreen a chance to do any necessary UI updates.
480a8de03f8104ac78874a50ebccf14d1d50b34b016David Brown        if (mInCallScreen != null) {
481a8de03f8104ac78874a50ebccf14d1d50b34b016David Brown            mInCallScreen.onDialerClose();
482a8de03f8104ac78874a50ebccf14d1d50b34b016David Brown        }
483b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
484b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
485b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /**
4861066df0a541fb7b6a31fe2bea8a5b2e4e3e29f1aDavid Brown     * Releases resources we keep around during a "dialer session"
4871066df0a541fb7b6a31fe2bea8a5b2e4e3e29f1aDavid Brown     * (see {@link startDialerSession}).
4881066df0a541fb7b6a31fe2bea8a5b2e4e3e29f1aDavid Brown     *
4891066df0a541fb7b6a31fe2bea8a5b2e4e3e29f1aDavid Brown     * It's safe to call this even without a corresponding
4901066df0a541fb7b6a31fe2bea8a5b2e4e3e29f1aDavid Brown     * startDialerSession call.
491b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     */
492b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    public void stopDialerSession() {
493b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // release the tone generator.
494b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        synchronized (mToneGeneratorLock) {
495b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            if (mToneGenerator != null) {
496b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                mToneGenerator.release();
497b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                mToneGenerator = null;
498b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
499b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
500b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
501b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
502b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /**
503b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * Called externally (from InCallScreen) to play a DTMF Tone.
504b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     */
505b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    public boolean onDialerKeyDown(KeyEvent event) {
506b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (DBG) log("Notifying dtmf key down.");
507b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        return mDialerKeyListener.onKeyDown(event);
508b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
509b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
510b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /**
511b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * Called externally (from InCallScreen) to cancel the last DTMF Tone played.
512b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     */
513b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    public boolean onDialerKeyUp(KeyEvent event) {
514b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (DBG) log("Notifying dtmf key up.");
515b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        return mDialerKeyListener.onKeyUp(event);
516b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
517b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
518b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /**
519b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * setup the keys on the dialer activity, using the keymaps.
520b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     */
521dfa83d531cdb88513f09e913424b7a16628b37d3David Brown    private void setupKeypad(DTMFTwelveKeyDialerView dialerView) {
522b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // for each view id listed in the displaymap
523b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        View button;
524b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        for (int viewId : mDisplayMap.keySet()) {
525b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            // locate the view
526dfa83d531cdb88513f09e913424b7a16628b37d3David Brown            button = dialerView.findViewById(viewId);
527b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            // Setup the listeners for the buttons
528b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            button.setOnTouchListener(this);
529b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            button.setClickable(true);
530b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            button.setOnKeyListener(this);
531b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
532b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
533b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
534b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /**
535b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * catch the back and call buttons to return to the in call activity.
536b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     */
537b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    public boolean onKeyDown(int keyCode, KeyEvent event) {
538b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // if (DBG) log("onKeyDown:  keyCode " + keyCode);
539b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        switch (keyCode) {
540b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            // finish for these events
541b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            case KeyEvent.KEYCODE_BACK:
542b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            case KeyEvent.KEYCODE_CALL:
543b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (DBG) log("exit requested");
544b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                closeDialer(true);  // do the "closing" animation
545b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                return true;
546b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
547b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        return mInCallScreen.onKeyDown(keyCode, event);
548b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
549b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
550b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /**
551b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * catch the back and call buttons to return to the in call activity.
552b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     */
553b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    public boolean onKeyUp(int keyCode, KeyEvent event) {
554b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // if (DBG) log("onKeyUp:  keyCode " + keyCode);
555b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        return mInCallScreen.onKeyUp(keyCode, event);
556b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
557b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
558b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /**
559b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * Implemented for the TouchListener, process the touch events.
560b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     */
561b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    public boolean onTouch(View v, MotionEvent event) {
562b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        int viewId = v.getId();
563b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
564b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // if the button is recognized
565b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (mDisplayMap.containsKey(viewId)) {
566b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            switch (event.getAction()) {
567b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                case MotionEvent.ACTION_DOWN:
568b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    // Append the character mapped to this button, to the display.
569b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    // start the tone
570b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    processDtmf(mDisplayMap.get(viewId));
571b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    break;
572b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                case MotionEvent.ACTION_UP:
573b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                case MotionEvent.ACTION_CANCEL:
574b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    // stop the tone on ANY other event, except for MOVE.
575b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    stopTone();
576b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    break;
577b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
578b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            // do not return true [handled] here, since we want the
579b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            // press / click animation to be handled by the framework.
580b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
581b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        return false;
582b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
583b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
584b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /**
585b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * Implements View.OnKeyListener for the DTMF buttons.  Enables dialing with trackball/dpad.
586b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     */
587b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    public boolean onKey(View v, int keyCode, KeyEvent event) {
588b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // if (DBG) log("onKey:  keyCode " + keyCode + ", view " + v);
589b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
590b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER) {
591b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            int viewId = v.getId();
592b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            if (mDisplayMap.containsKey(viewId)) {
593b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                switch (event.getAction()) {
594b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                case KeyEvent.ACTION_DOWN:
595b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    if (event.getRepeatCount() == 0) {
596b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        processDtmf(mDisplayMap.get(viewId));
597b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    }
598b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    break;
599b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                case KeyEvent.ACTION_UP:
600b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    stopTone();
601b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    break;
602b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
603b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // do not return true [handled] here, since we want the
604b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // press / click animation to be handled by the framework.
605b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
606b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
607b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        return false;
608b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
609b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
610b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /**
6115aadc2633b13d6676598dc0954be25c108d05fcdDavid Brown     * @return true if the dialer is currently visible onscreen.
612b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     */
6135aadc2633b13d6676598dc0954be25c108d05fcdDavid Brown    // TODO: clean up naming inconsistency of "opened" vs. "visible".
6145aadc2633b13d6676598dc0954be25c108d05fcdDavid Brown    // This should be called isVisible(), and open/closeDialer() should
6155aadc2633b13d6676598dc0954be25c108d05fcdDavid Brown    // be "show" and "hide".
616b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    public boolean isOpened() {
6174ba332e62c4d54b2623ccdc59fafd46ecba08cf0David Brown        // Return whether or not the dialer view is visible.
6185cba7d9f89df5092d3ae5095acd0bea96b5aa174David Brown        // (Note that if we're in the middle of a fade-out animation, that
6195cba7d9f89df5092d3ae5095acd0bea96b5aa174David Brown        // also counts as "not visible" even though mDialerView itself is
6205cba7d9f89df5092d3ae5095acd0bea96b5aa174David Brown        // technically still VISIBLE.)
6215cba7d9f89df5092d3ae5095acd0bea96b5aa174David Brown        return ((mDialerView.getVisibility() == View.VISIBLE)
6225cba7d9f89df5092d3ae5095acd0bea96b5aa174David Brown                && !CallCard.Fade.isFadingOut(mDialerView));
623b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
624b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
625b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /**
626b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * Forces the dialer into the "open" state.
627b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * Does nothing if the dialer is already open.
628b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     *
629b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * @param animate if true, open the dialer with an animation.
630b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     */
631b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    public void openDialer(boolean animate) {
6325aadc2633b13d6676598dc0954be25c108d05fcdDavid Brown        if (DBG) log("openDialer()...");
6335aadc2633b13d6676598dc0954be25c108d05fcdDavid Brown
6345aadc2633b13d6676598dc0954be25c108d05fcdDavid Brown        if (!isOpened()) {
6354ba332e62c4d54b2623ccdc59fafd46ecba08cf0David Brown            // Make the dialer view visible.
6365cba7d9f89df5092d3ae5095acd0bea96b5aa174David Brown            if (animate) {
6375cba7d9f89df5092d3ae5095acd0bea96b5aa174David Brown                CallCard.Fade.show(mDialerView);
6385cba7d9f89df5092d3ae5095acd0bea96b5aa174David Brown            } else {
6395cba7d9f89df5092d3ae5095acd0bea96b5aa174David Brown                mDialerView.setVisibility(View.VISIBLE);
6405cba7d9f89df5092d3ae5095acd0bea96b5aa174David Brown            }
6414ba332e62c4d54b2623ccdc59fafd46ecba08cf0David Brown            onDialerOpen();
642b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
643b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
644b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
645b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /**
646b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * Forces the dialer into the "closed" state.
647b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * Does nothing if the dialer is already closed.
648b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     *
649b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * @param animate if true, close the dialer with an animation.
650b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     */
651b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    public void closeDialer(boolean animate) {
6525aadc2633b13d6676598dc0954be25c108d05fcdDavid Brown        if (DBG) log("closeDialer()...");
6535aadc2633b13d6676598dc0954be25c108d05fcdDavid Brown
6545aadc2633b13d6676598dc0954be25c108d05fcdDavid Brown        if (isOpened()) {
6554ba332e62c4d54b2623ccdc59fafd46ecba08cf0David Brown            // Hide the dialer view.
6565cba7d9f89df5092d3ae5095acd0bea96b5aa174David Brown            if (animate) {
6575cba7d9f89df5092d3ae5095acd0bea96b5aa174David Brown                CallCard.Fade.hide(mDialerView, View.GONE);
6585cba7d9f89df5092d3ae5095acd0bea96b5aa174David Brown            } else {
6595cba7d9f89df5092d3ae5095acd0bea96b5aa174David Brown                mDialerView.setVisibility(View.GONE);
6605cba7d9f89df5092d3ae5095acd0bea96b5aa174David Brown            }
6614ba332e62c4d54b2623ccdc59fafd46ecba08cf0David Brown            onDialerClose();
662b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
663b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
664b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
665b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /**
666b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * Processes the specified digit as a DTMF key, by playing the
667b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * appropriate DTMF tone, and appending the digit to the EditText
668b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * field that displays the DTMF digits sent so far.
669b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     */
670b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private final void processDtmf(char c) {
671b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // if it is a valid key, then update the display and send the dtmf tone.
672b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (PhoneNumberUtils.is12Key(c)) {
673b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            if (DBG) log("updating display and sending dtmf tone for '" + c + "'");
674b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
675dfa83d531cdb88513f09e913424b7a16628b37d3David Brown            // Append this key to the "digits" widget.
676b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            if (mDialpadDigits != null) {
677dfa83d531cdb88513f09e913424b7a16628b37d3David Brown                // TODO: maybe *don't* manually append this digit if
678dfa83d531cdb88513f09e913424b7a16628b37d3David Brown                // mDialpadDigits is focused and this key came from the HW
679dfa83d531cdb88513f09e913424b7a16628b37d3David Brown                // keyboard, since in that case the EditText field will
680dfa83d531cdb88513f09e913424b7a16628b37d3David Brown                // get the key event directly and automatically appends
681dfa83d531cdb88513f09e913424b7a16628b37d3David Brown                // whetever the user types.
682dfa83d531cdb88513f09e913424b7a16628b37d3David Brown                // (Or, a cleaner fix would be to just make mDialpadDigits
683dfa83d531cdb88513f09e913424b7a16628b37d3David Brown                // *not* handle HW key presses.  That seems to be more
684dfa83d531cdb88513f09e913424b7a16628b37d3David Brown                // complicated than just setting focusable="false" on it,
685dfa83d531cdb88513f09e913424b7a16628b37d3David Brown                // though.)
686b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                mDialpadDigits.getText().append(c);
687b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
688b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
689b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            // Play the tone if it exists.
690b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            if (mToneMap.containsKey(c)) {
691b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                // begin tone playback.
692b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                startTone(c);
693b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
694b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        } else if (DBG) {
695b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            log("ignoring dtmf request for '" + c + "'");
696b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
697b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
6984472ce7a7e8568b4bb66098c4e4a2e71099167acDavid Brown        // Any DTMF keypress counts as explicit "user activity".
6994472ce7a7e8568b4bb66098c4e4a2e71099167acDavid Brown        PhoneApp.getInstance().pokeUserActivity();
700b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
701b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
702b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /**
703b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * Clears out the display of "DTMF digits typed so far" that's kept in
704dfa83d531cdb88513f09e913424b7a16628b37d3David Brown     * mDialpadDigits.
705b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     *
706b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * The InCallScreen is responsible for calling this method any time a
707b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * new call becomes active (or, more simply, any time a call ends).
708b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * This is how we make sure that the "history" of DTMF digits you type
709b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * doesn't persist from one call to the next.
710b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     *
711b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * TODO: it might be more elegent if the dialpad itself could remember
712b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * the call that we're associated with, and clear the digits if the
713b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * "current call" has changed since last time.  (This would require
714b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * some unique identifier that's different for each call.  We can't
715b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * just use the foreground Call object, since that's a singleton that
716b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * lasts the whole life of the phone process.  Instead, maybe look at
717b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * the Connection object that comes back from getEarliestConnection()?
718b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * Or getEarliestConnectTime()?)
719b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     *
720b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * Or to be even fancier, we could keep a mapping of *multiple*
721b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * "active calls" to DTMF strings.  That way you could have two lines
722b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * in use and swap calls multiple times, and we'd still remember the
723b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * digits for each call.  (But that's such an obscure use case that
724b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * it's probably not worth the extra complexity.)
725b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     */
726b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    public void clearDigits() {
727b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (DBG) log("clearDigits()...");
728b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
729b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (mDialpadDigits != null) {
730b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            mDialpadDigits.setText("");
731b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
732b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
733b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
734b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /**
73551eaa15edd6953b961a502bd517bcdec59d15d13Martin Hibdon     * Plays the local tone based the phone type.
736b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     */
73751eaa15edd6953b961a502bd517bcdec59d15d13Martin Hibdon    public void startTone(char c) {
73851eaa15edd6953b961a502bd517bcdec59d15d13Martin Hibdon        // Only play the tone if it exists.
73951eaa15edd6953b961a502bd517bcdec59d15d13Martin Hibdon        if (!mToneMap.containsKey(c)) {
74051eaa15edd6953b961a502bd517bcdec59d15d13Martin Hibdon            return;
74151eaa15edd6953b961a502bd517bcdec59d15d13Martin Hibdon        }
74251eaa15edd6953b961a502bd517bcdec59d15d13Martin Hibdon        // Read the settings as it may be changed by the user during the call
7437ede0c06e06bdb40aabccb52efab21cb85464904Hung-ying Tyan        Phone phone = mCM.getFgPhone();
7447ede0c06e06bdb40aabccb52efab21cb85464904Hung-ying Tyan        mShortTone = TelephonyCapabilities.useShortDtmfTones(phone, phone.getContext());
74551eaa15edd6953b961a502bd517bcdec59d15d13Martin Hibdon
746d533a71d64507e33d78dc65aa2521eacb5f8bb25Wink Saville        if (DBG) log("startDtmfTone()...");
747b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
74851eaa15edd6953b961a502bd517bcdec59d15d13Martin Hibdon        // For Short DTMF we need to play the local tone for fixed duration
74951eaa15edd6953b961a502bd517bcdec59d15d13Martin Hibdon        if (mShortTone) {
75051eaa15edd6953b961a502bd517bcdec59d15d13Martin Hibdon            sendShortDtmfToNetwork(c);
75151eaa15edd6953b961a502bd517bcdec59d15d13Martin Hibdon        } else {
75251eaa15edd6953b961a502bd517bcdec59d15d13Martin Hibdon            // Pass as a char to be sent to network
75351eaa15edd6953b961a502bd517bcdec59d15d13Martin Hibdon            Log.i(LOG_TAG, "send long dtmf for " + c);
7547ede0c06e06bdb40aabccb52efab21cb85464904Hung-ying Tyan            mCM.startDtmf(c);
755b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
75651eaa15edd6953b961a502bd517bcdec59d15d13Martin Hibdon        startLocalToneIfNeeded(c);
757b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
758b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
759b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /**
76051eaa15edd6953b961a502bd517bcdec59d15d13Martin Hibdon     * Plays the local tone based the phone type.
761b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     */
76251eaa15edd6953b961a502bd517bcdec59d15d13Martin Hibdon    public void startLocalToneIfNeeded(char c) {
76351eaa15edd6953b961a502bd517bcdec59d15d13Martin Hibdon        // if local tone playback is enabled, start it.
76451eaa15edd6953b961a502bd517bcdec59d15d13Martin Hibdon        // Only play the tone if it exists.
76551eaa15edd6953b961a502bd517bcdec59d15d13Martin Hibdon        if (!mToneMap.containsKey(c)) {
76651eaa15edd6953b961a502bd517bcdec59d15d13Martin Hibdon            return;
76751eaa15edd6953b961a502bd517bcdec59d15d13Martin Hibdon        }
76851eaa15edd6953b961a502bd517bcdec59d15d13Martin Hibdon        if (mLocalToneEnabled) {
769b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            synchronized (mToneGeneratorLock) {
770b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                if (mToneGenerator == null) {
77151eaa15edd6953b961a502bd517bcdec59d15d13Martin Hibdon                    if (DBG) log("startDtmfTone: mToneGenerator == null, tone: " + c);
772b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                } else {
77351eaa15edd6953b961a502bd517bcdec59d15d13Martin Hibdon                    if (DBG) log("starting local tone " + c);
77451eaa15edd6953b961a502bd517bcdec59d15d13Martin Hibdon                    int toneDuration = -1;
77551eaa15edd6953b961a502bd517bcdec59d15d13Martin Hibdon                    if (mShortTone) {
77651eaa15edd6953b961a502bd517bcdec59d15d13Martin Hibdon                        toneDuration = DTMF_DURATION_MS;
77751eaa15edd6953b961a502bd517bcdec59d15d13Martin Hibdon                    }
77851eaa15edd6953b961a502bd517bcdec59d15d13Martin Hibdon                    mToneGenerator.startTone(mToneMap.get(c), toneDuration);
779b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                }
780b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
781b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
782b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
783b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
784b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /**
785b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * Check to see if the keyEvent is dialable.
786b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     */
787b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    boolean isKeyEventAcceptable (KeyEvent event) {
788b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        return (mDialerKeyListener != null && mDialerKeyListener.isKeyEventAcceptable(event));
789b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
790b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
791b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    /**
792b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     * static logging method
793b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project     */
794b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private static void log(String msg) {
795b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        Log.d(LOG_TAG, msg);
796b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
797d533a71d64507e33d78dc65aa2521eacb5f8bb25Wink Saville
798d533a71d64507e33d78dc65aa2521eacb5f8bb25Wink Saville    /**
799d533a71d64507e33d78dc65aa2521eacb5f8bb25Wink Saville     * Stops the local tone based on the phone type.
800d533a71d64507e33d78dc65aa2521eacb5f8bb25Wink Saville     */
80151eaa15edd6953b961a502bd517bcdec59d15d13Martin Hibdon    public void stopTone() {
80251eaa15edd6953b961a502bd517bcdec59d15d13Martin Hibdon        if (!mShortTone) {
80351eaa15edd6953b961a502bd517bcdec59d15d13Martin Hibdon            if (DBG) log("stopping remote tone.");
8047ede0c06e06bdb40aabccb52efab21cb85464904Hung-ying Tyan            mCM.stopDtmf();
80551eaa15edd6953b961a502bd517bcdec59d15d13Martin Hibdon            stopLocalToneIfNeeded();
806d533a71d64507e33d78dc65aa2521eacb5f8bb25Wink Saville        }
807d533a71d64507e33d78dc65aa2521eacb5f8bb25Wink Saville    }
808d533a71d64507e33d78dc65aa2521eacb5f8bb25Wink Saville
809d533a71d64507e33d78dc65aa2521eacb5f8bb25Wink Saville    /**
81051eaa15edd6953b961a502bd517bcdec59d15d13Martin Hibdon     * Stops the local tone based on the phone type.
81199e0909905733fbc88300bdc4f475b1f6056388eZhu Kuanting     */
81251eaa15edd6953b961a502bd517bcdec59d15d13Martin Hibdon    public void stopLocalToneIfNeeded() {
81351eaa15edd6953b961a502bd517bcdec59d15d13Martin Hibdon        if (!mShortTone) {
81451eaa15edd6953b961a502bd517bcdec59d15d13Martin Hibdon            if (DBG) log("stopping remote tone.");
81551eaa15edd6953b961a502bd517bcdec59d15d13Martin Hibdon            // if local tone playback is enabled, stop it.
81651eaa15edd6953b961a502bd517bcdec59d15d13Martin Hibdon            if (DBG) log("trying to stop local tone...");
81751eaa15edd6953b961a502bd517bcdec59d15d13Martin Hibdon            if (mLocalToneEnabled) {
81851eaa15edd6953b961a502bd517bcdec59d15d13Martin Hibdon                synchronized (mToneGeneratorLock) {
81951eaa15edd6953b961a502bd517bcdec59d15d13Martin Hibdon                    if (mToneGenerator == null) {
82051eaa15edd6953b961a502bd517bcdec59d15d13Martin Hibdon                        if (DBG) log("stopLocalTone: mToneGenerator == null");
82151eaa15edd6953b961a502bd517bcdec59d15d13Martin Hibdon                    } else {
82251eaa15edd6953b961a502bd517bcdec59d15d13Martin Hibdon                        if (DBG) log("stopping local tone.");
82351eaa15edd6953b961a502bd517bcdec59d15d13Martin Hibdon                        mToneGenerator.stopTone();
82480fd5ab27e6a7df77e6e74e819f1a422f0f3fda8Peng Zhu                    }
82580fd5ab27e6a7df77e6e74e819f1a422f0f3fda8Peng Zhu                }
826d533a71d64507e33d78dc65aa2521eacb5f8bb25Wink Saville            }
827d533a71d64507e33d78dc65aa2521eacb5f8bb25Wink Saville        }
828d533a71d64507e33d78dc65aa2521eacb5f8bb25Wink Saville    }
829d533a71d64507e33d78dc65aa2521eacb5f8bb25Wink Saville
830d533a71d64507e33d78dc65aa2521eacb5f8bb25Wink Saville    /**
831d533a71d64507e33d78dc65aa2521eacb5f8bb25Wink Saville     * Sends the dtmf character over the network for short DTMF settings
83280fd5ab27e6a7df77e6e74e819f1a422f0f3fda8Peng Zhu     * When the characters are entered in quick succession,
83380fd5ab27e6a7df77e6e74e819f1a422f0f3fda8Peng Zhu     * the characters are queued before sending over the network.
834d533a71d64507e33d78dc65aa2521eacb5f8bb25Wink Saville     */
835d533a71d64507e33d78dc65aa2521eacb5f8bb25Wink Saville    private void sendShortDtmfToNetwork(char dtmfDigit) {
836d533a71d64507e33d78dc65aa2521eacb5f8bb25Wink Saville        synchronized (mDTMFQueue) {
837d533a71d64507e33d78dc65aa2521eacb5f8bb25Wink Saville            if (mDTMFBurstCnfPending == true) {
838d533a71d64507e33d78dc65aa2521eacb5f8bb25Wink Saville                // Insert the dtmf char to the queue
839d533a71d64507e33d78dc65aa2521eacb5f8bb25Wink Saville                mDTMFQueue.add(new Character(dtmfDigit));
840d533a71d64507e33d78dc65aa2521eacb5f8bb25Wink Saville            } else {
841d533a71d64507e33d78dc65aa2521eacb5f8bb25Wink Saville                String dtmfStr = Character.toString(dtmfDigit);
842dfa83d531cdb88513f09e913424b7a16628b37d3David Brown                Log.i(LOG_TAG, "dtmfsent = " + dtmfStr);
843fa08be2879b66dc61a8e0b5a85dfdd7ef942570bHung-ying Tyan                mCM.sendBurstDtmf(dtmfStr, 0, 0, mHandler.obtainMessage(DTMF_SEND_CNF));
844d533a71d64507e33d78dc65aa2521eacb5f8bb25Wink Saville                // Set flag to indicate wait for Telephony confirmation.
845d533a71d64507e33d78dc65aa2521eacb5f8bb25Wink Saville                mDTMFBurstCnfPending = true;
846d533a71d64507e33d78dc65aa2521eacb5f8bb25Wink Saville            }
847d533a71d64507e33d78dc65aa2521eacb5f8bb25Wink Saville        }
848d533a71d64507e33d78dc65aa2521eacb5f8bb25Wink Saville    }
849d533a71d64507e33d78dc65aa2521eacb5f8bb25Wink Saville
850d533a71d64507e33d78dc65aa2521eacb5f8bb25Wink Saville    /**
851d533a71d64507e33d78dc65aa2521eacb5f8bb25Wink Saville     * Handles Burst Dtmf Confirmation from the Framework.
852d533a71d64507e33d78dc65aa2521eacb5f8bb25Wink Saville     */
853d533a71d64507e33d78dc65aa2521eacb5f8bb25Wink Saville    void handleBurstDtmfConfirmation() {
854d533a71d64507e33d78dc65aa2521eacb5f8bb25Wink Saville        Character dtmfChar = null;
855dfa83d531cdb88513f09e913424b7a16628b37d3David Brown        synchronized (mDTMFQueue) {
856d533a71d64507e33d78dc65aa2521eacb5f8bb25Wink Saville            mDTMFBurstCnfPending = false;
857dfa83d531cdb88513f09e913424b7a16628b37d3David Brown            if (!mDTMFQueue.isEmpty()) {
858d533a71d64507e33d78dc65aa2521eacb5f8bb25Wink Saville                dtmfChar = mDTMFQueue.remove();
859d533a71d64507e33d78dc65aa2521eacb5f8bb25Wink Saville                Log.i(LOG_TAG, "The dtmf character removed from queue" + dtmfChar);
860d533a71d64507e33d78dc65aa2521eacb5f8bb25Wink Saville            }
861d533a71d64507e33d78dc65aa2521eacb5f8bb25Wink Saville        }
862d533a71d64507e33d78dc65aa2521eacb5f8bb25Wink Saville        if (dtmfChar != null) {
863d533a71d64507e33d78dc65aa2521eacb5f8bb25Wink Saville            sendShortDtmfToNetwork(dtmfChar);
864d533a71d64507e33d78dc65aa2521eacb5f8bb25Wink Saville        }
865d533a71d64507e33d78dc65aa2521eacb5f8bb25Wink Saville    }
866b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project}
867