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