1 /* 2 * Copyright 2014, The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server.telecom; 18 19 import android.content.Context; 20 import android.media.AudioManager; 21 import android.media.ToneGenerator; 22 import android.provider.Settings; 23 24 // TODO: Needed for move to system service: import com.android.internal.R; 25 26 /** 27 * Plays DTMF tones locally for the caller to hear. In order to reduce (1) the amount of times we 28 * check the "play local tones" setting and (2) the length of time we keep the tone generator, this 29 * class employs a concept of a call "session" that starts and stops when the foreground call 30 * changes. 31 */ 32 class DtmfLocalTonePlayer extends CallsManagerListenerBase { 33 /** Generator used to actually play the tone. */ 34 private ToneGenerator mToneGenerator; 35 36 /** The current call associated with an existing dtmf session. */ 37 private Call mCall; 38 39 /** The context. */ 40 private final Context mContext; 41 DtmfLocalTonePlayer(Context context)42 public DtmfLocalTonePlayer(Context context) { 43 mContext = context; 44 } 45 46 /** {@inheritDoc} */ 47 @Override onForegroundCallChanged(Call oldForegroundCall, Call newForegroundCall)48 public void onForegroundCallChanged(Call oldForegroundCall, Call newForegroundCall) { 49 endDtmfSession(oldForegroundCall); 50 startDtmfSession(newForegroundCall); 51 } 52 53 /** 54 * Starts playing the dtmf tone specified by c. 55 * 56 * @param call The associated call. 57 * @param c The digit to play. 58 */ playTone(Call call, char c)59 void playTone(Call call, char c) { 60 // Do nothing if it is not the right call. 61 if (mCall != call) { 62 return; 63 } 64 65 if (mToneGenerator == null) { 66 Log.d(this, "playTone: mToneGenerator == null, %c.", c); 67 } else { 68 Log.d(this, "starting local tone: %c.", c); 69 int tone = getMappedTone(c); 70 if (tone != ToneGenerator.TONE_UNKNOWN) { 71 mToneGenerator.startTone(tone, -1 /* toneDuration */); 72 } 73 } 74 } 75 76 /** 77 * Stops any currently playing dtmf tone. 78 * 79 * @param call The associated call. 80 */ stopTone(Call call)81 void stopTone(Call call) { 82 // Do nothing if it's not the right call. 83 if (mCall != call) { 84 return; 85 } 86 87 if (mToneGenerator == null) { 88 Log.d(this, "stopTone: mToneGenerator == null."); 89 } else { 90 Log.d(this, "stopping local tone."); 91 mToneGenerator.stopTone(); 92 } 93 } 94 95 /** 96 * Runs initialization requires to play local tones during a call. 97 * 98 * @param call The call associated with this dtmf session. 99 */ startDtmfSession(Call call)100 private void startDtmfSession(Call call) { 101 if (call == null) { 102 return; 103 } 104 final Context context = call.getContext(); 105 final boolean areLocalTonesEnabled; 106 if (context.getResources().getBoolean(R.bool.allow_local_dtmf_tones)) { 107 areLocalTonesEnabled = Settings.System.getInt( 108 context.getContentResolver(), Settings.System.DTMF_TONE_WHEN_DIALING, 1) == 1; 109 } else { 110 areLocalTonesEnabled = false; 111 } 112 113 mCall = call; 114 115 if (areLocalTonesEnabled) { 116 if (mToneGenerator == null) { 117 try { 118 mToneGenerator = new ToneGenerator(AudioManager.STREAM_DTMF, 80); 119 } catch (RuntimeException e) { 120 Log.e(this, e, "Error creating local tone generator."); 121 mToneGenerator = null; 122 } 123 } 124 } 125 } 126 127 /** 128 * Releases resources needed for playing local dtmf tones. 129 * 130 * @param call The call associated with the session to end. 131 */ endDtmfSession(Call call)132 private void endDtmfSession(Call call) { 133 if (call != null && mCall == call) { 134 // Do a stopTone() in case the sessions ends before we are told to stop the tone. 135 stopTone(call); 136 137 mCall = null; 138 139 if (mToneGenerator != null) { 140 mToneGenerator.release(); 141 mToneGenerator = null; 142 } 143 } 144 } 145 getMappedTone(char digit)146 private static final int getMappedTone(char digit) { 147 if (digit >= '0' && digit <= '9') { 148 return ToneGenerator.TONE_DTMF_0 + digit - '0'; 149 } else if (digit == '#') { 150 return ToneGenerator.TONE_DTMF_P; 151 } else if (digit == '*') { 152 return ToneGenerator.TONE_DTMF_S; 153 } 154 return ToneGenerator.TONE_UNKNOWN; 155 } 156 } 157