summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Pranav Madapurmath <pmadapurmath@google.com> 2023-01-09 23:26:14 +0000
committer Pranav Madapurmath <pmadapurmath@google.com> 2023-01-12 20:14:01 +0000
commit1cd2e8b3829a0f32041ecaab7037fbb5c1e799dc (patch)
treebb56df957638b1c10b372a80e05140d07c416d05
parent58495ae2418bb1108612d79fbd649ac6c797cc74 (diff)
Terminate ICS (for BT) after the disconnect tone finishes playing.
Currently, the disconnect tone and ICS termination occur independently so we run into a scenario where the disconnect tone never plays over BT (but we can hear the tone from the device). We can introduce a future to hold the connection until after the tone is done playing. The future can be configured to complete with a timeout of 4s (to account for the longest tone - TONE_CONGESTION) as a fallback. We can perform manual completion when we cleanup the tone player and in cases where we decide not to start the tone in the first place. This requires introducing the future into the framework as there is no other valid point of entry in the packages side. When we disconnect a call, InCallController#updateCall is invoked which ends up terminating the connection with the service. We cannot delay the workflow at this point since Dialer would need to be immediately informed when the call is being disconnected. Bug: 194979745 Test: Manual Change-Id: I5de05bcc38939d7ff3a710e847d8f33845b33706
-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) {