Merge "Add notification cache for VoipCallMonitor to avoid match failure between notifications and calls." into udc-dev
diff --git a/src/com/android/server/telecom/CallsManager.java b/src/com/android/server/telecom/CallsManager.java
index 9503c10..e195fd2 100644
--- a/src/com/android/server/telecom/CallsManager.java
+++ b/src/com/android/server/telecom/CallsManager.java
@@ -3656,40 +3656,57 @@
* @param call The call.
*/
private void performRemoval(Call call) {
- mInCallController.getBindingFuture().thenRunAsync(() -> {
- call.maybeCleanupHandover();
- removeCall(call);
- Call foregroundCall = mCallAudioManager.getPossiblyHeldForegroundCall();
- if (mLocallyDisconnectingCalls.contains(call)) {
- boolean isDisconnectingChildCall = call.isDisconnectingChildCall();
- Log.v(this, "performRemoval: isDisconnectingChildCall = "
- + isDisconnectingChildCall + "call -> %s", call);
- mLocallyDisconnectingCalls.remove(call);
- // Auto-unhold the foreground call due to a locally disconnected call, except if the
- // call which was disconnected is a member of a conference (don't want to auto
- // un-hold the conference if we remove a member of the conference).
- if (!isDisconnectingChildCall && foregroundCall != null
- && foregroundCall.getState() == CallState.ON_HOLD) {
- foregroundCall.unhold();
- }
- } else if (foregroundCall != null &&
- !foregroundCall.can(Connection.CAPABILITY_SUPPORT_HOLD) &&
- foregroundCall.getState() == CallState.ON_HOLD) {
+ if (mInCallController.getBindingFuture() != null) {
+ mInCallController.getBindingFuture().thenRunAsync(() -> {
+ doRemoval(call);
+ }, new LoggedHandlerExecutor(mHandler, "CM.pR", mLock))
+ .exceptionally((throwable) -> {
+ Log.e(TAG, throwable, "Error while executing call removal");
+ mAnomalyReporter.reportAnomaly(CALL_REMOVAL_EXECUTION_ERROR_UUID,
+ CALL_REMOVAL_EXECUTION_ERROR_MSG);
+ return null;
+ });
+ } else {
+ doRemoval(call);
+ }
+ }
- // The new foreground call is on hold, however the carrier does not display the hold
- // button in the UI. Therefore, we need to auto unhold the held call since the user
- // has no means of unholding it themselves.
- Log.i(this, "performRemoval: Auto-unholding held foreground call (call doesn't "
- + "support hold)");
+ /**
+ * Code to perform removal of a call. Called above from {@link #performRemoval(Call)} either
+ * async (in live code) or sync (in testing).
+ * @param call the call to remove.
+ */
+ private void doRemoval(Call call) {
+ call.maybeCleanupHandover();
+ removeCall(call);
+ Call foregroundCall = mCallAudioManager.getPossiblyHeldForegroundCall();
+ if (mLocallyDisconnectingCalls.contains(call)) {
+ boolean isDisconnectingChildCall = call.isDisconnectingChildCall();
+ Log.v(this, "performRemoval: isDisconnectingChildCall = "
+ + isDisconnectingChildCall + "call -> %s", call);
+ mLocallyDisconnectingCalls.remove(call);
+ // Auto-unhold the foreground call due to a locally disconnected call, except if the
+ // call which was disconnected is a member of a conference (don't want to auto
+ // un-hold the conference if we remove a member of the conference).
+ // Also, ensure that the call we're removing is from the same ConnectionService as
+ // the one we're removing. We don't want to auto-unhold between ConnectionService
+ // implementations, especially if one is managed and the other is a VoIP CS.
+ if (!isDisconnectingChildCall && foregroundCall != null
+ && foregroundCall.getState() == CallState.ON_HOLD
+ && areFromSameSource(foregroundCall, call)) {
foregroundCall.unhold();
}
- }, new LoggedHandlerExecutor(mHandler, "CM.pR", mLock))
- .exceptionally((throwable) -> {
- Log.e(TAG, throwable, "Error while executing call removal");
- mAnomalyReporter.reportAnomaly(CALL_REMOVAL_EXECUTION_ERROR_UUID,
- CALL_REMOVAL_EXECUTION_ERROR_MSG);
- return null;
- });
+ } else if (foregroundCall != null &&
+ !foregroundCall.can(Connection.CAPABILITY_SUPPORT_HOLD) &&
+ foregroundCall.getState() == CallState.ON_HOLD) {
+
+ // The new foreground call is on hold, however the carrier does not display the hold
+ // button in the UI. Therefore, we need to auto unhold the held call since the user
+ // has no means of unholding it themselves.
+ Log.i(this, "performRemoval: Auto-unholding held foreground call (call doesn't "
+ + "support hold)");
+ foregroundCall.unhold();
+ }
}
/**
diff --git a/tests/src/com/android/server/telecom/tests/CallsManagerTest.java b/tests/src/com/android/server/telecom/tests/CallsManagerTest.java
index 7ea3568..129bba2 100644
--- a/tests/src/com/android/server/telecom/tests/CallsManagerTest.java
+++ b/tests/src/com/android/server/telecom/tests/CallsManagerTest.java
@@ -688,6 +688,54 @@
verify(heldCall).unhold(any());
}
+ /**
+ * Ensures we don't auto-unhold a call from a different app when we locally disconnect a call.
+ */
+ @SmallTest
+ @Test
+ public void testDontUnholdCallsBetweenConnectionServices() {
+ // GIVEN a CallsManager with ongoing call
+ Call ongoingCall = addSpyCall(SIM_1_HANDLE, CallState.ACTIVE);
+ when(ongoingCall.isDisconnectHandledViaFuture()).thenReturn(false);
+ doReturn(true).when(ongoingCall).can(Connection.CAPABILITY_HOLD);
+ doReturn(true).when(ongoingCall).can(Connection.CAPABILITY_SUPPORT_HOLD);
+ when(mConnectionSvrFocusMgr.getCurrentFocusCall()).thenReturn(ongoingCall);
+
+ // and a held call which has different ConnectionService
+ Call heldCall = addSpyCall(VOIP_1_HANDLE, CallState.ON_HOLD);
+
+ // Disconnect and cleanup the active ongoing call.
+ mCallsManager.disconnectCall(ongoingCall);
+ mCallsManager.markCallAsRemoved(ongoingCall);
+
+ // Should not unhold the held call since its in another app.
+ verify(heldCall, never()).unhold();
+ }
+
+ /**
+ * Ensures we do auto-unhold a call from the same app when we locally disconnect a call.
+ */
+ @SmallTest
+ @Test
+ public void testUnholdCallWhenDisconnectingInSameApp() {
+ // GIVEN a CallsManager with ongoing call
+ Call ongoingCall = addSpyCall(SIM_1_HANDLE, CallState.ACTIVE);
+ when(ongoingCall.isDisconnectHandledViaFuture()).thenReturn(false);
+ doReturn(true).when(ongoingCall).can(Connection.CAPABILITY_HOLD);
+ doReturn(true).when(ongoingCall).can(Connection.CAPABILITY_SUPPORT_HOLD);
+ when(mConnectionSvrFocusMgr.getCurrentFocusCall()).thenReturn(ongoingCall);
+
+ // and a held call which has same ConnectionService
+ Call heldCall = addSpyCall(SIM_1_HANDLE, CallState.ON_HOLD);
+
+ // Disconnect and cleanup the active ongoing call.
+ mCallsManager.disconnectCall(ongoingCall);
+ mCallsManager.markCallAsRemoved(ongoingCall);
+
+ // Should auto-unhold the held call since its in the same app.
+ verify(heldCall).unhold();
+ }
+
@SmallTest
@Test
public void testUnholdCallWhenOngoingEmergCallCanNotBeHeldAndFromDifferentConnectionService() {