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;
23a3eccfee788c3ac3c831a443b085b141b39bb63dBrad Ebingerimport android.telecom.Log;
24a3eccfee788c3ac3c831a443b085b141b39bb63dBrad Ebingerimport android.telecom.Logging.Runnable;
25a3eccfee788c3ac3c831a443b085b141b39bb63dBrad Ebingerimport android.telecom.Logging.Session;
26a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon
27d931a017a0abea32ad4485a91402b5f62b9ddb0eBrad Ebingerimport com.android.internal.annotations.VisibleForTesting;
28d931a017a0abea32ad4485a91402b5f62b9ddb0eBrad Ebinger
29a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon/**
30a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon * Play a call-related tone (ringback, busy signal, etc.) through ToneGenerator. To use, create an
31a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon * instance using InCallTonePlayer.Factory (passing in the TONE_* constant for the tone you want)
32a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon * and start() it. Implemented on top of {@link Thread} so that the tone plays in its own thread.
33a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon */
34d931a017a0abea32ad4485a91402b5f62b9ddb0eBrad Ebingerpublic class InCallTonePlayer extends Thread {
35a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon
36a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon    /**
37a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon     * Factory used to create InCallTonePlayers. Exists to aid with testing mocks.
38a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon     */
39a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon    public static class Factory {
40e091ab90e37845cf4771051a6d2ce0ebadee4fe7Hall Liu        private CallAudioManager mCallAudioManager;
41f62630a57de0d52be2bdbc92a9bf8f305cc0892dHall Liu        private final CallAudioRoutePeripheralAdapter mCallAudioRoutePeripheralAdapter;
42abcbce4441720c52a443d292d5adc2d95f446494Ihab Awad        private final TelecomSystem.SyncRoot mLock;
437bba1112556e122254013562650aac6a6af80ac6Brad Ebinger        private final ToneGeneratorFactory mToneGeneratorFactory;
44a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon
45e091ab90e37845cf4771051a6d2ce0ebadee4fe7Hall Liu        Factory(CallAudioRoutePeripheralAdapter callAudioRoutePeripheralAdapter,
467bba1112556e122254013562650aac6a6af80ac6Brad Ebinger                TelecomSystem.SyncRoot lock, ToneGeneratorFactory toneGeneratorFactory) {
47f62630a57de0d52be2bdbc92a9bf8f305cc0892dHall Liu            mCallAudioRoutePeripheralAdapter = callAudioRoutePeripheralAdapter;
48abcbce4441720c52a443d292d5adc2d95f446494Ihab Awad            mLock = lock;
497bba1112556e122254013562650aac6a6af80ac6Brad Ebinger            mToneGeneratorFactory = toneGeneratorFactory;
50a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon        }
51a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon
52e091ab90e37845cf4771051a6d2ce0ebadee4fe7Hall Liu        public void setCallAudioManager(CallAudioManager callAudioManager) {
53e091ab90e37845cf4771051a6d2ce0ebadee4fe7Hall Liu            mCallAudioManager = callAudioManager;
54e091ab90e37845cf4771051a6d2ce0ebadee4fe7Hall Liu        }
55e091ab90e37845cf4771051a6d2ce0ebadee4fe7Hall Liu
56d931a017a0abea32ad4485a91402b5f62b9ddb0eBrad Ebinger        public InCallTonePlayer createPlayer(int tone) {
57f62630a57de0d52be2bdbc92a9bf8f305cc0892dHall Liu            return new InCallTonePlayer(tone, mCallAudioManager,
587bba1112556e122254013562650aac6a6af80ac6Brad Ebinger                    mCallAudioRoutePeripheralAdapter, mLock, mToneGeneratorFactory);
59a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon        }
60a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon    }
61a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon
627bba1112556e122254013562650aac6a6af80ac6Brad Ebinger    public interface ToneGeneratorFactory {
637bba1112556e122254013562650aac6a6af80ac6Brad Ebinger        ToneGenerator get (int streamType, int volume);
647bba1112556e122254013562650aac6a6af80ac6Brad Ebinger    }
657bba1112556e122254013562650aac6a6af80ac6Brad Ebinger
66a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon    // The possible tones that we can play.
67c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon    public static final int TONE_INVALID = 0;
68c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon    public static final int TONE_BUSY = 1;
69c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon    public static final int TONE_CALL_ENDED = 2;
70c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon    public static final int TONE_OTA_CALL_ENDED = 3;
71c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon    public static final int TONE_CALL_WAITING = 4;
72c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon    public static final int TONE_CDMA_DROP = 5;
73c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon    public static final int TONE_CONGESTION = 6;
74c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon    public static final int TONE_INTERCEPT = 7;
75c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon    public static final int TONE_OUT_OF_SERVICE = 8;
76c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon    public static final int TONE_REDIAL = 9;
77c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon    public static final int TONE_REORDER = 10;
78c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon    public static final int TONE_RING_BACK = 11;
79c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon    public static final int TONE_UNOBTAINABLE_NUMBER = 12;
80c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon    public static final int TONE_VOICE_PRIVACY = 13;
8186014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn    public static final int TONE_VIDEO_UPGRADE = 14;
82a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon
83a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon    private static final int RELATIVE_VOLUME_EMERGENCY = 100;
84a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon    private static final int RELATIVE_VOLUME_HIPRI = 80;
85a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon    private static final int RELATIVE_VOLUME_LOPRI = 50;
86a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon
87a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon    // Buffer time (in msec) to add on to the tone timeout value. Needed mainly when the timeout
88a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon    // value for a tone is exact duration of the tone itself.
898c85dee84fbbd8c36cf1c7b061001c6129623f92Sailesh Nepal    private static final int TIMEOUT_BUFFER_MILLIS = 20;
90a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon
91a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon    // The tone state.
92a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon    private static final int STATE_OFF = 0;
93a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon    private static final int STATE_ON = 1;
94a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon    private static final int STATE_STOPPED = 2;
95a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon
96a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon    /**
97a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon     * Keeps count of the number of actively playing tones so that we can notify CallAudioManager
98a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon     * when we need focus and when it can be release. This should only be manipulated from the main
99a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon     * thread.
100a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon     */
101a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon    private static int sTonesPlaying = 0;
102a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon
103a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon    private final CallAudioManager mCallAudioManager;
104f62630a57de0d52be2bdbc92a9bf8f305cc0892dHall Liu    private final CallAudioRoutePeripheralAdapter mCallAudioRoutePeripheralAdapter;
105a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon
106a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon    private final Handler mMainThreadHandler = new Handler(Looper.getMainLooper());
107a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon
108a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon    /** The ID of the tone to play. */
109a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon    private final int mToneId;
110a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon
111a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon    /** Current state of the tone player. */
112a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon    private int mState;
113a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon
114abcbce4441720c52a443d292d5adc2d95f446494Ihab Awad    /** Telecom lock object. */
115abcbce4441720c52a443d292d5adc2d95f446494Ihab Awad    private final TelecomSystem.SyncRoot mLock;
116abcbce4441720c52a443d292d5adc2d95f446494Ihab Awad
117d8ca5458f6ee1d47098a5934ddcef7e24cb074a9Hall Liu    private Session mSession;
118d8ca5458f6ee1d47098a5934ddcef7e24cb074a9Hall Liu    private final Object mSessionLock = new Object();
119d8ca5458f6ee1d47098a5934ddcef7e24cb074a9Hall Liu
1207bba1112556e122254013562650aac6a6af80ac6Brad Ebinger    private final ToneGeneratorFactory mToneGenerator;
1217bba1112556e122254013562650aac6a6af80ac6Brad Ebinger
122a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon    /**
123a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon     * Initializes the tone player. Private; use the {@link Factory} to create tone players.
124a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon     *
125a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon     * @param toneId ID of the tone to play, see TONE_* constants.
126a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon     */
127abcbce4441720c52a443d292d5adc2d95f446494Ihab Awad    private InCallTonePlayer(
128abcbce4441720c52a443d292d5adc2d95f446494Ihab Awad            int toneId,
129abcbce4441720c52a443d292d5adc2d95f446494Ihab Awad            CallAudioManager callAudioManager,
130f62630a57de0d52be2bdbc92a9bf8f305cc0892dHall Liu            CallAudioRoutePeripheralAdapter callAudioRoutePeripheralAdapter,
1317bba1112556e122254013562650aac6a6af80ac6Brad Ebinger            TelecomSystem.SyncRoot lock,
1327bba1112556e122254013562650aac6a6af80ac6Brad Ebinger            ToneGeneratorFactory toneGeneratorFactory) {
133a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon        mState = STATE_OFF;
134a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon        mToneId = toneId;
135a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon        mCallAudioManager = callAudioManager;
136f62630a57de0d52be2bdbc92a9bf8f305cc0892dHall Liu        mCallAudioRoutePeripheralAdapter = callAudioRoutePeripheralAdapter;
137abcbce4441720c52a443d292d5adc2d95f446494Ihab Awad        mLock = lock;
1387bba1112556e122254013562650aac6a6af80ac6Brad Ebinger        mToneGenerator = toneGeneratorFactory;
139a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon    }
140a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon
141a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon    /** {@inheritDoc} */
142a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon    @Override
143a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon    public void run() {
144a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon        ToneGenerator toneGenerator = null;
145a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon        try {
146d8ca5458f6ee1d47098a5934ddcef7e24cb074a9Hall Liu            synchronized (mSessionLock) {
147d8ca5458f6ee1d47098a5934ddcef7e24cb074a9Hall Liu                if (mSession != null) {
148d8ca5458f6ee1d47098a5934ddcef7e24cb074a9Hall Liu                    Log.continueSession(mSession, "ICTP.r");
149d8ca5458f6ee1d47098a5934ddcef7e24cb074a9Hall Liu                    mSession = null;
150d8ca5458f6ee1d47098a5934ddcef7e24cb074a9Hall Liu                }
151d8ca5458f6ee1d47098a5934ddcef7e24cb074a9Hall Liu            }
152a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon            Log.d(this, "run(toneId = %s)", mToneId);
153a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon
154a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon            final int toneType;  // Passed to ToneGenerator.startTone.
155a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon            final int toneVolume;  // Passed to the ToneGenerator constructor.
1568c85dee84fbbd8c36cf1c7b061001c6129623f92Sailesh Nepal            final int toneLengthMillis;
157a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon
158a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon            switch (mToneId) {
159c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon                case TONE_BUSY:
160c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon                    // TODO: CDMA-specific tones
161c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon                    toneType = ToneGenerator.TONE_SUP_BUSY;
162c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon                    toneVolume = RELATIVE_VOLUME_HIPRI;
1638c85dee84fbbd8c36cf1c7b061001c6129623f92Sailesh Nepal                    toneLengthMillis = 4000;
164c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon                    break;
165c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon                case TONE_CALL_ENDED:
166c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon                    toneType = ToneGenerator.TONE_PROP_PROMPT;
167c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon                    toneVolume = RELATIVE_VOLUME_HIPRI;
1687062bb96f567e7dc9c7bf933b7bee17bb2c8108cYorke Lee                    toneLengthMillis = 200;
169c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon                    break;
170c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon                case TONE_OTA_CALL_ENDED:
171c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon                    // TODO: fill in
172c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon                    throw new IllegalStateException("OTA Call ended NYI.");
173c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon                case TONE_CALL_WAITING:
17440f78c210512570f14cdfde9613dd85c510a1c0cSantos Cordon                    toneType = ToneGenerator.TONE_SUP_CALL_WAITING;
17540f78c210512570f14cdfde9613dd85c510a1c0cSantos Cordon                    toneVolume = RELATIVE_VOLUME_HIPRI;
17640f78c210512570f14cdfde9613dd85c510a1c0cSantos Cordon                    toneLengthMillis = Integer.MAX_VALUE - TIMEOUT_BUFFER_MILLIS;
17740f78c210512570f14cdfde9613dd85c510a1c0cSantos Cordon                    break;
178c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon                case TONE_CDMA_DROP:
179c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon                    toneType = ToneGenerator.TONE_CDMA_CALLDROP_LITE;
180c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon                    toneVolume = RELATIVE_VOLUME_LOPRI;
1818c85dee84fbbd8c36cf1c7b061001c6129623f92Sailesh Nepal                    toneLengthMillis = 375;
182c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon                    break;
183c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon                case TONE_CONGESTION:
184c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon                    toneType = ToneGenerator.TONE_SUP_CONGESTION;
185c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon                    toneVolume = RELATIVE_VOLUME_HIPRI;
1868c85dee84fbbd8c36cf1c7b061001c6129623f92Sailesh Nepal                    toneLengthMillis = 4000;
187c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon                    break;
188c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon                case TONE_INTERCEPT:
189c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon                    toneType = ToneGenerator.TONE_CDMA_ABBR_INTERCEPT;
190c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon                    toneVolume = RELATIVE_VOLUME_LOPRI;
1918c85dee84fbbd8c36cf1c7b061001c6129623f92Sailesh Nepal                    toneLengthMillis = 500;
192c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon                    break;
193c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon                case TONE_OUT_OF_SERVICE:
194c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon                    toneType = ToneGenerator.TONE_CDMA_CALLDROP_LITE;
195c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon                    toneVolume = RELATIVE_VOLUME_LOPRI;
1968c85dee84fbbd8c36cf1c7b061001c6129623f92Sailesh Nepal                    toneLengthMillis = 375;
197c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon                    break;
198c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon                case TONE_REDIAL:
199c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon                    toneType = ToneGenerator.TONE_CDMA_ALERT_AUTOREDIAL_LITE;
200c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon                    toneVolume = RELATIVE_VOLUME_LOPRI;
2018c85dee84fbbd8c36cf1c7b061001c6129623f92Sailesh Nepal                    toneLengthMillis = 5000;
202c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon                    break;
203c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon                case TONE_REORDER:
204c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon                    toneType = ToneGenerator.TONE_CDMA_REORDER;
205c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon                    toneVolume = RELATIVE_VOLUME_HIPRI;
2067062bb96f567e7dc9c7bf933b7bee17bb2c8108cYorke Lee                    toneLengthMillis = 4000;
207c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon                    break;
208a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon                case TONE_RING_BACK:
209a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon                    toneType = ToneGenerator.TONE_SUP_RINGTONE;
210a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon                    toneVolume = RELATIVE_VOLUME_HIPRI;
2118c85dee84fbbd8c36cf1c7b061001c6129623f92Sailesh Nepal                    toneLengthMillis = Integer.MAX_VALUE - TIMEOUT_BUFFER_MILLIS;
212a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon                    break;
213c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon                case TONE_UNOBTAINABLE_NUMBER:
214c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon                    toneType = ToneGenerator.TONE_SUP_ERROR;
215c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon                    toneVolume = RELATIVE_VOLUME_HIPRI;
2168c85dee84fbbd8c36cf1c7b061001c6129623f92Sailesh Nepal                    toneLengthMillis = 4000;
217c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon                    break;
218c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon                case TONE_VOICE_PRIVACY:
219c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon                    // TODO: fill in.
220c7b8ebabf904aa70a7a2a2a0ad01883088c56180Santos Cordon                    throw new IllegalStateException("Voice privacy tone NYI.");
22186014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn                case TONE_VIDEO_UPGRADE:
22286014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn                    // Similar to the call waiting tone, but does not repeat.
22386014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn                    toneType = ToneGenerator.TONE_SUP_CALL_WAITING;
22486014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn                    toneVolume = RELATIVE_VOLUME_HIPRI;
22586014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn                    toneLengthMillis = 4000;
22686014fcf9ec86e198a1ebac7c46e0e5c630735d7Tyler Gunn                    break;
227a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon                default:
228a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon                    throw new IllegalStateException("Bad toneId: " + mToneId);
229a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon            }
230a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon
231a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon            int stream = AudioManager.STREAM_VOICE_CALL;
232f62630a57de0d52be2bdbc92a9bf8f305cc0892dHall Liu            if (mCallAudioRoutePeripheralAdapter.isBluetoothAudioOn()) {
233c7e85d4fa0bb3325133a79d4c89f3149e0af430eSantos Cordon                stream = AudioManager.STREAM_BLUETOOTH_SCO;
234c7e85d4fa0bb3325133a79d4c89f3149e0af430eSantos Cordon            }
235a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon
236a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon            // If the ToneGenerator creation fails, just continue without it. It is a local audio
237a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon            // signal, and is not as important.
238a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon            try {
239a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon                Log.v(this, "Creating generator");
2407bba1112556e122254013562650aac6a6af80ac6Brad Ebinger                toneGenerator = mToneGenerator.get(stream, toneVolume);
241a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon            } catch (RuntimeException e) {
242a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon                Log.w(this, "Failed to create ToneGenerator.", e);
243a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon                return;
244a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon            }
245a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon
246df39986de36d40aaa45e61d19a21eca536765ca5Santos Cordon            // TODO: Certain CDMA tones need to check the ringer-volume state before
247a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon            // playing. See CallNotifier.InCallTonePlayer.
248a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon
249df39986de36d40aaa45e61d19a21eca536765ca5Santos Cordon            // TODO: Some tones play through the end of a call so we need to inform
250a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon            // CallAudioManager that we want focus the same way that Ringer does.
251a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon
252a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon            synchronized (this) {
253a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon                if (mState != STATE_STOPPED) {
254a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon                    mState = STATE_ON;
255a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon                    toneGenerator.startTone(toneType);
256a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon                    try {
257a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon                        Log.v(this, "Starting tone %d...waiting for %d ms.", mToneId,
2588c85dee84fbbd8c36cf1c7b061001c6129623f92Sailesh Nepal                                toneLengthMillis + TIMEOUT_BUFFER_MILLIS);
2598c85dee84fbbd8c36cf1c7b061001c6129623f92Sailesh Nepal                        wait(toneLengthMillis + TIMEOUT_BUFFER_MILLIS);
260a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon                    } catch (InterruptedException e) {
261a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon                        Log.w(this, "wait interrupted", e);
262a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon                    }
263a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon                }
264a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon            }
265a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon            mState = STATE_OFF;
266a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon        } finally {
267a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon            if (toneGenerator != null) {
268a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon                toneGenerator.release();
269a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon            }
270a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon            cleanUpTonePlayer();
271efa8d2ad756e2ef5928bdf9171f52226096822ffBrad Ebinger            Log.endSession();
272a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon        }
273a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon    }
274d931a017a0abea32ad4485a91402b5f62b9ddb0eBrad Ebinger
275d931a017a0abea32ad4485a91402b5f62b9ddb0eBrad Ebinger    @VisibleForTesting
276d931a017a0abea32ad4485a91402b5f62b9ddb0eBrad Ebinger    public void startTone() {
277a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon        sTonesPlaying++;
278a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon        if (sTonesPlaying == 1) {
279a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon            mCallAudioManager.setIsTonePlaying(true);
280a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon        }
281a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon
282d8ca5458f6ee1d47098a5934ddcef7e24cb074a9Hall Liu        synchronized (mSessionLock) {
283d8ca5458f6ee1d47098a5934ddcef7e24cb074a9Hall Liu            if (mSession != null) {
284d8ca5458f6ee1d47098a5934ddcef7e24cb074a9Hall Liu                Log.cancelSubsession(mSession);
285d8ca5458f6ee1d47098a5934ddcef7e24cb074a9Hall Liu            }
286d8ca5458f6ee1d47098a5934ddcef7e24cb074a9Hall Liu            mSession = Log.createSubsession();
287d8ca5458f6ee1d47098a5934ddcef7e24cb074a9Hall Liu        }
288d8ca5458f6ee1d47098a5934ddcef7e24cb074a9Hall Liu
289b626c02daaae6757299cdb2b8228ef0635b6b5ddHall Liu        super.start();
290b626c02daaae6757299cdb2b8228ef0635b6b5ddHall Liu    }
291b626c02daaae6757299cdb2b8228ef0635b6b5ddHall Liu
292b626c02daaae6757299cdb2b8228ef0635b6b5ddHall Liu    @Override
293b626c02daaae6757299cdb2b8228ef0635b6b5ddHall Liu    public void start() {
294b626c02daaae6757299cdb2b8228ef0635b6b5ddHall Liu        Log.w(this, "Do not call the start method directly; use startTone instead.");
295a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon    }
296a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon
297a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon    /**
298a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon     * Stops the tone.
299a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon     */
300d931a017a0abea32ad4485a91402b5f62b9ddb0eBrad Ebinger    @VisibleForTesting
301d931a017a0abea32ad4485a91402b5f62b9ddb0eBrad Ebinger    public void stopTone() {
302a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon        synchronized (this) {
303a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon            if (mState == STATE_ON) {
304a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon                Log.d(this, "Stopping the tone %d.", mToneId);
305a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon                notify();
306a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon            }
307a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon            mState = STATE_STOPPED;
308a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon        }
309a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon    }
310a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon
311a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon    private void cleanUpTonePlayer() {
312a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon        // Release focus on the main thread.
313f5e066609d0acc7ff53752bd6b9e3f2634bd0746Brad Ebinger        mMainThreadHandler.post(new Runnable("ICTP.cUTP", mLock) {
314e62e9e83a17824b8e2057be35c2adcca20af9e35Brad Ebinger            @Override
315e62e9e83a17824b8e2057be35c2adcca20af9e35Brad Ebinger            public void loggedRun() {
316f5e066609d0acc7ff53752bd6b9e3f2634bd0746Brad Ebinger                if (sTonesPlaying == 0) {
317f5e066609d0acc7ff53752bd6b9e3f2634bd0746Brad Ebinger                    Log.wtf(this, "Over-releasing focus for tone player.");
318f5e066609d0acc7ff53752bd6b9e3f2634bd0746Brad Ebinger                } else if (--sTonesPlaying == 0) {
319f5e066609d0acc7ff53752bd6b9e3f2634bd0746Brad Ebinger                    mCallAudioManager.setIsTonePlaying(false);
320a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon                }
321a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon            }
322e62e9e83a17824b8e2057be35c2adcca20af9e35Brad Ebinger        }.prepare());
323a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon    }
324a56f276cafcad80ab3a28996b6a0d72cffa4b2bcSantos Cordon}
325