Add support for Emergency Tone on outgoing Cdma Calls.
Move the old Emergency Ringback code from CallNotifier to new
EmergencyTonePlayer class and invoke that class from CdmaConnection.
*Also removes non-functional ringback code from old codebase.
Bug: 17452018
Change-Id: I92081ecc683f6b354eeca539ec7f170e7a5cec71
diff --git a/src/com/android/phone/CallNotifier.java b/src/com/android/phone/CallNotifier.java
index 5380fa5..be1e3b2 100644
--- a/src/com/android/phone/CallNotifier.java
+++ b/src/com/android/phone/CallNotifier.java
@@ -91,10 +91,6 @@
private static final int DISPLAYINFO_NOTIFICATION_DONE = 24;
private static final int UPDATE_IN_CALL_NOTIFICATION = 27;
- // Emergency call related defines:
- private static final int EMERGENCY_TONE_OFF = 0;
- private static final int EMERGENCY_TONE_ALERT = 1;
- private static final int EMERGENCY_TONE_VIBRATE = 2;
private PhoneGlobals mApplication;
private CallManager mCM;
@@ -111,14 +107,6 @@
private boolean mVoicePrivacyState = false;
private boolean mIsCdmaRedialCall = false;
- // Emergency call tone and vibrate:
- private int mIsEmergencyToneOn;
- private int mCurrentEmergencyToneState = EMERGENCY_TONE_OFF;
- private EmergencyTonePlayerVibrator mEmergencyTonePlayerVibrator;
-
- // Ringback tone player
- private InCallTonePlayer mInCallRingbackTonePlayer;
-
// Cached AudioManager
private AudioManager mAudioManager;
@@ -253,11 +241,6 @@
}
break;
- case CallStateMonitor.PHONE_RINGBACK_TONE:
- // DISABLED. The Telecom and new ConnectionService layers are now responsible.
- // onRingbackTone((AsyncResult) msg.obj);
- break;
-
default:
// super.handleMessage(msg);
}
@@ -481,59 +464,11 @@
// make sure audio is in in-call mode now
PhoneUtils.setAudioMode(mCM);
}
-
- if (fgPhone.getPhoneType() == PhoneConstants.PHONE_TYPE_CDMA) {
- Connection c = fgPhone.getForegroundCall().getLatestConnection();
- if ((c != null) && (PhoneNumberUtils.isLocalEmergencyNumber(mApplication,
- c.getAddress()))) {
- if (VDBG) log("onPhoneStateChanged: it is an emergency call.");
- Call.State callState = fgPhone.getForegroundCall().getState();
- if (mEmergencyTonePlayerVibrator == null) {
- mEmergencyTonePlayerVibrator = new EmergencyTonePlayerVibrator();
- }
-
- if (callState == Call.State.DIALING || callState == Call.State.ALERTING) {
- mIsEmergencyToneOn = Settings.Global.getInt(
- mApplication.getContentResolver(),
- Settings.Global.EMERGENCY_TONE, EMERGENCY_TONE_OFF);
- if (mIsEmergencyToneOn != EMERGENCY_TONE_OFF &&
- mCurrentEmergencyToneState == EMERGENCY_TONE_OFF) {
- if (mEmergencyTonePlayerVibrator != null) {
- mEmergencyTonePlayerVibrator.start();
- }
- }
- } else if (callState == Call.State.ACTIVE) {
- if (mCurrentEmergencyToneState != EMERGENCY_TONE_OFF) {
- if (mEmergencyTonePlayerVibrator != null) {
- mEmergencyTonePlayerVibrator.stop();
- }
- }
- }
- }
- }
-
- if (fgPhone.getPhoneType() == PhoneConstants.PHONE_TYPE_GSM
- || fgPhone.getPhoneType() == PhoneConstants.PHONE_TYPE_SIP
- || fgPhone.getPhoneType() == PhoneConstants.PHONE_TYPE_IMS
- || fgPhone.getPhoneType() == PhoneConstants.PHONE_TYPE_THIRD_PARTY) {
- Call.State callState = mCM.getActiveFgCallState();
- if (!callState.isDialing()) {
- // If call gets activated or disconnected before the ringback
- // tone stops, we have to stop it to prevent disturbing.
- if (mInCallRingbackTonePlayer != null) {
- mInCallRingbackTonePlayer.stopTone();
- mInCallRingbackTonePlayer = null;
- }
- }
- }
}
void updateCallNotifierRegistrationsAfterRadioTechnologyChange() {
if (DBG) Log.d(LOG_TAG, "updateCallNotifierRegistrationsAfterRadioTechnologyChange...");
- // Clear ringback tone player
- mInCallRingbackTonePlayer = null;
-
// Instantiate mSignalInfoToneGenerator
createSignalInfoToneGenerator();
}
@@ -614,15 +549,6 @@
final boolean isEmergencyNumber =
PhoneNumberUtils.isLocalEmergencyNumber(mApplication, number);
- if (phone.getPhoneType() == PhoneConstants.PHONE_TYPE_CDMA) {
- if ((isEmergencyNumber)
- && (mCurrentEmergencyToneState != EMERGENCY_TONE_OFF)) {
- if (mEmergencyTonePlayerVibrator != null) {
- mEmergencyTonePlayerVibrator.stop();
- }
- }
- }
-
// Possibly play a "post-disconnect tone" thru the earpiece.
// We do this here, rather than from the InCallScreen
// activity, since we need to do this even if you're not in
@@ -750,7 +676,6 @@
public static final int TONE_OUT_OF_SERVICE = 9;
public static final int TONE_REDIAL = 10;
public static final int TONE_OTA_CALL_END = 11;
- public static final int TONE_RING_BACK = 12;
public static final int TONE_UNOBTAINABLE_NUMBER = 13;
// The tone volume relative to other sounds in the stream
@@ -855,12 +780,6 @@
toneVolume = TONE_RELATIVE_VOLUME_LOPRI;
toneLengthMillis = 5000;
break;
- case TONE_RING_BACK:
- toneType = ToneGenerator.TONE_SUP_RINGTONE;
- toneVolume = TONE_RELATIVE_VOLUME_HIPRI;
- // Call ring back tone is stopped by stopTone() method
- toneLengthMillis = Integer.MAX_VALUE - TONE_TIMEOUT_BUFFER;
- break;
case TONE_UNOBTAINABLE_NUMBER:
toneType = ToneGenerator.TONE_SUP_ERROR;
toneVolume = TONE_RELATIVE_VOLUME_HIPRI;
@@ -1107,78 +1026,7 @@
return mIsCdmaRedialCall;
}
- /**
- * Inner class to handle emergency call tone and vibrator
- */
- private class EmergencyTonePlayerVibrator {
- private final int EMG_VIBRATE_LENGTH = 1000; // ms.
- private final int EMG_VIBRATE_PAUSE = 1000; // ms.
- private final long[] mVibratePattern =
- new long[] { EMG_VIBRATE_LENGTH, EMG_VIBRATE_PAUSE };
-
- private ToneGenerator mToneGenerator;
- // We don't rely on getSystemService(Context.VIBRATOR_SERVICE) to make sure this vibrator
- // object will be isolated from others.
- private Vibrator mEmgVibrator = new SystemVibrator();
- private int mInCallVolume;
-
- /**
- * constructor
- */
- public EmergencyTonePlayerVibrator() {
- }
-
- /**
- * Start the emergency tone or vibrator.
- */
- private void start() {
- if (VDBG) log("call startEmergencyToneOrVibrate.");
- int ringerMode = mAudioManager.getRingerMode();
-
- if ((mIsEmergencyToneOn == EMERGENCY_TONE_ALERT) &&
- (ringerMode == AudioManager.RINGER_MODE_NORMAL)) {
- log("EmergencyTonePlayerVibrator.start(): emergency tone...");
- mToneGenerator = new ToneGenerator (AudioManager.STREAM_VOICE_CALL,
- InCallTonePlayer.TONE_RELATIVE_VOLUME_EMERGENCY);
- if (mToneGenerator != null) {
- mInCallVolume = mAudioManager.getStreamVolume(AudioManager.STREAM_VOICE_CALL);
- mAudioManager.setStreamVolume(AudioManager.STREAM_VOICE_CALL,
- mAudioManager.getStreamMaxVolume(AudioManager.STREAM_VOICE_CALL),
- 0);
- mToneGenerator.startTone(ToneGenerator.TONE_CDMA_EMERGENCY_RINGBACK);
- mCurrentEmergencyToneState = EMERGENCY_TONE_ALERT;
- }
- } else if (mIsEmergencyToneOn == EMERGENCY_TONE_VIBRATE) {
- log("EmergencyTonePlayerVibrator.start(): emergency vibrate...");
- if (mEmgVibrator != null) {
- mEmgVibrator.vibrate(mVibratePattern, 0, VIBRATION_ATTRIBUTES);
- mCurrentEmergencyToneState = EMERGENCY_TONE_VIBRATE;
- }
- }
- }
-
- /**
- * If the emergency tone is active, stop the tone or vibrator accordingly.
- */
- private void stop() {
- if (VDBG) log("call stopEmergencyToneOrVibrate.");
-
- if ((mCurrentEmergencyToneState == EMERGENCY_TONE_ALERT)
- && (mToneGenerator != null)) {
- mToneGenerator.stopTone();
- mToneGenerator.release();
- mAudioManager.setStreamVolume(AudioManager.STREAM_VOICE_CALL,
- mInCallVolume,
- 0);
- } else if ((mCurrentEmergencyToneState == EMERGENCY_TONE_VIBRATE)
- && (mEmgVibrator != null)) {
- mEmgVibrator.cancel();
- }
- mCurrentEmergencyToneState = EMERGENCY_TONE_OFF;
- }
- }
-
- private BluetoothProfile.ServiceListener mBluetoothProfileServiceListener =
+ private BluetoothProfile.ServiceListener mBluetoothProfileServiceListener =
new BluetoothProfile.ServiceListener() {
public void onServiceConnected(int profile, BluetoothProfile proxy) {
mBluetoothHeadset = (BluetoothHeadset) proxy;
@@ -1190,27 +1038,6 @@
}
};
- private void onRingbackTone(AsyncResult r) {
- boolean playTone = (Boolean)(r.result);
-
- if (playTone == true) {
- // Only play when foreground call is in DIALING or ALERTING.
- // to prevent a late coming playtone after ALERTING.
- // Don't play ringback tone if it is in play, otherwise it will cut
- // the current tone and replay it
- if (mCM.getActiveFgCallState().isDialing() &&
- mInCallRingbackTonePlayer == null) {
- mInCallRingbackTonePlayer = new InCallTonePlayer(InCallTonePlayer.TONE_RING_BACK);
- mInCallRingbackTonePlayer.start();
- }
- } else {
- if (mInCallRingbackTonePlayer != null) {
- mInCallRingbackTonePlayer.stopTone();
- mInCallRingbackTonePlayer = null;
- }
- }
- }
-
private void log(String msg) {
Log.d(LOG_TAG, msg);
}
diff --git a/src/com/android/services/telephony/CdmaConnection.java b/src/com/android/services/telephony/CdmaConnection.java
index a56205a..5d470ab 100644
--- a/src/com/android/services/telephony/CdmaConnection.java
+++ b/src/com/android/services/telephony/CdmaConnection.java
@@ -22,10 +22,12 @@
import android.provider.Settings;
import android.telecom.PhoneCapabilities;
import android.telephony.DisconnectCause;
+import android.telephony.PhoneNumberUtils;
import com.android.internal.telephony.Call;
import com.android.internal.telephony.CallStateException;
import com.android.internal.telephony.Connection;
+import com.android.internal.telephony.Phone;
import com.android.phone.Constants;
import java.util.LinkedList;
@@ -66,13 +68,20 @@
private final boolean mIsOutgoing;
// Queue of pending short-DTMF characters.
private final Queue<Character> mDtmfQueue = new LinkedList<>();
+ private final EmergencyTonePlayer mEmergencyTonePlayer;
// Indicates that the DTMF confirmation from telephony is pending.
private boolean mDtmfBurstConfirmationPending = false;
private boolean mIsCallWaiting;
- CdmaConnection(Connection connection, boolean allowMute, boolean isOutgoing) {
+ CdmaConnection(
+ Connection connection,
+ EmergencyTonePlayer emergencyTonePlayer,
+ boolean allowMute,
+ boolean isOutgoing) {
+
super(connection);
+ mEmergencyTonePlayer = emergencyTonePlayer;
mAllowMute = allowMute;
mIsOutgoing = isOutgoing;
mIsCallWaiting = connection != null && connection.getState() == Call.State.WAITING;
@@ -133,6 +142,16 @@
Connection originalConnection = getOriginalConnection();
mIsCallWaiting = originalConnection != null &&
originalConnection.getState() == Call.State.WAITING;
+
+ if (state == android.telecom.Connection.STATE_DIALING) {
+ if (isEmergency()) {
+ mEmergencyTonePlayer.start();
+ }
+ } else {
+ // No need to check if it is an emergency call, since it is a no-op if it isn't started.
+ mEmergencyTonePlayer.stop();
+ }
+
super.onStateChanged(state);
}
@@ -231,4 +250,11 @@
}
}
}
+
+ private boolean isEmergency() {
+ Phone phone = getPhone();
+ return phone != null &&
+ PhoneNumberUtils.isLocalEmergencyNumber(
+ phone.getContext(), getAddress().getSchemeSpecificPart());
+ }
}
diff --git a/src/com/android/services/telephony/EmergencyTonePlayer.java b/src/com/android/services/telephony/EmergencyTonePlayer.java
new file mode 100644
index 0000000..aaec24f
--- /dev/null
+++ b/src/com/android/services/telephony/EmergencyTonePlayer.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.services.telephony;
+
+import android.content.Context;
+import android.media.AudioAttributes;
+import android.media.AudioManager;
+import android.media.ToneGenerator;
+import android.os.SystemVibrator;
+import android.os.Vibrator;
+import android.provider.Settings;
+
+/**
+ * Plays an emergency tone when placing emergency calls on CDMA devices.
+ */
+class EmergencyTonePlayer {
+
+ private static final int EMERGENCY_TONE_OFF = 0;
+ private static final int EMERGENCY_TONE_ALERT = 1;
+ private static final int EMERGENCY_TONE_VIBRATE = 2;
+
+ private static final int ALERT_RELATIVE_VOLUME_PERCENT = 100;
+
+ private static final int VIBRATE_LENGTH_MILLIS = 1000;
+ private static final int VIBRATE_PAUSE_MILLIS = 1000;
+ private static final long[] VIBRATE_PATTERN =
+ new long[] { VIBRATE_LENGTH_MILLIS, VIBRATE_PAUSE_MILLIS};
+
+ private static final AudioAttributes VIBRATION_ATTRIBUTES =
+ new AudioAttributes.Builder()
+ .setContentType(AudioAttributes.CONTENT_TYPE_SPEECH)
+ .setUsage(AudioAttributes.USAGE_VOICE_COMMUNICATION)
+ .build();
+
+ // We don't rely on getSystemService(Context.VIBRATOR_SERVICE) to make sure that this vibrator
+ // object will be isolated from others.
+ private final Vibrator mVibrator = new SystemVibrator();
+ private final Context mContext;
+ private final AudioManager mAudioManager;
+
+ private ToneGenerator mToneGenerator;
+ private int mSavedInCallVolume;
+ private boolean mIsVibrating = false;
+
+ EmergencyTonePlayer(Context context) {
+ mContext = context;
+ mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
+ }
+
+ public void start() {
+ switch (getToneSetting()) {
+ case EMERGENCY_TONE_VIBRATE:
+ startVibrate();
+ break;
+ case EMERGENCY_TONE_ALERT:
+ // Only start if we are not in silent mode.
+ int ringerMode = mAudioManager.getRingerMode();
+ if (ringerMode == AudioManager.RINGER_MODE_NORMAL) {
+ startAlert();
+ }
+ break;
+ case EMERGENCY_TONE_OFF:
+ // nothing;
+ break;
+ }
+ }
+
+ public void stop() {
+ stopVibrate();
+ stopAlert();
+ }
+
+ private void startVibrate() {
+ if (!mIsVibrating) {
+ mVibrator.vibrate(VIBRATE_PATTERN, 0, VIBRATION_ATTRIBUTES);
+ mIsVibrating = true;
+ }
+ }
+
+ private void stopVibrate() {
+ if (mIsVibrating) {
+ mVibrator.cancel();
+ mIsVibrating = false;
+ }
+ }
+
+ private void startAlert() {
+ if (mToneGenerator == null) {
+ mToneGenerator = new ToneGenerator(
+ AudioManager.STREAM_VOICE_CALL, ALERT_RELATIVE_VOLUME_PERCENT);
+
+ // Set the volume to max and save the old volume setting.
+ mSavedInCallVolume = mAudioManager.getStreamVolume(AudioManager.STREAM_VOICE_CALL);
+ mAudioManager.setStreamVolume(
+ AudioManager.STREAM_VOICE_CALL,
+ mAudioManager.getStreamMaxVolume(AudioManager.STREAM_VOICE_CALL),
+ 0);
+ mToneGenerator.startTone(ToneGenerator.TONE_CDMA_EMERGENCY_RINGBACK);
+ } else {
+ Log.d(this, "An alert is already running.");
+ }
+ }
+
+ private void stopAlert() {
+ if (mToneGenerator != null) {
+ mToneGenerator.stopTone();
+ mToneGenerator.release();
+ mToneGenerator = null;
+
+ mAudioManager.setStreamVolume(AudioManager.STREAM_VOICE_CALL, mSavedInCallVolume, 0);
+ mSavedInCallVolume = 0;
+ }
+ }
+
+ private int getToneSetting() {
+ return Settings.Global.getInt(
+ mContext.getContentResolver(), Settings.Global.EMERGENCY_TONE, EMERGENCY_TONE_OFF);
+ }
+}
diff --git a/src/com/android/services/telephony/TelephonyConnectionService.java b/src/com/android/services/telephony/TelephonyConnectionService.java
index 5935765..cb7894c 100644
--- a/src/com/android/services/telephony/TelephonyConnectionService.java
+++ b/src/com/android/services/telephony/TelephonyConnectionService.java
@@ -52,11 +52,13 @@
new CdmaConferenceController(this);
private ComponentName mExpectedComponentName = null;
private EmergencyCallHelper mEmergencyCallHelper;
+ private EmergencyTonePlayer mEmergencyTonePlayer;
@Override
public void onCreate() {
super.onCreate();
mExpectedComponentName = new ComponentName(this, this.getClass());
+ mEmergencyTonePlayer = new EmergencyTonePlayer(this);
}
@Override
@@ -290,8 +292,8 @@
return connection;
} else if (phoneType == TelephonyManager.PHONE_TYPE_CDMA) {
boolean allowMute = allowMute(phone);
- CdmaConnection connection =
- new CdmaConnection(originalConnection, allowMute, isOutgoing);
+ CdmaConnection connection = new CdmaConnection(
+ originalConnection, mEmergencyTonePlayer, allowMute, isOutgoing);
mCdmaConferenceController.add(connection);
return connection;
} else {