InCallTonePlayer.java revision 7062bb96f567e7dc9c7bf933b7bee17bb2c8108c
1a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon/*
2a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon * Copyright 2014, The Android Open Source Project
3a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon *
4a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon * Licensed under the Apache License, Version 2.0 (the "License");
5a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon * you may not use this file except in compliance with the License.
6a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon * You may obtain a copy of the License at
7a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon *
8a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon *     http://www.apache.org/licenses/LICENSE-2.0
9a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon *
10a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon * Unless required by applicable law or agreed to in writing, software
11a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon * distributed under the License is distributed on an "AS IS" BASIS,
12a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon * See the License for the specific language governing permissions and
14a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon * limitations under the License.
15a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon */
16a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon
177cc70b4f0ad1064a4a0dce6056ad82b205887160Tyler Gunnpackage com.android.server.telecom;
18a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon
19a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordonimport android.media.AudioManager;
20a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordonimport android.media.ToneGenerator;
21a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordonimport android.os.Handler;
22a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordonimport android.os.Looper;
23a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon
24a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon/**
25a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon * Play a call-related tone (ringback, busy signal, etc.) through ToneGenerator. To use, create an
26a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon * instance using InCallTonePlayer.Factory (passing in the TONE_* constant for the tone you want)
27a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon * and start() it. Implemented on top of {@link Thread} so that the tone plays in its own thread.
28a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon */
29a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordonpublic final class InCallTonePlayer extends Thread {
30a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon
31a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon    /**
32a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon     * Factory used to create InCallTonePlayers. Exists to aid with testing mocks.
33a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon     */
34a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon    public static class Factory {
35a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon        private final CallAudioManager mCallAudioManager;
36a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon
37a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon        Factory(CallAudioManager callAudioManager) {
38a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon            mCallAudioManager = callAudioManager;
39a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon        }
40a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon
41a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon        InCallTonePlayer createPlayer(int tone) {
42a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon            return new InCallTonePlayer(tone, mCallAudioManager);
43a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon        }
44a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon    }
45a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon
46a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon    // The possible tones that we can play.
47c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon    public static final int TONE_INVALID = 0;
48c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon    public static final int TONE_BUSY = 1;
49c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon    public static final int TONE_CALL_ENDED = 2;
50c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon    public static final int TONE_OTA_CALL_ENDED = 3;
51c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon    public static final int TONE_CALL_WAITING = 4;
52c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon    public static final int TONE_CDMA_DROP = 5;
53c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon    public static final int TONE_CONGESTION = 6;
54c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon    public static final int TONE_INTERCEPT = 7;
55c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon    public static final int TONE_OUT_OF_SERVICE = 8;
56c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon    public static final int TONE_REDIAL = 9;
57c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon    public static final int TONE_REORDER = 10;
58c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon    public static final int TONE_RING_BACK = 11;
59c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon    public static final int TONE_UNOBTAINABLE_NUMBER = 12;
60c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon    public static final int TONE_VOICE_PRIVACY = 13;
61a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon
62a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon    private static final int RELATIVE_VOLUME_EMERGENCY = 100;
63a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon    private static final int RELATIVE_VOLUME_HIPRI = 80;
64a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon    private static final int RELATIVE_VOLUME_LOPRI = 50;
65a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon
66a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon    // Buffer time (in msec) to add on to the tone timeout value. Needed mainly when the timeout
67a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon    // value for a tone is exact duration of the tone itself.
688c85dee84fbbd8c36cf1c7b061001c6129623f92Sailesh Nepal    private static final int TIMEOUT_BUFFER_MILLIS = 20;
69a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon
70a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon    // The tone state.
71a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon    private static final int STATE_OFF = 0;
72a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon    private static final int STATE_ON = 1;
73a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon    private static final int STATE_STOPPED = 2;
74a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon
75a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon    /**
76a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon     * Keeps count of the number of actively playing tones so that we can notify CallAudioManager
77a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon     * when we need focus and when it can be release. This should only be manipulated from the main
78a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon     * thread.
79a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon     */
80a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon    private static int sTonesPlaying = 0;
81a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon
82a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon    private final CallAudioManager mCallAudioManager;
83a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon
84a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon    private final Handler mMainThreadHandler = new Handler(Looper.getMainLooper());
85a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon
86a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon    /** The ID of the tone to play. */
87a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon    private final int mToneId;
88a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon
89a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon    /** Current state of the tone player. */
90a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon    private int mState;
91a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon
92a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon    /**
93a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon     * Initializes the tone player. Private; use the {@link Factory} to create tone players.
94a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon     *
95a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon     * @param toneId ID of the tone to play, see TONE_* constants.
96a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon     */
97a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon    private InCallTonePlayer(int toneId, CallAudioManager callAudioManager) {
98a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon        mState = STATE_OFF;
99a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon        mToneId = toneId;
100a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon        mCallAudioManager = callAudioManager;
101a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon    }
102a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon
103a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon    /** {@inheritDoc} */
104a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon    @Override
105a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon    public void run() {
106a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon        ToneGenerator toneGenerator = null;
107a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon        try {
108a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon            Log.d(this, "run(toneId = %s)", mToneId);
109a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon
110a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon            final int toneType;  // Passed to ToneGenerator.startTone.
111a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon            final int toneVolume;  // Passed to the ToneGenerator constructor.
1128c85dee84fbbd8c36cf1c7b061001c6129623f92Sailesh Nepal            final int toneLengthMillis;
113a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon
114a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon            switch (mToneId) {
115c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon                case TONE_BUSY:
116c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon                    // TODO: CDMA-specific tones
117c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon                    toneType = ToneGenerator.TONE_SUP_BUSY;
118c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon                    toneVolume = RELATIVE_VOLUME_HIPRI;
1198c85dee84fbbd8c36cf1c7b061001c6129623f92Sailesh Nepal                    toneLengthMillis = 4000;
120c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon                    break;
121c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon                case TONE_CALL_ENDED:
122c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon                    toneType = ToneGenerator.TONE_PROP_PROMPT;
123c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon                    toneVolume = RELATIVE_VOLUME_HIPRI;
1247062bb96f567e7dc9c7bf933b7bee17bb2c8108cYorke Lee                    toneLengthMillis = 200;
125c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon                    break;
126c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon                case TONE_OTA_CALL_ENDED:
127c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon                    // TODO: fill in
128c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon                    throw new IllegalStateException("OTA Call ended NYI.");
129c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon                case TONE_CALL_WAITING:
13040f78c210512570f14cdfde9613dd85c510a1c0cSantos Cordon                    toneType = ToneGenerator.TONE_SUP_CALL_WAITING;
13140f78c210512570f14cdfde9613dd85c510a1c0cSantos Cordon                    toneVolume = RELATIVE_VOLUME_HIPRI;
13240f78c210512570f14cdfde9613dd85c510a1c0cSantos Cordon                    toneLengthMillis = Integer.MAX_VALUE - TIMEOUT_BUFFER_MILLIS;
13340f78c210512570f14cdfde9613dd85c510a1c0cSantos Cordon                    break;
134c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon                case TONE_CDMA_DROP:
135c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon                    toneType = ToneGenerator.TONE_CDMA_CALLDROP_LITE;
136c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon                    toneVolume = RELATIVE_VOLUME_LOPRI;
1378c85dee84fbbd8c36cf1c7b061001c6129623f92Sailesh Nepal                    toneLengthMillis = 375;
138c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon                    break;
139c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon                case TONE_CONGESTION:
140c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon                    toneType = ToneGenerator.TONE_SUP_CONGESTION;
141c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon                    toneVolume = RELATIVE_VOLUME_HIPRI;
1428c85dee84fbbd8c36cf1c7b061001c6129623f92Sailesh Nepal                    toneLengthMillis = 4000;
143c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon                    break;
144c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon                case TONE_INTERCEPT:
145c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon                    toneType = ToneGenerator.TONE_CDMA_ABBR_INTERCEPT;
146c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon                    toneVolume = RELATIVE_VOLUME_LOPRI;
1478c85dee84fbbd8c36cf1c7b061001c6129623f92Sailesh Nepal                    toneLengthMillis = 500;
148c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon                    break;
149c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon                case TONE_OUT_OF_SERVICE:
150c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon                    toneType = ToneGenerator.TONE_CDMA_CALLDROP_LITE;
151c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon                    toneVolume = RELATIVE_VOLUME_LOPRI;
1528c85dee84fbbd8c36cf1c7b061001c6129623f92Sailesh Nepal                    toneLengthMillis = 375;
153c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon                    break;
154c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon                case TONE_REDIAL:
155c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon                    toneType = ToneGenerator.TONE_CDMA_ALERT_AUTOREDIAL_LITE;
156c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon                    toneVolume = RELATIVE_VOLUME_LOPRI;
1578c85dee84fbbd8c36cf1c7b061001c6129623f92Sailesh Nepal                    toneLengthMillis = 5000;
158c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon                    break;
159c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon                case TONE_REORDER:
160c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon                    toneType = ToneGenerator.TONE_CDMA_REORDER;
161c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon                    toneVolume = RELATIVE_VOLUME_HIPRI;
1627062bb96f567e7dc9c7bf933b7bee17bb2c8108cYorke Lee                    toneLengthMillis = 4000;
163c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon                    break;
164a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon                case TONE_RING_BACK:
165a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon                    toneType = ToneGenerator.TONE_SUP_RINGTONE;
166a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon                    toneVolume = RELATIVE_VOLUME_HIPRI;
1678c85dee84fbbd8c36cf1c7b061001c6129623f92Sailesh Nepal                    toneLengthMillis = Integer.MAX_VALUE - TIMEOUT_BUFFER_MILLIS;
168a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon                    break;
169c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon                case TONE_UNOBTAINABLE_NUMBER:
170c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon                    toneType = ToneGenerator.TONE_SUP_ERROR;
171c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon                    toneVolume = RELATIVE_VOLUME_HIPRI;
1728c85dee84fbbd8c36cf1c7b061001c6129623f92Sailesh Nepal                    toneLengthMillis = 4000;
173c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon                    break;
174c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon                case TONE_VOICE_PRIVACY:
175c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon                    // TODO: fill in.
176c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon                    throw new IllegalStateException("Voice privacy tone NYI.");
177a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon                default:
178a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon                    throw new IllegalStateException("Bad toneId: " + mToneId);
179a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon            }
180a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon
181a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon            int stream = AudioManager.STREAM_VOICE_CALL;
182c7e85d4fa0bb3325133a79d4c89f3149e0af430eSantos Cordon            if (mCallAudioManager.isBluetoothAudioOn()) {
183c7e85d4fa0bb3325133a79d4c89f3149e0af430eSantos Cordon                stream = AudioManager.STREAM_BLUETOOTH_SCO;
184c7e85d4fa0bb3325133a79d4c89f3149e0af430eSantos Cordon            }
185a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon
186a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon            // If the ToneGenerator creation fails, just continue without it. It is a local audio
187a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon            // signal, and is not as important.
188a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon            try {
189a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon                Log.v(this, "Creating generator");
190a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon                toneGenerator = new ToneGenerator(stream, toneVolume);
191a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon            } catch (RuntimeException e) {
192a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon                Log.w(this, "Failed to create ToneGenerator.", e);
193a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon                return;
194a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon            }
195a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon
196df39986de36d40aaa45e61d19a21eca536765ca5Santos Cordon            // TODO: Certain CDMA tones need to check the ringer-volume state before
197a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon            // playing. See CallNotifier.InCallTonePlayer.
198a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon
199df39986de36d40aaa45e61d19a21eca536765ca5Santos Cordon            // TODO: Some tones play through the end of a call so we need to inform
200a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon            // CallAudioManager that we want focus the same way that Ringer does.
201a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon
202a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon            synchronized (this) {
203a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon                if (mState != STATE_STOPPED) {
204a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon                    mState = STATE_ON;
205a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon                    toneGenerator.startTone(toneType);
206a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon                    try {
207a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon                        Log.v(this, "Starting tone %d...waiting for %d ms.", mToneId,
2088c85dee84fbbd8c36cf1c7b061001c6129623f92Sailesh Nepal                                toneLengthMillis + TIMEOUT_BUFFER_MILLIS);
2098c85dee84fbbd8c36cf1c7b061001c6129623f92Sailesh Nepal                        wait(toneLengthMillis + TIMEOUT_BUFFER_MILLIS);
210a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon                    } catch (InterruptedException e) {
211a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon                        Log.w(this, "wait interrupted", e);
212a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon                    }
213a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon                }
214a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon            }
215a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon            mState = STATE_OFF;
216a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon        } finally {
217a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon            if (toneGenerator != null) {
218a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon                toneGenerator.release();
219a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon            }
220a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon            cleanUpTonePlayer();
221a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon        }
222a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon    }
223a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon
224a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon    void startTone() {
225a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon        ThreadUtil.checkOnMainThread();
226a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon
227a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon        sTonesPlaying++;
228a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon        if (sTonesPlaying == 1) {
229a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon            mCallAudioManager.setIsTonePlaying(true);
230a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon        }
231a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon
232a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon        start();
233a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon    }
234a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon
235a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon    /**
236a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon     * Stops the tone.
237a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon     */
238a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon    void stopTone() {
239a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon        synchronized (this) {
240a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon            if (mState == STATE_ON) {
241a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon                Log.d(this, "Stopping the tone %d.", mToneId);
242a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon                notify();
243a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon            }
244a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon            mState = STATE_STOPPED;
245a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon        }
246a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon    }
247a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon
248a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon    private void cleanUpTonePlayer() {
249a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon        // Release focus on the main thread.
250a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon        mMainThreadHandler.post(new Runnable() {
251a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon            @Override public void run() {
252a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon                if (sTonesPlaying == 0) {
253a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon                    Log.wtf(this, "Over-releasing focus for tone player.");
254a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon                } else if (--sTonesPlaying == 0) {
255a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon                    mCallAudioManager.setIsTonePlaying(false);
256a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon                }
257a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon            }
258a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon        });
259a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon    }
260a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon}
261