1/*
2 * Copyright (C) 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.services.telephony;
18
19import static android.media.AudioManager.RINGER_MODE_NORMAL;
20import static android.media.AudioManager.RINGER_MODE_SILENT;
21
22import android.content.Context;
23import android.media.AudioAttributes;
24import android.media.AudioManager;
25import android.media.ToneGenerator;
26import android.os.SystemVibrator;
27import android.os.Vibrator;
28import android.provider.Settings;
29
30/**
31 * Plays an emergency tone when placing emergency calls on CDMA devices.
32 */
33class EmergencyTonePlayer {
34
35    private static final int EMERGENCY_TONE_OFF = 0;
36    private static final int EMERGENCY_TONE_ALERT = 1;
37    private static final int EMERGENCY_TONE_VIBRATE = 2;
38
39    private static final int ALERT_RELATIVE_VOLUME_PERCENT = 100;
40
41    private static final int VIBRATE_LENGTH_MILLIS = 1000;
42    private static final int VIBRATE_PAUSE_MILLIS = 1000;
43    private static final long[] VIBRATE_PATTERN =
44            new long[] { VIBRATE_LENGTH_MILLIS, VIBRATE_PAUSE_MILLIS};
45
46    private static final AudioAttributes VIBRATION_ATTRIBUTES =
47            new AudioAttributes.Builder()
48                .setContentType(AudioAttributes.CONTENT_TYPE_SPEECH)
49                .setUsage(AudioAttributes.USAGE_VOICE_COMMUNICATION)
50                .build();
51
52    // We don't rely on getSystemService(Context.VIBRATOR_SERVICE) to make sure that this vibrator
53    // object will be isolated from others.
54    private final Vibrator mVibrator = new SystemVibrator();
55    private final Context mContext;
56    private final AudioManager mAudioManager;
57
58    private ToneGenerator mToneGenerator;
59    private int mSavedInCallVolume;
60    private boolean mIsVibrating = false;
61
62    EmergencyTonePlayer(Context context) {
63        mContext = context;
64        mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
65    }
66
67    public void start() {
68        switch (getToneSetting()) {
69            case EMERGENCY_TONE_VIBRATE:
70                startVibrate();
71                break;
72            case EMERGENCY_TONE_ALERT:
73                startAlert();
74                break;
75            case EMERGENCY_TONE_OFF:
76                // nothing;
77                break;
78        }
79    }
80
81    public void stop() {
82        stopVibrate();
83        stopAlert();
84    }
85
86    private void startVibrate() {
87        int ringerMode = mAudioManager.getRingerMode();
88        if (ringerMode == RINGER_MODE_SILENT) {
89            Log.i(this, "startVibrate: skipping vibrate tone due to ringer mode %d", ringerMode);
90            return;
91        }
92
93        if (!mIsVibrating) {
94            mVibrator.vibrate(VIBRATE_PATTERN, 0, VIBRATION_ATTRIBUTES);
95            mIsVibrating = true;
96        }
97    }
98
99    private void stopVibrate() {
100        if (mIsVibrating) {
101            mVibrator.cancel();
102            mIsVibrating = false;
103        }
104    }
105
106    private void startAlert() {
107        int ringerMode = mAudioManager.getRingerMode();
108        if (ringerMode != RINGER_MODE_NORMAL) {
109            Log.i(this, "startAlert: skipping emergency tone due to ringer mode %d", ringerMode);
110            return;
111        }
112
113        if (mToneGenerator == null) {
114            mToneGenerator = new ToneGenerator(
115                    AudioManager.STREAM_VOICE_CALL, ALERT_RELATIVE_VOLUME_PERCENT);
116
117            // Set the volume to max and save the old volume setting.
118            mSavedInCallVolume = mAudioManager.getStreamVolume(AudioManager.STREAM_VOICE_CALL);
119            mAudioManager.setStreamVolume(
120                    AudioManager.STREAM_VOICE_CALL,
121                    mAudioManager.getStreamMaxVolume(AudioManager.STREAM_VOICE_CALL),
122                    0);
123            mToneGenerator.startTone(ToneGenerator.TONE_CDMA_EMERGENCY_RINGBACK);
124        }
125    }
126
127    private void stopAlert() {
128        if (mToneGenerator != null) {
129            mToneGenerator.stopTone();
130            mToneGenerator.release();
131            mToneGenerator = null;
132
133            mAudioManager.setStreamVolume(AudioManager.STREAM_VOICE_CALL, mSavedInCallVolume, 0);
134            mSavedInCallVolume = 0;
135        }
136    }
137
138    private int getToneSetting() {
139       return Settings.Global.getInt(
140               mContext.getContentResolver(), Settings.Global.EMERGENCY_TONE, EMERGENCY_TONE_OFF);
141    }
142}
143