From 1a40c4f4daf2cdfba3f67383c726f93b85a98b00 Mon Sep 17 00:00:00 2001 From: Tyler Gunn Date: Thu, 14 Apr 2016 14:29:45 -0700 Subject: Improvements to external call handling. Add onExternalCallChanged listener in Call to report when a call switches between being external and not. In CallAudioManager, BluetoothPhoneServiceImpl, HeadsetMediaButton, and PhoneStateBroadcaster, listen to changes in the external call state. This ensures that when a call becomes external or a call becomes non-external that the various modules updates themselves appropriately. Bug: 28179159 Change-Id: I44bc0b94f185c66aeddb68549223533249bb0b62 --- .../server/telecom/BluetoothPhoneServiceImpl.java | 16 +++++++++ src/com/android/server/telecom/Call.java | 20 +++++++++-- .../android/server/telecom/CallAudioManager.java | 39 ++++++++++++++++++---- src/com/android/server/telecom/CallsManager.java | 32 +++++++++++++++++- .../server/telecom/CallsManagerListenerBase.java | 4 +++ .../android/server/telecom/HeadsetMediaButton.java | 13 ++++++++ .../android/server/telecom/InCallController.java | 9 +++-- .../server/telecom/PhoneStateBroadcaster.java | 21 ++++++++++++ 8 files changed, 143 insertions(+), 11 deletions(-) diff --git a/src/com/android/server/telecom/BluetoothPhoneServiceImpl.java b/src/com/android/server/telecom/BluetoothPhoneServiceImpl.java index 33ca5318..1fdd77f3 100644 --- a/src/com/android/server/telecom/BluetoothPhoneServiceImpl.java +++ b/src/com/android/server/telecom/BluetoothPhoneServiceImpl.java @@ -300,6 +300,22 @@ public class BluetoothPhoneServiceImpl { updateHeadsetWithCallState(false /* force */); } + /** + * Where a call which was external becomes a regular call, or a regular call becomes + * external, treat as an add or remove, respectively. + * + * @param call The call. + * @param isExternalCall {@code True} if the call became external, {@code false} otherwise. + */ + @Override + public void onExternalCallChanged(Call call, boolean isExternalCall) { + if (isExternalCall) { + onCallRemoved(call); + } else { + onCallAdded(call); + } + } + @Override public void onCallStateChanged(Call call, int oldState, int newState) { // If a call is being put on hold because of a new connecting call, ignore the diff --git a/src/com/android/server/telecom/Call.java b/src/com/android/server/telecom/Call.java index 33e3e4e4..010b8c27 100644 --- a/src/com/android/server/telecom/Call.java +++ b/src/com/android/server/telecom/Call.java @@ -43,9 +43,7 @@ import android.os.UserHandle; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telecom.IVideoProvider; import com.android.internal.telephony.CallerInfo; -import com.android.internal.telephony.CallerInfoAsyncQuery; import com.android.internal.telephony.SmsApplication; -import com.android.server.telecom.ContactsAsyncHelper.OnImageLoadCompleteListener; import com.android.internal.util.Preconditions; import java.lang.String; @@ -113,6 +111,7 @@ public class Call implements CreateConnectionResponse { boolean onCanceledViaNewOutgoingCallBroadcast(Call call); void onHoldToneRequested(Call call); void onConnectionEvent(Call call, String event, Bundle extras); + void onExternalCallChanged(Call call, boolean isExternalCall); } public abstract static class ListenerBase implements Listener { @@ -179,6 +178,8 @@ public class Call implements CreateConnectionResponse { public void onHoldToneRequested(Call call) {} @Override public void onConnectionEvent(Call call, String event, Bundle extras) {} + @Override + public void onExternalCallChanged(Call call, boolean isExternalCall) {} } private final CallerInfoLookupHelper.OnQueryCompleteListener mCallerInfoQueryListener = @@ -961,10 +962,25 @@ public class Call implements CreateConnectionResponse { Log.v(this, "setConnectionProperties: %s", Connection.propertiesToString( connectionProperties)); if (mConnectionProperties != connectionProperties) { + int previousProperties = mConnectionProperties; mConnectionProperties = connectionProperties; for (Listener l : mListeners) { l.onConnectionPropertiesChanged(this); } + + boolean wasExternal = (previousProperties & Connection.PROPERTY_IS_EXTERNAL_CALL) + == Connection.PROPERTY_IS_EXTERNAL_CALL; + boolean isExternal = (connectionProperties & Connection.PROPERTY_IS_EXTERNAL_CALL) + == Connection.PROPERTY_IS_EXTERNAL_CALL; + if (wasExternal != isExternal) { + Log.v(this, "setConnectionProperties: external call changed isExternal = %b", + isExternal); + + for (Listener l : mListeners) { + l.onExternalCallChanged(this, isExternal); + } + + } } } diff --git a/src/com/android/server/telecom/CallAudioManager.java b/src/com/android/server/telecom/CallAudioManager.java index 4d9fd08c..bf4f1df0 100644 --- a/src/com/android/server/telecom/CallAudioManager.java +++ b/src/com/android/server/telecom/CallAudioManager.java @@ -119,6 +119,19 @@ public class CallAudioManager extends CallsManagerListenerBase { return; // Don't do audio handling for calls in a conference, or external calls. } + addCall(call); + } + + @Override + public void onCallRemoved(Call call) { + if (shouldIgnoreCallForAudio(call)) { + return; // Don't do audio handling for calls in a conference, or external calls. + } + + removeCall(call); + } + + private void addCall(Call call) { if (mCalls.contains(call)) { Log.w(LOG_TAG, "Call TC@%s is being added twice.", call.getId()); return; // No guarantees that the same call won't get added twice. @@ -136,12 +149,7 @@ public class CallAudioManager extends CallsManagerListenerBase { onCallEnteringState(call, call.getState()); } - @Override - public void onCallRemoved(Call call) { - if (shouldIgnoreCallForAudio(call)) { - return; // Don't do audio handling for calls in a conference, or external calls. - } - + private void removeCall(Call call) { if (!mCalls.contains(call)) { return; // No guarantees that the same call won't get removed twice. } @@ -159,6 +167,25 @@ public class CallAudioManager extends CallsManagerListenerBase { onCallLeavingState(call, call.getState()); } + /** + * Handles changes to the external state of a call. External calls which become regular calls + * should be tracked, and regular calls which become external should no longer be tracked. + * + * @param call The call. + * @param isExternalCall {@code True} if the call is now external, {@code false} if it is now + * a regular call. + */ + @Override + public void onExternalCallChanged(Call call, boolean isExternalCall) { + if (isExternalCall) { + Log.d(LOG_TAG, "Removing call which became external ID %s", call.getId()); + removeCall(call); + } else if (!isExternalCall) { + Log.d(LOG_TAG, "Adding external call which was pulled with ID %s", call.getId()); + addCall(call); + } + } + /** * Determines if {@link CallAudioManager} should do any audio routing operations for a call. * We ignore child calls of a conference and external calls for audio routing purposes. diff --git a/src/com/android/server/telecom/CallsManager.java b/src/com/android/server/telecom/CallsManager.java index 5d646a5c..56c4555d 100644 --- a/src/com/android/server/telecom/CallsManager.java +++ b/src/com/android/server/telecom/CallsManager.java @@ -97,6 +97,7 @@ public class CallsManager extends Call.ListenerBase void onCanAddCallChanged(boolean canAddCall); void onSessionModifyRequestReceived(Call call, VideoProfile videoProfile); void onHoldToneRequested(Call call); + void onExternalCallChanged(Call call, boolean isExternalCall); } private static final String TAG = "CallsManager"; @@ -1214,6 +1215,21 @@ public class CallsManager extends Call.ListenerBase return allAccounts; } + /** + * Informs listeners (notably {@link CallAudioManager} of a change to the call's external + * property. + * . + * @param call The call whose external property changed. + * @param isExternalCall {@code True} if the call is now external, {@code false} otherwise. + */ + @Override + public void onExternalCallChanged(Call call, boolean isExternalCall) { + Log.v(this, "onConnectionPropertiesChanged: %b", isExternalCall); + for (CallsManagerListener listener : mListeners) { + listener.onExternalCallChanged(call, isExternalCall); + } + } + private void handleCallTechnologyChange(Call call) { if (call.getExtras() != null && call.getExtras().containsKey(TelecomManager.EXTRA_CALL_TECHNOLOGY_TYPE)) { @@ -1360,8 +1376,22 @@ public class CallsManager extends Call.ListenerBase } } + /** + * Determines if the {@link CallsManager} has any non-external calls. + * + * @return {@code True} if there are any non-external calls, {@code false} otherwise. + */ boolean hasAnyCalls() { - return !mCalls.isEmpty(); + if (mCalls.isEmpty()) { + return false; + } + + for (Call call : mCalls) { + if (!call.isExternalCall()) { + return true; + } + } + return false; } boolean hasActiveOrHoldingCall() { diff --git a/src/com/android/server/telecom/CallsManagerListenerBase.java b/src/com/android/server/telecom/CallsManagerListenerBase.java index 71d6c53f..9bfa098d 100644 --- a/src/com/android/server/telecom/CallsManagerListenerBase.java +++ b/src/com/android/server/telecom/CallsManagerListenerBase.java @@ -84,4 +84,8 @@ public class CallsManagerListenerBase implements CallsManager.CallsManagerListen @Override public void onHoldToneRequested(Call call) { } + + @Override + public void onExternalCallChanged(Call call, boolean isExternalCall) { + } } diff --git a/src/com/android/server/telecom/HeadsetMediaButton.java b/src/com/android/server/telecom/HeadsetMediaButton.java index 93dc6dec..a8bd3544 100644 --- a/src/com/android/server/telecom/HeadsetMediaButton.java +++ b/src/com/android/server/telecom/HeadsetMediaButton.java @@ -126,6 +126,9 @@ public class HeadsetMediaButton extends CallsManagerListenerBase { /** ${inheritDoc} */ @Override public void onCallAdded(Call call) { + if (call.isExternalCall()) { + return; + } mMediaSessionHandler.obtainMessage(MSG_MEDIA_SESSION_SET_ACTIVE, 1, 0).sendToTarget(); } @@ -136,4 +139,14 @@ public class HeadsetMediaButton extends CallsManagerListenerBase { mMediaSessionHandler.obtainMessage(MSG_MEDIA_SESSION_SET_ACTIVE, 0, 0).sendToTarget(); } } + + /** ${inheritDoc} */ + @Override + public void onExternalCallChanged(Call call, boolean isExternalCall) { + if (isExternalCall) { + onCallRemoved(call); + } else { + onCallAdded(call); + } + } } diff --git a/src/com/android/server/telecom/InCallController.java b/src/com/android/server/telecom/InCallController.java index 66dfb4da..12805a30 100644 --- a/src/com/android/server/telecom/InCallController.java +++ b/src/com/android/server/telecom/InCallController.java @@ -50,12 +50,10 @@ import com.android.server.telecom.TelecomServiceImpl.DefaultDialerManagerAdapter import java.util.ArrayList; import java.util.Collection; -import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Objects; -import java.util.concurrent.ConcurrentHashMap; /** * Binds to {@link IInCallService} and provides the service to {@link CallsManager} through which it @@ -618,6 +616,13 @@ public final class InCallController extends CallsManagerListenerBase { mCallIdMapper.removeCall(call); } + @Override + public void onExternalCallChanged(Call call, boolean isExternalCall) { + Log.i(this, "onExternalCallChanged: %s -> %b", call, isExternalCall); + // TODO: Need to add logic which ensures changes to a call's external state adds or removes + // the call from the InCallServices depending on whether they support external calls. + } + @Override public void onCallStateChanged(Call call, int oldState, int newState) { updateCall(call); diff --git a/src/com/android/server/telecom/PhoneStateBroadcaster.java b/src/com/android/server/telecom/PhoneStateBroadcaster.java index 54329c86..413f06c7 100644 --- a/src/com/android/server/telecom/PhoneStateBroadcaster.java +++ b/src/com/android/server/telecom/PhoneStateBroadcaster.java @@ -48,17 +48,38 @@ final class PhoneStateBroadcaster extends CallsManagerListenerBase { @Override public void onCallAdded(Call call) { + if (call.isExternalCall()) { + return; + } updateStates(call); } @Override public void onCallRemoved(Call call) { + if (call.isExternalCall()) { + return; + } + updateStates(call); + } + + /** + * Handles changes to a call's external property. If the call becomes external, we end up + * updating the call state to idle. If the call becomes non-external, then the call state can + * update to off hook. + * + * @param call The call. + * @param isExternalCall {@code True} if the call is external, {@code false} otherwise. + */ + @Override + public void onExternalCallChanged(Call call, boolean isExternalCall) { updateStates(call); } private void updateStates(Call call) { // Recalculate the current phone state based on the consolidated state of the remaining // calls in the call list. + // Note: CallsManager#hasRingingCall() and CallsManager#getFirstCallWithState(..) do not + // consider external calls, so an external call is going to cause the state to be idle. int callState = TelephonyManager.CALL_STATE_IDLE; if (mCallsManager.hasRingingCall()) { callState = TelephonyManager.CALL_STATE_RINGING; -- cgit v1.2.3