Add CallsManagerListener
Also contains some minor bug fixes:
- add an incoming field to Call
- correcty log failed outgoing calls (previously these were mostly dropped)
- log missed incoming calls
Change-Id: I72dc39efd519302c1f765f4f9c9d04c5095e45a6
diff --git a/src/com/android/telecomm/Ringer.java b/src/com/android/telecomm/Ringer.java
index bca0d15..bc24560 100644
--- a/src/com/android/telecomm/Ringer.java
+++ b/src/com/android/telecomm/Ringer.java
@@ -23,18 +23,18 @@
import android.media.MediaPlayer.OnPreparedListener;
import android.media.RingtoneManager;
import android.net.Uri;
+import android.telecomm.CallState;
import com.google.common.base.Preconditions;
+import com.google.common.collect.Lists;
import java.io.IOException;
+import java.util.List;
/**
* Controls ringing and vibration for incoming calls.
- *
- * TODO(santoscordon): Consider moving all ringing responsibility to InCall app as an implementation
- * within InCallServiceBase.
*/
-final class Ringer implements OnErrorListener, OnPreparedListener {
+final class Ringer extends CallsManagerListenerBase implements OnErrorListener, OnPreparedListener {
// States for the Ringer.
/** Actively playing the ringer. */
private static final int RINGING = 1;
@@ -56,11 +56,79 @@
/** The active media player for the ringer. */
private MediaPlayer mMediaPlayer;
+ /*
+ * Used to keep ordering of unanswered incoming calls. The existence of multiple call services
+ * means that there can easily exist multiple incoming calls and explicit ordering is useful for
+ * maintaining the proper state of the ringer.
+ */
+ private final List<String> mUnansweredCallIds = Lists.newLinkedList();
+
+ @Override
+ public void onCallAdded(Call call) {
+ if (call.isIncoming() && call.getState() == CallState.RINGING) {
+ if (mUnansweredCallIds.contains(call.getId())) {
+ Log.wtf(this, "New ringing call is already in list of unanswered calls");
+ }
+ mUnansweredCallIds.add(call.getId());
+ if (mUnansweredCallIds.size() == 1) {
+ // Start the ringer if we are the top-most incoming call (the only one in this
+ // case).
+ startRinging();
+ }
+ }
+ }
+
+ @Override
+ public void onCallRemoved(Call call) {
+ removeFromUnansweredCallIds(call.getId());
+ }
+
+ @Override
+ public void onCallStateChanged(Call call, CallState oldState, CallState newState) {
+ if (newState != CallState.RINGING) {
+ removeFromUnansweredCallIds(call.getId());
+ }
+ }
+
+ @Override
+ public void onIncomingCallAnswered(Call call) {
+ onRespondedToIncomingCall(call);
+ }
+
+ @Override
+ public void onIncomingCallRejected(Call call) {
+ onRespondedToIncomingCall(call);
+ }
+
+ private void onRespondedToIncomingCall(Call call) {
+ // Only stop the ringer if this call is the top-most incoming call.
+ if (!mUnansweredCallIds.isEmpty() && mUnansweredCallIds.get(0).equals(call.getId())) {
+ stopRinging();
+ }
+ }
+
+ /**
+ * Removes the specified call from the list of unanswered incoming calls and updates the ringer
+ * based on the new state of {@link #mUnansweredCallIds}. Safe to call with a call ID that
+ * is not present in the list of incoming calls.
+ *
+ * @param callId The ID of the call.
+ */
+ private void removeFromUnansweredCallIds(String callId) {
+ if (mUnansweredCallIds.remove(callId)) {
+ if (mUnansweredCallIds.isEmpty()) {
+ stopRinging();
+ } else {
+ startRinging();
+ }
+ }
+ }
+
/**
* Starts the vibration, ringer, and/or call-waiting tone.
* TODO(santoscordon): vibration and call-waiting tone.
*/
- void startRinging() {
+ private void startRinging() {
// Check if we are muted before playing the ringer.
if (getAudioManager().getStreamVolume(AudioManager.STREAM_RING) > 0) {
moveToState(RINGING);
@@ -72,7 +140,7 @@
/**
* Stops the vibration, ringer, and/or call-waiting tone.
*/
- void stopRinging() {
+ private void stopRinging() {
moveToState(STOPPED);
}