InCallTonePlayer.java revision 8c85dee84fbbd8c36cf1c7b061001c6129623f92
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
17a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordonpackage com.android.telecomm;
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;
1248c85dee84fbbd8c36cf1c7b061001c6129623f92Sailesh Nepal                    toneLengthMillis = 4000;
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:
130c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon                    // TODO: fill in.
131c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon                    throw new IllegalStateException("Call waiting NYI.");
132c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon                case TONE_CDMA_DROP:
133c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon                    toneType = ToneGenerator.TONE_CDMA_CALLDROP_LITE;
134c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon                    toneVolume = RELATIVE_VOLUME_LOPRI;
1358c85dee84fbbd8c36cf1c7b061001c6129623f92Sailesh Nepal                    toneLengthMillis = 375;
136c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon                    break;
137c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon                case TONE_CONGESTION:
138c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon                    toneType = ToneGenerator.TONE_SUP_CONGESTION;
139c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon                    toneVolume = RELATIVE_VOLUME_HIPRI;
1408c85dee84fbbd8c36cf1c7b061001c6129623f92Sailesh Nepal                    toneLengthMillis = 4000;
141c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon                    break;
142c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon                case TONE_INTERCEPT:
143c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon                    toneType = ToneGenerator.TONE_CDMA_ABBR_INTERCEPT;
144c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon                    toneVolume = RELATIVE_VOLUME_LOPRI;
1458c85dee84fbbd8c36cf1c7b061001c6129623f92Sailesh Nepal                    toneLengthMillis = 500;
146c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon                    break;
147c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon                case TONE_OUT_OF_SERVICE:
148c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon                    toneType = ToneGenerator.TONE_CDMA_CALLDROP_LITE;
149c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon                    toneVolume = RELATIVE_VOLUME_LOPRI;
1508c85dee84fbbd8c36cf1c7b061001c6129623f92Sailesh Nepal                    toneLengthMillis = 375;
151c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon                    break;
152c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon                case TONE_REDIAL:
153c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon                    toneType = ToneGenerator.TONE_CDMA_ALERT_AUTOREDIAL_LITE;
154c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon                    toneVolume = RELATIVE_VOLUME_LOPRI;
1558c85dee84fbbd8c36cf1c7b061001c6129623f92Sailesh Nepal                    toneLengthMillis = 5000;
156c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon                    break;
157c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon                case TONE_REORDER:
158c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon                    toneType = ToneGenerator.TONE_CDMA_REORDER;
159c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon                    toneVolume = RELATIVE_VOLUME_HIPRI;
1608c85dee84fbbd8c36cf1c7b061001c6129623f92Sailesh Nepal                    toneLengthMillis = 5000;
161c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon                    break;
162a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon                case TONE_RING_BACK:
163a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon                    toneType = ToneGenerator.TONE_SUP_RINGTONE;
164a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon                    toneVolume = RELATIVE_VOLUME_HIPRI;
1658c85dee84fbbd8c36cf1c7b061001c6129623f92Sailesh Nepal                    toneLengthMillis = Integer.MAX_VALUE - TIMEOUT_BUFFER_MILLIS;
166a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon                    break;
167c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon                case TONE_UNOBTAINABLE_NUMBER:
168c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon                    toneType = ToneGenerator.TONE_SUP_ERROR;
169c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon                    toneVolume = RELATIVE_VOLUME_HIPRI;
1708c85dee84fbbd8c36cf1c7b061001c6129623f92Sailesh Nepal                    toneLengthMillis = 4000;
171c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon                    break;
172c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon                case TONE_VOICE_PRIVACY:
173c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon                    // TODO: fill in.
174c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon                    throw new IllegalStateException("Voice privacy tone NYI.");
175a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon                default:
176a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon                    throw new IllegalStateException("Bad toneId: " + mToneId);
177a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon            }
178a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon
179a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon            // TODO(santoscordon): Bluetooth should be set manually (STREAM_BLUETOOTH_SCO) for tone
180a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon            // generator.
181a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon            int stream = AudioManager.STREAM_VOICE_CALL;
182a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon
183a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon            // If the ToneGenerator creation fails, just continue without it. It is a local audio
184a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon            // signal, and is not as important.
185a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon            try {
186a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon                Log.v(this, "Creating generator");
187a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon                toneGenerator = new ToneGenerator(stream, toneVolume);
188a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon            } catch (RuntimeException e) {
189a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon                Log.w(this, "Failed to create ToneGenerator.", e);
190a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon                return;
191a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon            }
192a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon
193a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon            // TODO(santoscordon): Certain CDMA tones need to check the ringer-volume state before
194a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon            // playing. See CallNotifier.InCallTonePlayer.
195a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon
196a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon            // TODO(santoscordon): Some tones play through the end of a call so we need to inform
197a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon            // CallAudioManager that we want focus the same way that Ringer does.
198a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon
199a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon            synchronized (this) {
200a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon                if (mState != STATE_STOPPED) {
201a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon                    mState = STATE_ON;
202a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon                    toneGenerator.startTone(toneType);
203a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon                    try {
204a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon                        Log.v(this, "Starting tone %d...waiting for %d ms.", mToneId,
2058c85dee84fbbd8c36cf1c7b061001c6129623f92Sailesh Nepal                                toneLengthMillis + TIMEOUT_BUFFER_MILLIS);
2068c85dee84fbbd8c36cf1c7b061001c6129623f92Sailesh Nepal                        wait(toneLengthMillis + TIMEOUT_BUFFER_MILLIS);
207a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon                    } catch (InterruptedException e) {
208a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon                        Log.w(this, "wait interrupted", e);
209a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon                    }
210a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon                }
211a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon            }
212a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon            mState = STATE_OFF;
213a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon        } finally {
214a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon            if (toneGenerator != null) {
215a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon                toneGenerator.release();
216a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon            }
217a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon            cleanUpTonePlayer();
218a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon        }
219a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon    }
220a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon
221a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon    void startTone() {
222a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon        ThreadUtil.checkOnMainThread();
223a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon
224a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon        sTonesPlaying++;
225a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon        if (sTonesPlaying == 1) {
226a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon            mCallAudioManager.setIsTonePlaying(true);
227a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon        }
228a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon
229a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon        start();
230a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon    }
231a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon
232a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon    /**
233a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon     * Stops the tone.
234a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon     */
235a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon    void stopTone() {
236a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon        synchronized (this) {
237a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon            if (mState == STATE_ON) {
238a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon                Log.d(this, "Stopping the tone %d.", mToneId);
239a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon                notify();
240a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon            }
241a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon            mState = STATE_STOPPED;
242a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon        }
243a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon    }
244a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon
245a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon    private void cleanUpTonePlayer() {
246a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon        // Release focus on the main thread.
247a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon        mMainThreadHandler.post(new Runnable() {
248a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon            @Override public void run() {
249a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon                if (sTonesPlaying == 0) {
250a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon                    Log.wtf(this, "Over-releasing focus for tone player.");
251a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon                } else if (--sTonesPlaying == 0) {
252a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon                    mCallAudioManager.setIsTonePlaying(false);
253a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon                }
254a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon            }
255a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon        });
256a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon    }
257a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon}
258