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 {