Listen for ConnectionEvent and use the InCallToneMonitor to play the tone
BUG=25357778
Change-Id: Iad4f36f9b01670a2f188e726895a8349aeeb1502
diff --git a/src/com/android/server/telecom/Call.java b/src/com/android/server/telecom/Call.java
index 7b342bc..fc124a4 100644
--- a/src/com/android/server/telecom/Call.java
+++ b/src/com/android/server/telecom/Call.java
@@ -104,6 +104,7 @@
void onPhoneAccountChanged(Call call);
void onConferenceableCallsChanged(Call call);
boolean onCanceledViaNewOutgoingCallBroadcast(Call call);
+ void onHoldToneRequested(Call call);
}
public abstract static class ListenerBase implements Listener {
@@ -161,6 +162,9 @@
public boolean onCanceledViaNewOutgoingCallBroadcast(Call call) {
return false;
}
+
+ @Override
+ public void onHoldToneRequested(Call call) {}
}
private final OnQueryCompleteListener mCallerInfoQueryListener =
@@ -365,6 +369,14 @@
// Set to true once the NewOutgoingCallIntentBroadcast comes back and is processed.
private boolean mIsNewOutgoingCallIntentBroadcastDone = false;
+
+ /**
+ * Indicates whether the call is remotely held. A call is considered remotely held when
+ * {@link #onConnectionEvent(String)} receives the {@link Connection#EVENT_ON_HOLD_TONE_START}
+ * event.
+ */
+ private boolean mIsRemotelyHeld = false;
+
/**
* Persists the specified parameters and initializes the new instance.
*
@@ -1921,4 +1933,36 @@
public void setNewOutgoingCallIntentBroadcastIsDone() {
mIsNewOutgoingCallIntentBroadcastDone = true;
}
+
+ /**
+ * Determines if the call has been held by the remote party.
+ *
+ * @return {@code true} if the call is remotely held, {@code false} otherwise.
+ */
+ public boolean isRemotelyHeld() {
+ return mIsRemotelyHeld;
+ }
+
+ /**
+ * Handles Connection events received from a {@link ConnectionService}.
+ *
+ * @param event The event.
+ */
+ public void onConnectionEvent(String event) {
+ if (Connection.EVENT_ON_HOLD_TONE_START.equals(event)) {
+ mIsRemotelyHeld = true;
+ Log.event(this, Log.Events.REMOTELY_HELD);
+ // Inform listeners of the fact that a call hold tone was received. This will trigger
+ // the CallAudioManager to play a tone via the InCallTonePlayer.
+ for (Listener l : mListeners) {
+ l.onHoldToneRequested(this);
+ }
+ } else if (Connection.EVENT_ON_HOLD_TONE_END.equals(event)) {
+ mIsRemotelyHeld = false;
+ Log.event(this, Log.Events.REMOTELY_UNHELD);
+ for (Listener l : mListeners) {
+ l.onHoldToneRequested(this);
+ }
+ }
+ }
}
diff --git a/src/com/android/server/telecom/CallAudioManager.java b/src/com/android/server/telecom/CallAudioManager.java
index 1a5cc7b..07c1440 100644
--- a/src/com/android/server/telecom/CallAudioManager.java
+++ b/src/com/android/server/telecom/CallAudioManager.java
@@ -55,6 +55,7 @@
private Call mForegroundCall;
private boolean mIsTonePlaying = false;
+ private InCallTonePlayer mHoldTonePlayer;
public CallAudioManager(CallAudioRouteStateMachine callAudioRouteStateMachine,
CallsManager callsManager,
@@ -213,6 +214,19 @@
}
}
+ /**
+ * Play or stop a call hold tone for a call. Triggered via
+ * {@link Connection#sendConnectionEvent(String)} when the
+ * {@link Connection#EVENT_ON_HOLD_TONE_START} event or
+ * {@link Connection#EVENT_ON_HOLD_TONE_STOP} event is passed through to the
+ *
+ * @param call The call which requested the hold tone.
+ */
+ @Override
+ public void onHoldToneRequested(Call call) {
+ maybePlayHoldTone();
+ }
+
@Override
public void onIsVoipAudioModeChanged(Call call) {
if (call != mForegroundCall) {
@@ -486,6 +500,7 @@
if (mForegroundCall != oldForegroundCall) {
mDtmfLocalTonePlayer.onForegroundCallChanged(oldForegroundCall, mForegroundCall);
+ maybePlayHoldTone();
}
}
@@ -554,6 +569,51 @@
mRingbackPlayer.stopRingbackForCall(call);
}
+ /**
+ * Determines if a hold tone should be played and then starts or stops it accordingly.
+ */
+ private void maybePlayHoldTone() {
+ if (shouldPlayHoldTone()) {
+ if (mHoldTonePlayer == null) {
+ mHoldTonePlayer = mPlayerFactory.createPlayer(InCallTonePlayer.TONE_CALL_WAITING);
+ mHoldTonePlayer.start();
+ }
+ } else {
+ if (mHoldTonePlayer != null) {
+ mHoldTonePlayer.stopTone();
+ mHoldTonePlayer = null;
+ }
+ }
+ }
+
+ /**
+ * Determines if a hold tone should be played.
+ * A hold tone should be played only if foreground call is equals with call which is
+ * remotely held.
+ *
+ * @return {@code true} if the the hold tone should be played, {@code false} otherwise.
+ */
+ private boolean shouldPlayHoldTone() {
+ Call foregroundCall = getForegroundCall();
+ // If there is no foreground call, no hold tone should play.
+ if (foregroundCall == null) {
+ return false;
+ }
+
+ // If another call is ringing, no hold tone should play.
+ if (mCallsManager.hasRingingCall()) {
+ return false;
+ }
+
+ // If the foreground call isn't active, no hold tone should play. This might happen, for
+ // example, if the user puts a remotely held call on hold itself.
+ if (!foregroundCall.isActive()) {
+ return false;
+ }
+
+ return foregroundCall.isRemotelyHeld();
+ }
+
private void dumpCallsInCollection(IndentingPrintWriter pw, Collection<Call> calls) {
for (Call call : calls) {
if (call != null) pw.println(call.getId());
diff --git a/src/com/android/server/telecom/CallsManager.java b/src/com/android/server/telecom/CallsManager.java
index fbb35ba..ce18f8a 100644
--- a/src/com/android/server/telecom/CallsManager.java
+++ b/src/com/android/server/telecom/CallsManager.java
@@ -91,6 +91,7 @@
void onVideoStateChanged(Call call);
void onCanAddCallChanged(boolean canAddCall);
void onSessionModifyRequestReceived(Call call, VideoProfile videoProfile);
+ void onHoldToneRequested(Call call);
}
private static final String TAG = "CallsManager";
@@ -522,11 +523,25 @@
}
}
- @VisibleForTesting
public Collection<Call> getCalls() {
return Collections.unmodifiableCollection(mCalls);
}
+ /**
+ * Play or stop a call hold tone for a call. Triggered via
+ * {@link Connection#sendConnectionEvent(String)} when the
+ * {@link Connection#EVENT_ON_HOLD_TONE_START} event or
+ * {@link Connection#EVENT_ON_HOLD_TONE_STOP} event is passed through to the
+ *
+ * @param call The call which requested the hold tone.
+ */
+ @Override
+ public void onHoldToneRequested(Call call) {
+ for (CallsManagerListener listener : mListeners) {
+ listener.onHoldToneRequested(call);
+ }
+ }
+
@VisibleForTesting
public Call getForegroundCall() {
if (mCallAudioManager == null) {
diff --git a/src/com/android/server/telecom/CallsManagerListenerBase.java b/src/com/android/server/telecom/CallsManagerListenerBase.java
index 50716d5..71d6c53 100644
--- a/src/com/android/server/telecom/CallsManagerListenerBase.java
+++ b/src/com/android/server/telecom/CallsManagerListenerBase.java
@@ -80,4 +80,8 @@
public void onSessionModifyRequestReceived(Call call, VideoProfile videoProfile) {
}
+
+ @Override
+ public void onHoldToneRequested(Call call) {
+ }
}
diff --git a/src/com/android/server/telecom/ConnectionServiceWrapper.java b/src/com/android/server/telecom/ConnectionServiceWrapper.java
index 56fbd5c..1feb356 100644
--- a/src/com/android/server/telecom/ConnectionServiceWrapper.java
+++ b/src/com/android/server/telecom/ConnectionServiceWrapper.java
@@ -587,6 +587,23 @@
Log.endSession();
}
}
+
+ @Override
+ public void onConnectionEvent(String callId, String event) {
+ Log.startSession("CSW.oCE");
+ long token = Binder.clearCallingIdentity();
+ try {
+ synchronized (mLock) {
+ Call call = mCallIdMapper.getCall(callId);
+ if (call != null) {
+ call.onConnectionEvent(event);
+ }
+ }
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ Log.endSession();
+ }
+ }
}
private final Adapter mAdapter = new Adapter();
diff --git a/src/com/android/server/telecom/Log.java b/src/com/android/server/telecom/Log.java
index 5e2dc9d..8daf6c1 100644
--- a/src/com/android/server/telecom/Log.java
+++ b/src/com/android/server/telecom/Log.java
@@ -101,6 +101,8 @@
public static final String BLOCK_CHECK_INITIATED = "BLOCK_CHECK_INITIATED";
public static final String BLOCK_CHECK_TIMED_OUT = "BLOCK_CHECK_TIMED_OUT";
public static final String BLOCK_CHECK_FINISHED = "BLOCK_CHECK_FINISHED";
+ public static final String REMOTELY_HELD = "REMOTELY_HELD";
+ public static final String REMOTELY_UNHELD = "REMOTELY_UNHELD";
/**
* Maps from a request to a response. The same event could be listed as the