192a2d811b6206eec84b3c21100dd64f660dae3a2Santos Cordon/* 292a2d811b6206eec84b3c21100dd64f660dae3a2Santos Cordon * Copyright 2014, The Android Open Source Project 392a2d811b6206eec84b3c21100dd64f660dae3a2Santos Cordon * 492a2d811b6206eec84b3c21100dd64f660dae3a2Santos Cordon * Licensed under the Apache License, Version 2.0 (the "License"); 592a2d811b6206eec84b3c21100dd64f660dae3a2Santos Cordon * you may not use this file except in compliance with the License. 692a2d811b6206eec84b3c21100dd64f660dae3a2Santos Cordon * You may obtain a copy of the License at 792a2d811b6206eec84b3c21100dd64f660dae3a2Santos Cordon * 892a2d811b6206eec84b3c21100dd64f660dae3a2Santos Cordon * http://www.apache.org/licenses/LICENSE-2.0 992a2d811b6206eec84b3c21100dd64f660dae3a2Santos Cordon * 1092a2d811b6206eec84b3c21100dd64f660dae3a2Santos Cordon * Unless required by applicable law or agreed to in writing, software 1192a2d811b6206eec84b3c21100dd64f660dae3a2Santos Cordon * distributed under the License is distributed on an "AS IS" BASIS, 1292a2d811b6206eec84b3c21100dd64f660dae3a2Santos Cordon * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1392a2d811b6206eec84b3c21100dd64f660dae3a2Santos Cordon * See the License for the specific language governing permissions and 1492a2d811b6206eec84b3c21100dd64f660dae3a2Santos Cordon * limitations under the License. 1592a2d811b6206eec84b3c21100dd64f660dae3a2Santos Cordon */ 1692a2d811b6206eec84b3c21100dd64f660dae3a2Santos Cordon 177cc70b4f0ad1064a4a0dce6056ad82b205887160Tyler Gunnpackage com.android.server.telecom; 1892a2d811b6206eec84b3c21100dd64f660dae3a2Santos Cordon 1991d43cf9c985cc5a83795f256ef5c46ebb8fbdc1Tyler Gunnimport android.content.Context; 2092a2d811b6206eec84b3c21100dd64f660dae3a2Santos Cordonimport android.media.AudioManager; 2192a2d811b6206eec84b3c21100dd64f660dae3a2Santos Cordonimport android.media.ToneGenerator; 229bb88e9ce53449aa6f612b98d36fbfa80a1624e4Roshan Piusimport android.os.Handler; 239bb88e9ce53449aa6f612b98d36fbfa80a1624e4Roshan Piusimport android.os.HandlerThread; 249bb88e9ce53449aa6f612b98d36fbfa80a1624e4Roshan Piusimport android.os.Message; 2592a2d811b6206eec84b3c21100dd64f660dae3a2Santos Cordonimport android.provider.Settings; 2692a2d811b6206eec84b3c21100dd64f660dae3a2Santos Cordon 279bb88e9ce53449aa6f612b98d36fbfa80a1624e4Roshan Piusimport com.android.internal.util.Preconditions; 289bb88e9ce53449aa6f612b98d36fbfa80a1624e4Roshan Pius 2991d43cf9c985cc5a83795f256ef5c46ebb8fbdc1Tyler Gunn// TODO: Needed for move to system service: import com.android.internal.R; 3092a2d811b6206eec84b3c21100dd64f660dae3a2Santos Cordon 3192a2d811b6206eec84b3c21100dd64f660dae3a2Santos Cordon/** 3292a2d811b6206eec84b3c21100dd64f660dae3a2Santos Cordon * Plays DTMF tones locally for the caller to hear. In order to reduce (1) the amount of times we 3392a2d811b6206eec84b3c21100dd64f660dae3a2Santos Cordon * check the "play local tones" setting and (2) the length of time we keep the tone generator, this 3492a2d811b6206eec84b3c21100dd64f660dae3a2Santos Cordon * class employs a concept of a call "session" that starts and stops when the foreground call 3592a2d811b6206eec84b3c21100dd64f660dae3a2Santos Cordon * changes. 3692a2d811b6206eec84b3c21100dd64f660dae3a2Santos Cordon */ 37e792b33c2aa95d97db74e4c0b1e7ea6896cf99eeHall Liupublic class DtmfLocalTonePlayer { 3892a2d811b6206eec84b3c21100dd64f660dae3a2Santos Cordon /** Generator used to actually play the tone. */ 3992a2d811b6206eec84b3c21100dd64f660dae3a2Santos Cordon private ToneGenerator mToneGenerator; 4092a2d811b6206eec84b3c21100dd64f660dae3a2Santos Cordon 4192a2d811b6206eec84b3c21100dd64f660dae3a2Santos Cordon /** The current call associated with an existing dtmf session. */ 4292a2d811b6206eec84b3c21100dd64f660dae3a2Santos Cordon private Call mCall; 4392a2d811b6206eec84b3c21100dd64f660dae3a2Santos Cordon 449bb88e9ce53449aa6f612b98d36fbfa80a1624e4Roshan Pius /** 459bb88e9ce53449aa6f612b98d36fbfa80a1624e4Roshan Pius * Message codes to be used for creating and deleting ToneGenerator object in the tonegenerator 469bb88e9ce53449aa6f612b98d36fbfa80a1624e4Roshan Pius * thread. 479bb88e9ce53449aa6f612b98d36fbfa80a1624e4Roshan Pius */ 489bb88e9ce53449aa6f612b98d36fbfa80a1624e4Roshan Pius private static final int EVENT_CREATE_OBJECT = 1; 499bb88e9ce53449aa6f612b98d36fbfa80a1624e4Roshan Pius private static final int EVENT_DELETE_OBJECT = 2; 509bb88e9ce53449aa6f612b98d36fbfa80a1624e4Roshan Pius 519bb88e9ce53449aa6f612b98d36fbfa80a1624e4Roshan Pius /** Handler running on the tonegenerator thread. */ 529bb88e9ce53449aa6f612b98d36fbfa80a1624e4Roshan Pius private Handler mHandler; 539bb88e9ce53449aa6f612b98d36fbfa80a1624e4Roshan Pius 54e091ab90e37845cf4771051a6d2ce0ebadee4fe7Hall Liu public DtmfLocalTonePlayer() { } 559bb88e9ce53449aa6f612b98d36fbfa80a1624e4Roshan Pius 5692a2d811b6206eec84b3c21100dd64f660dae3a2Santos Cordon public void onForegroundCallChanged(Call oldForegroundCall, Call newForegroundCall) { 57acb91eb8e9d0f08a7ccce72062a7eb2cf958aa51Jay Shrauner endDtmfSession(oldForegroundCall); 58acb91eb8e9d0f08a7ccce72062a7eb2cf958aa51Jay Shrauner startDtmfSession(newForegroundCall); 5992a2d811b6206eec84b3c21100dd64f660dae3a2Santos Cordon } 6092a2d811b6206eec84b3c21100dd64f660dae3a2Santos Cordon 6192a2d811b6206eec84b3c21100dd64f660dae3a2Santos Cordon /** 6292a2d811b6206eec84b3c21100dd64f660dae3a2Santos Cordon * Starts playing the dtmf tone specified by c. 6392a2d811b6206eec84b3c21100dd64f660dae3a2Santos Cordon * 6492a2d811b6206eec84b3c21100dd64f660dae3a2Santos Cordon * @param call The associated call. 6592a2d811b6206eec84b3c21100dd64f660dae3a2Santos Cordon * @param c The digit to play. 6692a2d811b6206eec84b3c21100dd64f660dae3a2Santos Cordon */ 6792a2d811b6206eec84b3c21100dd64f660dae3a2Santos Cordon void playTone(Call call, char c) { 6892a2d811b6206eec84b3c21100dd64f660dae3a2Santos Cordon // Do nothing if it is not the right call. 6992a2d811b6206eec84b3c21100dd64f660dae3a2Santos Cordon if (mCall != call) { 7092a2d811b6206eec84b3c21100dd64f660dae3a2Santos Cordon return; 7192a2d811b6206eec84b3c21100dd64f660dae3a2Santos Cordon } 729bb88e9ce53449aa6f612b98d36fbfa80a1624e4Roshan Pius synchronized(this) { 739bb88e9ce53449aa6f612b98d36fbfa80a1624e4Roshan Pius if (mToneGenerator == null) { 749bb88e9ce53449aa6f612b98d36fbfa80a1624e4Roshan Pius Log.d(this, "playTone: mToneGenerator == null, %c.", c); 759bb88e9ce53449aa6f612b98d36fbfa80a1624e4Roshan Pius } else { 769bb88e9ce53449aa6f612b98d36fbfa80a1624e4Roshan Pius Log.d(this, "starting local tone: %c.", c); 779bb88e9ce53449aa6f612b98d36fbfa80a1624e4Roshan Pius int tone = getMappedTone(c); 789bb88e9ce53449aa6f612b98d36fbfa80a1624e4Roshan Pius if (tone != ToneGenerator.TONE_UNKNOWN) { 799bb88e9ce53449aa6f612b98d36fbfa80a1624e4Roshan Pius mToneGenerator.startTone(tone, -1 /* toneDuration */); 809bb88e9ce53449aa6f612b98d36fbfa80a1624e4Roshan Pius } 8192a2d811b6206eec84b3c21100dd64f660dae3a2Santos Cordon } 8292a2d811b6206eec84b3c21100dd64f660dae3a2Santos Cordon } 8392a2d811b6206eec84b3c21100dd64f660dae3a2Santos Cordon } 8492a2d811b6206eec84b3c21100dd64f660dae3a2Santos Cordon 8592a2d811b6206eec84b3c21100dd64f660dae3a2Santos Cordon /** 8692a2d811b6206eec84b3c21100dd64f660dae3a2Santos Cordon * Stops any currently playing dtmf tone. 8792a2d811b6206eec84b3c21100dd64f660dae3a2Santos Cordon * 8892a2d811b6206eec84b3c21100dd64f660dae3a2Santos Cordon * @param call The associated call. 8992a2d811b6206eec84b3c21100dd64f660dae3a2Santos Cordon */ 9092a2d811b6206eec84b3c21100dd64f660dae3a2Santos Cordon void stopTone(Call call) { 9192a2d811b6206eec84b3c21100dd64f660dae3a2Santos Cordon // Do nothing if it's not the right call. 9292a2d811b6206eec84b3c21100dd64f660dae3a2Santos Cordon if (mCall != call) { 9392a2d811b6206eec84b3c21100dd64f660dae3a2Santos Cordon return; 9492a2d811b6206eec84b3c21100dd64f660dae3a2Santos Cordon } 959bb88e9ce53449aa6f612b98d36fbfa80a1624e4Roshan Pius synchronized(this) { 969bb88e9ce53449aa6f612b98d36fbfa80a1624e4Roshan Pius if (mToneGenerator == null) { 979bb88e9ce53449aa6f612b98d36fbfa80a1624e4Roshan Pius Log.d(this, "stopTone: mToneGenerator == null."); 989bb88e9ce53449aa6f612b98d36fbfa80a1624e4Roshan Pius } else { 999bb88e9ce53449aa6f612b98d36fbfa80a1624e4Roshan Pius Log.d(this, "stopping local tone."); 1009bb88e9ce53449aa6f612b98d36fbfa80a1624e4Roshan Pius mToneGenerator.stopTone(); 1019bb88e9ce53449aa6f612b98d36fbfa80a1624e4Roshan Pius } 10292a2d811b6206eec84b3c21100dd64f660dae3a2Santos Cordon } 10392a2d811b6206eec84b3c21100dd64f660dae3a2Santos Cordon } 10492a2d811b6206eec84b3c21100dd64f660dae3a2Santos Cordon 10592a2d811b6206eec84b3c21100dd64f660dae3a2Santos Cordon /** 10692a2d811b6206eec84b3c21100dd64f660dae3a2Santos Cordon * Runs initialization requires to play local tones during a call. 10792a2d811b6206eec84b3c21100dd64f660dae3a2Santos Cordon * 10892a2d811b6206eec84b3c21100dd64f660dae3a2Santos Cordon * @param call The call associated with this dtmf session. 10992a2d811b6206eec84b3c21100dd64f660dae3a2Santos Cordon */ 11092a2d811b6206eec84b3c21100dd64f660dae3a2Santos Cordon private void startDtmfSession(Call call) { 111acb91eb8e9d0f08a7ccce72062a7eb2cf958aa51Jay Shrauner if (call == null) { 112acb91eb8e9d0f08a7ccce72062a7eb2cf958aa51Jay Shrauner return; 113acb91eb8e9d0f08a7ccce72062a7eb2cf958aa51Jay Shrauner } 11491d43cf9c985cc5a83795f256ef5c46ebb8fbdc1Tyler Gunn final Context context = call.getContext(); 11592a2d811b6206eec84b3c21100dd64f660dae3a2Santos Cordon final boolean areLocalTonesEnabled; 11691d43cf9c985cc5a83795f256ef5c46ebb8fbdc1Tyler Gunn if (context.getResources().getBoolean(R.bool.allow_local_dtmf_tones)) { 11792a2d811b6206eec84b3c21100dd64f660dae3a2Santos Cordon areLocalTonesEnabled = Settings.System.getInt( 11891d43cf9c985cc5a83795f256ef5c46ebb8fbdc1Tyler Gunn context.getContentResolver(), Settings.System.DTMF_TONE_WHEN_DIALING, 1) == 1; 11992a2d811b6206eec84b3c21100dd64f660dae3a2Santos Cordon } else { 12092a2d811b6206eec84b3c21100dd64f660dae3a2Santos Cordon areLocalTonesEnabled = false; 12192a2d811b6206eec84b3c21100dd64f660dae3a2Santos Cordon } 12292a2d811b6206eec84b3c21100dd64f660dae3a2Santos Cordon 12392a2d811b6206eec84b3c21100dd64f660dae3a2Santos Cordon mCall = call; 12492a2d811b6206eec84b3c21100dd64f660dae3a2Santos Cordon 12592a2d811b6206eec84b3c21100dd64f660dae3a2Santos Cordon if (areLocalTonesEnabled) { 1269bb88e9ce53449aa6f612b98d36fbfa80a1624e4Roshan Pius Log.d(this, "Posting create."); 1279bb88e9ce53449aa6f612b98d36fbfa80a1624e4Roshan Pius postMessage(EVENT_CREATE_OBJECT); 12892a2d811b6206eec84b3c21100dd64f660dae3a2Santos Cordon } 12992a2d811b6206eec84b3c21100dd64f660dae3a2Santos Cordon } 13092a2d811b6206eec84b3c21100dd64f660dae3a2Santos Cordon 13192a2d811b6206eec84b3c21100dd64f660dae3a2Santos Cordon /** 13292a2d811b6206eec84b3c21100dd64f660dae3a2Santos Cordon * Releases resources needed for playing local dtmf tones. 13392a2d811b6206eec84b3c21100dd64f660dae3a2Santos Cordon * 13492a2d811b6206eec84b3c21100dd64f660dae3a2Santos Cordon * @param call The call associated with the session to end. 13592a2d811b6206eec84b3c21100dd64f660dae3a2Santos Cordon */ 13692a2d811b6206eec84b3c21100dd64f660dae3a2Santos Cordon private void endDtmfSession(Call call) { 137acb91eb8e9d0f08a7ccce72062a7eb2cf958aa51Jay Shrauner if (call != null && mCall == call) { 13892a2d811b6206eec84b3c21100dd64f660dae3a2Santos Cordon // Do a stopTone() in case the sessions ends before we are told to stop the tone. 13992a2d811b6206eec84b3c21100dd64f660dae3a2Santos Cordon stopTone(call); 14092a2d811b6206eec84b3c21100dd64f660dae3a2Santos Cordon 14192a2d811b6206eec84b3c21100dd64f660dae3a2Santos Cordon mCall = null; 1429bb88e9ce53449aa6f612b98d36fbfa80a1624e4Roshan Pius Log.d(this, "Posting delete."); 1439bb88e9ce53449aa6f612b98d36fbfa80a1624e4Roshan Pius postMessage(EVENT_DELETE_OBJECT); 1449bb88e9ce53449aa6f612b98d36fbfa80a1624e4Roshan Pius } 1459bb88e9ce53449aa6f612b98d36fbfa80a1624e4Roshan Pius } 14692a2d811b6206eec84b3c21100dd64f660dae3a2Santos Cordon 1479bb88e9ce53449aa6f612b98d36fbfa80a1624e4Roshan Pius /** 1489bb88e9ce53449aa6f612b98d36fbfa80a1624e4Roshan Pius * Posts a message to the tonegenerator-thread handler. Creates the handler if the handler 1499bb88e9ce53449aa6f612b98d36fbfa80a1624e4Roshan Pius * has not been instantiated. 1509bb88e9ce53449aa6f612b98d36fbfa80a1624e4Roshan Pius * 1519bb88e9ce53449aa6f612b98d36fbfa80a1624e4Roshan Pius * @param messageCode The message to post. 1529bb88e9ce53449aa6f612b98d36fbfa80a1624e4Roshan Pius */ 1539bb88e9ce53449aa6f612b98d36fbfa80a1624e4Roshan Pius private void postMessage(int messageCode) { 1549bb88e9ce53449aa6f612b98d36fbfa80a1624e4Roshan Pius synchronized(this) { 1559bb88e9ce53449aa6f612b98d36fbfa80a1624e4Roshan Pius if (mHandler == null) { 1569bb88e9ce53449aa6f612b98d36fbfa80a1624e4Roshan Pius mHandler = getNewHandler(); 1579bb88e9ce53449aa6f612b98d36fbfa80a1624e4Roshan Pius } 1589bb88e9ce53449aa6f612b98d36fbfa80a1624e4Roshan Pius 1599bb88e9ce53449aa6f612b98d36fbfa80a1624e4Roshan Pius if (mHandler == null) { 1609bb88e9ce53449aa6f612b98d36fbfa80a1624e4Roshan Pius Log.d(this, "Message %d skipped because there is no handler.", messageCode); 1619bb88e9ce53449aa6f612b98d36fbfa80a1624e4Roshan Pius } else { 1629bb88e9ce53449aa6f612b98d36fbfa80a1624e4Roshan Pius mHandler.obtainMessage(messageCode, null).sendToTarget(); 16392a2d811b6206eec84b3c21100dd64f660dae3a2Santos Cordon } 16492a2d811b6206eec84b3c21100dd64f660dae3a2Santos Cordon } 16592a2d811b6206eec84b3c21100dd64f660dae3a2Santos Cordon } 1664bc0245eb5c09ab48dcbb673eefdf7175ae8ac9cSantos Cordon 1679bb88e9ce53449aa6f612b98d36fbfa80a1624e4Roshan Pius /** 1689bb88e9ce53449aa6f612b98d36fbfa80a1624e4Roshan Pius * Creates a new tonegenerator Handler running in its own thread. 1699bb88e9ce53449aa6f612b98d36fbfa80a1624e4Roshan Pius */ 1709bb88e9ce53449aa6f612b98d36fbfa80a1624e4Roshan Pius private Handler getNewHandler() { 1719bb88e9ce53449aa6f612b98d36fbfa80a1624e4Roshan Pius Preconditions.checkState(mHandler == null); 1729bb88e9ce53449aa6f612b98d36fbfa80a1624e4Roshan Pius 1739bb88e9ce53449aa6f612b98d36fbfa80a1624e4Roshan Pius HandlerThread thread = new HandlerThread("tonegenerator-dtmf"); 1749bb88e9ce53449aa6f612b98d36fbfa80a1624e4Roshan Pius thread.start(); 1759bb88e9ce53449aa6f612b98d36fbfa80a1624e4Roshan Pius 1769bb88e9ce53449aa6f612b98d36fbfa80a1624e4Roshan Pius return new Handler(thread.getLooper()) { 1779bb88e9ce53449aa6f612b98d36fbfa80a1624e4Roshan Pius @Override 1789bb88e9ce53449aa6f612b98d36fbfa80a1624e4Roshan Pius public void handleMessage(Message msg) { 1799bb88e9ce53449aa6f612b98d36fbfa80a1624e4Roshan Pius switch(msg.what) { 1809bb88e9ce53449aa6f612b98d36fbfa80a1624e4Roshan Pius case EVENT_CREATE_OBJECT: 1819bb88e9ce53449aa6f612b98d36fbfa80a1624e4Roshan Pius synchronized(DtmfLocalTonePlayer.this) { 1829bb88e9ce53449aa6f612b98d36fbfa80a1624e4Roshan Pius if (mToneGenerator == null) { 1839bb88e9ce53449aa6f612b98d36fbfa80a1624e4Roshan Pius try { 1849bb88e9ce53449aa6f612b98d36fbfa80a1624e4Roshan Pius mToneGenerator = new ToneGenerator( 1859bb88e9ce53449aa6f612b98d36fbfa80a1624e4Roshan Pius AudioManager.STREAM_DTMF, 80); 1869bb88e9ce53449aa6f612b98d36fbfa80a1624e4Roshan Pius } catch (RuntimeException e) { 1879bb88e9ce53449aa6f612b98d36fbfa80a1624e4Roshan Pius Log.e(this, e, "Error creating local tone generator."); 1889bb88e9ce53449aa6f612b98d36fbfa80a1624e4Roshan Pius mToneGenerator = null; 1899bb88e9ce53449aa6f612b98d36fbfa80a1624e4Roshan Pius } 1909bb88e9ce53449aa6f612b98d36fbfa80a1624e4Roshan Pius } 1919bb88e9ce53449aa6f612b98d36fbfa80a1624e4Roshan Pius } 1929bb88e9ce53449aa6f612b98d36fbfa80a1624e4Roshan Pius break; 1939bb88e9ce53449aa6f612b98d36fbfa80a1624e4Roshan Pius case EVENT_DELETE_OBJECT: 1949bb88e9ce53449aa6f612b98d36fbfa80a1624e4Roshan Pius synchronized(DtmfLocalTonePlayer.this) { 1959bb88e9ce53449aa6f612b98d36fbfa80a1624e4Roshan Pius if (mToneGenerator != null) { 1969bb88e9ce53449aa6f612b98d36fbfa80a1624e4Roshan Pius mToneGenerator.release(); 1979bb88e9ce53449aa6f612b98d36fbfa80a1624e4Roshan Pius mToneGenerator = null; 1989bb88e9ce53449aa6f612b98d36fbfa80a1624e4Roshan Pius } 1999bb88e9ce53449aa6f612b98d36fbfa80a1624e4Roshan Pius // Delete the handler after the tone generator object is deleted by 2009bb88e9ce53449aa6f612b98d36fbfa80a1624e4Roshan Pius // the tonegenerator thread. 2019bb88e9ce53449aa6f612b98d36fbfa80a1624e4Roshan Pius if (mHandler != null && !mHandler.hasMessages(EVENT_CREATE_OBJECT)) { 2029bb88e9ce53449aa6f612b98d36fbfa80a1624e4Roshan Pius // Stop the handler only if there are no pending CREATE messages. 2039bb88e9ce53449aa6f612b98d36fbfa80a1624e4Roshan Pius mHandler.removeMessages(EVENT_DELETE_OBJECT); 2049bb88e9ce53449aa6f612b98d36fbfa80a1624e4Roshan Pius mHandler.getLooper().quitSafely(); 2059bb88e9ce53449aa6f612b98d36fbfa80a1624e4Roshan Pius mHandler = null; 2069bb88e9ce53449aa6f612b98d36fbfa80a1624e4Roshan Pius } 2079bb88e9ce53449aa6f612b98d36fbfa80a1624e4Roshan Pius } 2089bb88e9ce53449aa6f612b98d36fbfa80a1624e4Roshan Pius break; 2099bb88e9ce53449aa6f612b98d36fbfa80a1624e4Roshan Pius } 2109bb88e9ce53449aa6f612b98d36fbfa80a1624e4Roshan Pius } 2119bb88e9ce53449aa6f612b98d36fbfa80a1624e4Roshan Pius }; 2129bb88e9ce53449aa6f612b98d36fbfa80a1624e4Roshan Pius } 2139bb88e9ce53449aa6f612b98d36fbfa80a1624e4Roshan Pius 214e091ab90e37845cf4771051a6d2ce0ebadee4fe7Hall Liu private static int getMappedTone(char digit) { 2154bc0245eb5c09ab48dcbb673eefdf7175ae8ac9cSantos Cordon if (digit >= '0' && digit <= '9') { 2164bc0245eb5c09ab48dcbb673eefdf7175ae8ac9cSantos Cordon return ToneGenerator.TONE_DTMF_0 + digit - '0'; 2174bc0245eb5c09ab48dcbb673eefdf7175ae8ac9cSantos Cordon } else if (digit == '#') { 2184bc0245eb5c09ab48dcbb673eefdf7175ae8ac9cSantos Cordon return ToneGenerator.TONE_DTMF_P; 2194bc0245eb5c09ab48dcbb673eefdf7175ae8ac9cSantos Cordon } else if (digit == '*') { 2204bc0245eb5c09ab48dcbb673eefdf7175ae8ac9cSantos Cordon return ToneGenerator.TONE_DTMF_S; 2214bc0245eb5c09ab48dcbb673eefdf7175ae8ac9cSantos Cordon } 2224bc0245eb5c09ab48dcbb673eefdf7175ae8ac9cSantos Cordon return ToneGenerator.TONE_UNKNOWN; 2234bc0245eb5c09ab48dcbb673eefdf7175ae8ac9cSantos Cordon } 22492a2d811b6206eec84b3c21100dd64f660dae3a2Santos Cordon} 225