Merge "Add tones for call disconnection." into master-nova
diff --git a/src/com/android/telecomm/CallsManager.java b/src/com/android/telecomm/CallsManager.java
index a302c8d..b7f7aec 100644
--- a/src/com/android/telecomm/CallsManager.java
+++ b/src/com/android/telecomm/CallsManager.java
@@ -96,11 +96,14 @@
 
         mCallAudioManager = new CallAudioManager();
 
+        InCallTonePlayer.Factory playerFactory = new InCallTonePlayer.Factory(mCallAudioManager);
+
         mListeners.add(new CallLogManager(TelecommApp.getInstance()));
         mListeners.add(new PhoneStateBroadcaster());
         mListeners.add(new InCallController());
         mListeners.add(new Ringer(mCallAudioManager));
-        mListeners.add(new RingbackPlayer(this, new InCallTonePlayer.Factory(mCallAudioManager)));
+        mListeners.add(new RingbackPlayer(this, playerFactory));
+        mListeners.add(new InCallToneMonitor(playerFactory, this));
         mListeners.add(mCallAudioManager);
     }
 
diff --git a/src/com/android/telecomm/InCallToneMonitor.java b/src/com/android/telecomm/InCallToneMonitor.java
new file mode 100644
index 0000000..bafbfcc
--- /dev/null
+++ b/src/com/android/telecomm/InCallToneMonitor.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright 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.telecomm;
+
+import android.telecomm.CallAudioState;
+import android.telecomm.CallState;
+import android.telephony.DisconnectCause;
+
+import java.util.Collection;
+
+/**
+ * Monitors events from CallsManager and plays in-call tones for events which require them, such as
+ * different type of call disconnections (busy tone, congestion tone, etc).
+ */
+public final class InCallToneMonitor extends CallsManagerListenerBase {
+    private final InCallTonePlayer.Factory mPlayerFactory;
+
+    private final CallsManager mCallsManager;
+
+    InCallToneMonitor(InCallTonePlayer.Factory playerFactory, CallsManager callsManager) {
+        mPlayerFactory = playerFactory;
+        mCallsManager = callsManager;
+    }
+
+    @Override
+    public void onCallStateChanged(Call call, CallState oldState, CallState newState) {
+        if (mCallsManager.getForegroundCall() != call) {
+            // We only play tones for foreground calls.
+            return;
+        }
+
+        if (newState == CallState.DISCONNECTED) {
+            int toneToPlay = InCallTonePlayer.TONE_INVALID;
+
+            Log.v(this, "Disconnect cause: %d.", call.getDisconnectCause());
+
+            switch(call.getDisconnectCause()) {
+                case DisconnectCause.BUSY:
+                    toneToPlay = InCallTonePlayer.TONE_BUSY;
+                    break;
+                case DisconnectCause.CONGESTION:
+                    toneToPlay = InCallTonePlayer.TONE_CONGESTION;
+                    break;
+                case DisconnectCause.CDMA_REORDER:
+                    toneToPlay = InCallTonePlayer.TONE_REORDER;
+                    break;
+                case DisconnectCause.CDMA_INTERCEPT:
+                    toneToPlay = InCallTonePlayer.TONE_INTERCEPT;
+                    break;
+                case DisconnectCause.CDMA_DROP:
+                    toneToPlay = InCallTonePlayer.TONE_CDMA_DROP;
+                    break;
+                case DisconnectCause.OUT_OF_SERVICE:
+                    toneToPlay = InCallTonePlayer.TONE_OUT_OF_SERVICE;
+                    break;
+                case DisconnectCause.UNOBTAINABLE_NUMBER:
+                    toneToPlay = InCallTonePlayer.TONE_UNOBTAINABLE_NUMBER;
+                    break;
+                case DisconnectCause.ERROR_UNSPECIFIED:
+                    toneToPlay = InCallTonePlayer.TONE_CALL_ENDED;
+                    break;
+                case DisconnectCause.NORMAL:
+                case DisconnectCause.LOCAL:
+                    // Only play the disconnect sound on normal disconnects if there are no other
+                    // calls present beyond the one that is currently disconnected.
+                    Collection<Call> allCalls = mCallsManager.getCalls();
+                    if (allCalls.size() == 1) {
+                        if (!allCalls.contains(call)) {
+                            Log.wtf(this, "Disconnecting call not found %s.", call);
+                        }
+                        toneToPlay = InCallTonePlayer.TONE_CALL_ENDED;
+                    }
+                    break;
+            }
+
+            Log.d(this, "Found a disconnected call with tone to play %d.", toneToPlay);
+
+            if (toneToPlay != InCallTonePlayer.TONE_INVALID) {
+                mPlayerFactory.createPlayer(toneToPlay).startTone();
+            }
+        }
+    }
+}
diff --git a/src/com/android/telecomm/InCallTonePlayer.java b/src/com/android/telecomm/InCallTonePlayer.java
index c00e1cf..58e0423 100644
--- a/src/com/android/telecomm/InCallTonePlayer.java
+++ b/src/com/android/telecomm/InCallTonePlayer.java
@@ -44,10 +44,21 @@
     }
 
     // The possible tones that we can play.
-    public static final int TONE_NONE = 0;
-    public static final int TONE_RING_BACK = 1;
+    public static final int TONE_INVALID = 0;
+    public static final int TONE_BUSY = 1;
+    public static final int TONE_CALL_ENDED = 2;
+    public static final int TONE_OTA_CALL_ENDED = 3;
+    public static final int TONE_CALL_WAITING = 4;
+    public static final int TONE_CDMA_DROP = 5;
+    public static final int TONE_CONGESTION = 6;
+    public static final int TONE_INTERCEPT = 7;
+    public static final int TONE_OUT_OF_SERVICE = 8;
+    public static final int TONE_REDIAL = 9;
+    public static final int TONE_REORDER = 10;
+    public static final int TONE_RING_BACK = 11;
+    public static final int TONE_UNOBTAINABLE_NUMBER = 12;
+    public static final int TONE_VOICE_PRIVACY = 13;
 
-    // The tone volume relative to other sounds in the stream.
     private static final int RELATIVE_VOLUME_EMERGENCY = 100;
     private static final int RELATIVE_VOLUME_HIPRI = 80;
     private static final int RELATIVE_VOLUME_LOPRI = 50;
@@ -101,11 +112,66 @@
             final int toneLengthMs;
 
             switch (mToneId) {
+                case TONE_BUSY:
+                    // TODO: CDMA-specific tones
+                    toneType = ToneGenerator.TONE_SUP_BUSY;
+                    toneVolume = RELATIVE_VOLUME_HIPRI;
+                    toneLengthMs = 4000;
+                    break;
+                case TONE_CALL_ENDED:
+                    toneType = ToneGenerator.TONE_PROP_PROMPT;
+                    toneVolume = RELATIVE_VOLUME_HIPRI;
+                    toneLengthMs = 4000;
+                    break;
+                case TONE_OTA_CALL_ENDED:
+                    // TODO: fill in
+                    throw new IllegalStateException("OTA Call ended NYI.");
+                case TONE_CALL_WAITING:
+                    // TODO: fill in.
+                    throw new IllegalStateException("Call waiting NYI.");
+                case TONE_CDMA_DROP:
+                    toneType = ToneGenerator.TONE_CDMA_CALLDROP_LITE;
+                    toneVolume = RELATIVE_VOLUME_LOPRI;
+                    toneLengthMs = 375;
+                    break;
+                case TONE_CONGESTION:
+                    toneType = ToneGenerator.TONE_SUP_CONGESTION;
+                    toneVolume = RELATIVE_VOLUME_HIPRI;
+                    toneLengthMs = 4000;
+                    break;
+                case TONE_INTERCEPT:
+                    toneType = ToneGenerator.TONE_CDMA_ABBR_INTERCEPT;
+                    toneVolume = RELATIVE_VOLUME_LOPRI;
+                    toneLengthMs = 500;
+                    break;
+                case TONE_OUT_OF_SERVICE:
+                    toneType = ToneGenerator.TONE_CDMA_CALLDROP_LITE;
+                    toneVolume = RELATIVE_VOLUME_LOPRI;
+                    toneLengthMs = 375;
+                    break;
+                case TONE_REDIAL:
+                    toneType = ToneGenerator.TONE_CDMA_ALERT_AUTOREDIAL_LITE;
+                    toneVolume = RELATIVE_VOLUME_LOPRI;
+                    toneLengthMs = 5000;
+                    break;
+                case TONE_REORDER:
+                    toneType = ToneGenerator.TONE_CDMA_REORDER;
+                    toneVolume = RELATIVE_VOLUME_HIPRI;
+                    toneLengthMs = 5000;
+                    break;
                 case TONE_RING_BACK:
                     toneType = ToneGenerator.TONE_SUP_RINGTONE;
                     toneVolume = RELATIVE_VOLUME_HIPRI;
                     toneLengthMs = Integer.MAX_VALUE - TIMEOUT_BUFFER_MS;
                     break;
+                case TONE_UNOBTAINABLE_NUMBER:
+                    toneType = ToneGenerator.TONE_SUP_ERROR;
+                    toneVolume = RELATIVE_VOLUME_HIPRI;
+                    toneLengthMs = 4000;
+                    break;
+                case TONE_VOICE_PRIVACY:
+                    // TODO: fill in.
+                    throw new IllegalStateException("Voice privacy tone NYI.");
                 default:
                     throw new IllegalStateException("Bad toneId: " + mToneId);
             }