DtmfLocalTonePlayer.java revision 92a2d811b6206eec84b3c21100dd64f660dae3a2
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
17package com.android.telecomm;
18
19import android.media.AudioManager;
20import android.media.ToneGenerator;
21import android.provider.Settings;
22
23import com.google.common.base.Preconditions;
24import com.google.common.collect.ImmutableMap;
25
26import java.util.Map;
27
28/**
29 * Plays DTMF tones locally for the caller to hear. In order to reduce (1) the amount of times we
30 * check the "play local tones" setting and (2) the length of time we keep the tone generator, this
31 * class employs a concept of a call "session" that starts and stops when the foreground call
32 * changes.
33 */
34class DtmfLocalTonePlayer extends CallsManagerListenerBase {
35    private static final Map<Character, Integer> TONE_MAP =
36            ImmutableMap.<Character, Integer>builder()
37                    .put('1', ToneGenerator.TONE_DTMF_1)
38                    .put('2', ToneGenerator.TONE_DTMF_2)
39                    .put('3', ToneGenerator.TONE_DTMF_3)
40                    .put('4', ToneGenerator.TONE_DTMF_4)
41                    .put('5', ToneGenerator.TONE_DTMF_5)
42                    .put('6', ToneGenerator.TONE_DTMF_6)
43                    .put('7', ToneGenerator.TONE_DTMF_7)
44                    .put('8', ToneGenerator.TONE_DTMF_8)
45                    .put('9', ToneGenerator.TONE_DTMF_9)
46                    .put('0', ToneGenerator.TONE_DTMF_0)
47                    .put('#', ToneGenerator.TONE_DTMF_P)
48                    .put('*', ToneGenerator.TONE_DTMF_S)
49                    .build();
50
51    /** Generator used to actually play the tone. */
52    private ToneGenerator mToneGenerator;
53
54    /** The current call associated with an existing dtmf session. */
55    private Call mCall;
56
57    /** {@inheritDoc} */
58    @Override
59    public void onForegroundCallChanged(Call oldForegroundCall, Call newForegroundCall) {
60        if (oldForegroundCall != null) {
61            endDtmfSession(oldForegroundCall);
62        }
63
64        if (newForegroundCall != null) {
65            startDtmfSession(newForegroundCall);
66        }
67    }
68
69    /**
70     * Starts playing the dtmf tone specified by c.
71     *
72     * @param call The associated call.
73     * @param c The digit to play.
74     */
75    void playTone(Call call, char c) {
76        // Do nothing if it is not the right call.
77        if (mCall != call) {
78            return;
79        }
80
81        if (mToneGenerator == null) {
82            Log.d(this, "playTone: mToneGenerator == null, %c.", c);
83        } else {
84            Log.d(this, "starting local tone: %c.", c);
85            if (TONE_MAP.containsKey(c)) {
86                mToneGenerator.startTone(TONE_MAP.get(c), -1 /* toneDuration */);
87            }
88        }
89    }
90
91    /**
92     * Stops any currently playing dtmf tone.
93     *
94     * @param call The associated call.
95     */
96    void stopTone(Call call) {
97        // Do nothing if it's not the right call.
98        if (mCall != call) {
99            return;
100        }
101
102        if (mToneGenerator == null) {
103            Log.d(this, "stopTone: mToneGenerator == null.");
104        } else {
105            Log.d(this, "stopping local tone.");
106            mToneGenerator.stopTone();
107        }
108    }
109
110    /**
111     * Runs initialization requires to play local tones during a call.
112     *
113     * @param call The call associated with this dtmf session.
114     */
115    private void startDtmfSession(Call call) {
116        Preconditions.checkNotNull(call);
117        TelecommApp app = TelecommApp.getInstance();
118
119        final boolean areLocalTonesEnabled;
120        if (app.getResources().getBoolean(R.bool.allow_local_dtmf_tones)) {
121            areLocalTonesEnabled = Settings.System.getInt(
122                    app.getContentResolver(), Settings.System.DTMF_TONE_WHEN_DIALING, 1) == 1;
123        } else {
124            areLocalTonesEnabled = false;
125        }
126
127        mCall = call;
128
129        if (areLocalTonesEnabled) {
130            if (mToneGenerator == null) {
131                try {
132                    mToneGenerator = new ToneGenerator(AudioManager.STREAM_DTMF, 80);
133                } catch (RuntimeException e) {
134                    Log.e(this, e, "Error creating local tone generator.");
135                    mToneGenerator = null;
136                }
137            }
138        }
139    }
140
141    /**
142     * Releases resources needed for playing local dtmf tones.
143     *
144     * @param call The call associated with the session to end.
145     */
146    private void endDtmfSession(Call call) {
147        Preconditions.checkNotNull(call);
148        if (mCall == call) {
149            // Do a stopTone() in case the sessions ends before we are told to stop the tone.
150            stopTone(call);
151
152            mCall = null;
153
154            if (mToneGenerator != null) {
155                mToneGenerator.release();
156                mToneGenerator = null;
157            }
158        }
159    }
160}
161