summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--telecomm/java/android/telecom/Phone.java50
1 files changed, 48 insertions, 2 deletions
diff --git a/telecomm/java/android/telecom/Phone.java b/telecomm/java/android/telecom/Phone.java
index 95a8e16ace3d..fd2907c69d7a 100644
--- a/telecomm/java/android/telecom/Phone.java
+++ b/telecomm/java/android/telecom/Phone.java
@@ -32,8 +32,10 @@ import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
+import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.Executor;
+import java.util.concurrent.TimeUnit;
/**
* A unified virtual device providing a means of voice (and other) communication on a device.
@@ -148,6 +150,14 @@ public final class Phone {
private final Object mLock = new Object();
+ // Future used to delay terminating the InCallService before the call disconnect tone
+ // finishes playing.
+ private static Map<String, CompletableFuture<Void>> sDisconnectedToneFutures = new ArrayMap<>();
+
+ // Timeout value to be used to ensure future completion for sDisconnectedToneFutures. This is
+ // set to 4 seconds to account for the exceptional case (TONE_CONGESTION).
+ private static final int DISCONNECTED_TONE_TIMEOUT = 4000;
+
Phone(InCallAdapter adapter, String callingPackage, int targetSdkVersion) {
mInCallAdapter = adapter;
mCallingPackage = callingPackage;
@@ -456,9 +466,45 @@ public final class Phone {
}
private void fireCallRemoved(Call call) {
- for (Listener listener : mListeners) {
- listener.onCallRemoved(this, call);
+ String callId = call.internalGetCallId();
+ CompletableFuture<Void> disconnectedToneFuture = initializeDisconnectedToneFuture(callId);
+ // delay the InCallService termination until after the disconnect tone finishes playing
+ disconnectedToneFuture.thenRunAsync(() -> {
+ for (Listener listener : mListeners) {
+ listener.onCallRemoved(this, call);
+ }
+ // clean up the future after
+ sDisconnectedToneFutures.remove(callId);
+ });
+ }
+
+ /**
+ * Initialize disconnect tone future to be used in delaying ICS termination.
+ *
+ * @return CompletableFuture to delay InCallService termination until after the disconnect tone
+ * finishes playing. A timeout of 4s is used to handle the use case when we play
+ * TONE_CONGESTION and to ensure completion so that we don't block the removal of the service.
+ */
+ private CompletableFuture<Void> initializeDisconnectedToneFuture(String callId) {
+ // create the future and map (sDisconnectedToneFutures) it to the corresponding call id
+ CompletableFuture<Void> disconnectedToneFuture = new CompletableFuture<Void>()
+ .completeOnTimeout(null, DISCONNECTED_TONE_TIMEOUT, TimeUnit.MILLISECONDS);
+ // we should not encounter duplicate insertions since call ids are unique
+ sDisconnectedToneFutures.put(callId, disconnectedToneFuture);
+ return disconnectedToneFuture;
+ }
+
+ /**
+ * Completes disconnected tone future with passed in result.
+ * @hide
+ * @return true if future was completed, false otherwise
+ */
+ public static boolean completeDisconnectedToneFuture(String callId) {
+ if (sDisconnectedToneFutures.containsKey(callId)) {
+ sDisconnectedToneFutures.get(callId).complete(null);
+ return true;
}
+ return false;
}
private void fireCallAudioStateChanged(CallAudioState audioState) {