fdc4bff319
When an existing connection is added to represent an IMS conference participant, it is added with an associated parent conference specified. This was NOT passed along to the connection manager via the RemoteConnectionService API since there is no equivalent API present for that operation. To work around this, we stash the parent conference's ID into the connection extras. We will use that later so that Telecom can know which conference is the parent of this call. Also, removing restriction in RemoteConnectionService which would ignore conferences with no children. This assumption was incorrect for VOLTE conferences since they will start with no children. As a consequence we would ALWAYS skip adding IMS conferences to the connection manager, which would mean that it had no way of knowing about the conference that the existing connections are associated with. Test: Manual test with connection manager APIS on live network; make conference and verify that the correct objects are being created wrapped by the connection manager. Bug: 188420526 Change-Id: Ie58afed7a3b7eeaa7e329e80479d273e4c50ec82 Change-Id: I4250f9459c7a1b82936583a10e93d049fdfb4c5d
670 lines
28 KiB
Java
670 lines
28 KiB
Java
/*
|
|
* Copyright (C) 2014 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
package android.telecom;
|
|
|
|
import android.net.Uri;
|
|
import android.os.Bundle;
|
|
import android.os.IBinder;
|
|
import android.os.IBinder.DeathRecipient;
|
|
import android.os.RemoteException;
|
|
import android.telecom.Logging.Session;
|
|
|
|
import com.android.internal.telecom.IConnectionService;
|
|
import com.android.internal.telecom.IConnectionServiceAdapter;
|
|
import com.android.internal.telecom.IVideoProvider;
|
|
import com.android.internal.telecom.RemoteServiceCallback;
|
|
|
|
import java.util.ArrayList;
|
|
import java.util.HashMap;
|
|
import java.util.HashSet;
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
import java.util.Set;
|
|
import java.util.UUID;
|
|
|
|
/**
|
|
* Remote connection service which other connection services can use to place calls on their behalf.
|
|
*
|
|
* @hide
|
|
*/
|
|
final class RemoteConnectionService {
|
|
|
|
// Note: Casting null to avoid ambiguous constructor reference.
|
|
private static final RemoteConnection NULL_CONNECTION =
|
|
new RemoteConnection("NULL", null, (ConnectionRequest) null);
|
|
|
|
private static final RemoteConference NULL_CONFERENCE =
|
|
new RemoteConference("NULL", null);
|
|
|
|
private final IConnectionServiceAdapter mServantDelegate = new IConnectionServiceAdapter() {
|
|
@Override
|
|
public void handleCreateConnectionComplete(
|
|
String id,
|
|
ConnectionRequest request,
|
|
ParcelableConnection parcel,
|
|
Session.Info info) {
|
|
RemoteConnection connection =
|
|
findConnectionForAction(id, "handleCreateConnectionSuccessful");
|
|
if (connection != NULL_CONNECTION && mPendingConnections.contains(connection)) {
|
|
mPendingConnections.remove(connection);
|
|
// Unconditionally initialize the connection ...
|
|
connection.setConnectionCapabilities(parcel.getConnectionCapabilities());
|
|
connection.setConnectionProperties(parcel.getConnectionProperties());
|
|
if (parcel.getHandle() != null
|
|
|| parcel.getState() != Connection.STATE_DISCONNECTED) {
|
|
connection.setAddress(parcel.getHandle(), parcel.getHandlePresentation());
|
|
}
|
|
if (parcel.getCallerDisplayName() != null
|
|
|| parcel.getState() != Connection.STATE_DISCONNECTED) {
|
|
connection.setCallerDisplayName(
|
|
parcel.getCallerDisplayName(),
|
|
parcel.getCallerDisplayNamePresentation());
|
|
}
|
|
// Set state after handle so that the client can identify the connection.
|
|
if (parcel.getState() == Connection.STATE_DISCONNECTED) {
|
|
connection.setDisconnected(parcel.getDisconnectCause());
|
|
} else {
|
|
connection.setState(parcel.getState());
|
|
}
|
|
List<RemoteConnection> conferenceable = new ArrayList<>();
|
|
for (String confId : parcel.getConferenceableConnectionIds()) {
|
|
if (mConnectionById.containsKey(confId)) {
|
|
conferenceable.add(mConnectionById.get(confId));
|
|
}
|
|
}
|
|
connection.setConferenceableConnections(conferenceable);
|
|
connection.setVideoState(parcel.getVideoState());
|
|
if (connection.getState() == Connection.STATE_DISCONNECTED) {
|
|
// ... then, if it was created in a disconnected state, that indicates
|
|
// failure on the providing end, so immediately mark it destroyed
|
|
connection.setDestroyed();
|
|
}
|
|
connection.setStatusHints(parcel.getStatusHints());
|
|
connection.setIsVoipAudioMode(parcel.getIsVoipAudioMode());
|
|
connection.setRingbackRequested(parcel.isRingbackRequested());
|
|
connection.putExtras(parcel.getExtras());
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void handleCreateConferenceComplete(
|
|
String id,
|
|
ConnectionRequest request,
|
|
ParcelableConference parcel,
|
|
Session.Info info) {
|
|
}
|
|
|
|
@Override
|
|
public void setActive(String callId, Session.Info sessionInfo) {
|
|
if (mConnectionById.containsKey(callId)) {
|
|
findConnectionForAction(callId, "setActive")
|
|
.setState(Connection.STATE_ACTIVE);
|
|
} else {
|
|
findConferenceForAction(callId, "setActive")
|
|
.setState(Connection.STATE_ACTIVE);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void setRinging(String callId, Session.Info sessionInfo) {
|
|
findConnectionForAction(callId, "setRinging")
|
|
.setState(Connection.STATE_RINGING);
|
|
}
|
|
|
|
@Override
|
|
public void setDialing(String callId, Session.Info sessionInfo) {
|
|
findConnectionForAction(callId, "setDialing")
|
|
.setState(Connection.STATE_DIALING);
|
|
}
|
|
|
|
@Override
|
|
public void setPulling(String callId, Session.Info sessionInfo) {
|
|
findConnectionForAction(callId, "setPulling")
|
|
.setState(Connection.STATE_PULLING_CALL);
|
|
}
|
|
|
|
@Override
|
|
public void setDisconnected(String callId, DisconnectCause disconnectCause,
|
|
Session.Info sessionInfo) {
|
|
if (mConnectionById.containsKey(callId)) {
|
|
findConnectionForAction(callId, "setDisconnected")
|
|
.setDisconnected(disconnectCause);
|
|
} else {
|
|
findConferenceForAction(callId, "setDisconnected")
|
|
.setDisconnected(disconnectCause);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void setOnHold(String callId, Session.Info sessionInfo) {
|
|
if (mConnectionById.containsKey(callId)) {
|
|
findConnectionForAction(callId, "setOnHold")
|
|
.setState(Connection.STATE_HOLDING);
|
|
} else {
|
|
findConferenceForAction(callId, "setOnHold")
|
|
.setState(Connection.STATE_HOLDING);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void setRingbackRequested(String callId, boolean ringing, Session.Info sessionInfo) {
|
|
findConnectionForAction(callId, "setRingbackRequested")
|
|
.setRingbackRequested(ringing);
|
|
}
|
|
|
|
@Override
|
|
public void setConnectionCapabilities(String callId, int connectionCapabilities,
|
|
Session.Info sessionInfo) {
|
|
if (mConnectionById.containsKey(callId)) {
|
|
findConnectionForAction(callId, "setConnectionCapabilities")
|
|
.setConnectionCapabilities(connectionCapabilities);
|
|
} else {
|
|
findConferenceForAction(callId, "setConnectionCapabilities")
|
|
.setConnectionCapabilities(connectionCapabilities);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void setConnectionProperties(String callId, int connectionProperties,
|
|
Session.Info sessionInfo) {
|
|
if (mConnectionById.containsKey(callId)) {
|
|
findConnectionForAction(callId, "setConnectionProperties")
|
|
.setConnectionProperties(connectionProperties);
|
|
} else {
|
|
findConferenceForAction(callId, "setConnectionProperties")
|
|
.setConnectionProperties(connectionProperties);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void setIsConferenced(String callId, String conferenceCallId,
|
|
Session.Info sessionInfo) {
|
|
// Note: callId should not be null; conferenceCallId may be null
|
|
RemoteConnection connection =
|
|
findConnectionForAction(callId, "setIsConferenced");
|
|
if (connection != NULL_CONNECTION) {
|
|
if (conferenceCallId == null) {
|
|
// 'connection' is being split from its conference
|
|
if (connection.getConference() != null) {
|
|
connection.getConference().removeConnection(connection);
|
|
}
|
|
} else {
|
|
RemoteConference conference =
|
|
findConferenceForAction(conferenceCallId, "setIsConferenced");
|
|
if (conference != NULL_CONFERENCE) {
|
|
conference.addConnection(connection);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void setConferenceMergeFailed(String callId, Session.Info sessionInfo) {
|
|
// Nothing to do here.
|
|
// The event has already been handled and there is no state to update
|
|
// in the underlying connection or conference objects
|
|
}
|
|
|
|
@Override
|
|
public void onPhoneAccountChanged(String callId, PhoneAccountHandle pHandle,
|
|
Session.Info sessionInfo) {
|
|
}
|
|
|
|
@Override
|
|
public void onConnectionServiceFocusReleased(Session.Info sessionInfo) {}
|
|
|
|
@Override
|
|
public void addConferenceCall(
|
|
final String callId, ParcelableConference parcel, Session.Info sessionInfo) {
|
|
RemoteConference conference = new RemoteConference(callId,
|
|
mOutgoingConnectionServiceRpc);
|
|
|
|
for (String id : parcel.getConnectionIds()) {
|
|
RemoteConnection c = mConnectionById.get(id);
|
|
if (c != null) {
|
|
conference.addConnection(c);
|
|
}
|
|
}
|
|
// We used to skip adding empty conferences; however in the world of IMS conference
|
|
// calls we need to add them to the remote connection service because they will always
|
|
// start with no participants.
|
|
|
|
conference.setState(parcel.getState());
|
|
conference.setConnectionCapabilities(parcel.getConnectionCapabilities());
|
|
conference.setConnectionProperties(parcel.getConnectionProperties());
|
|
conference.putExtras(parcel.getExtras());
|
|
mConferenceById.put(callId, conference);
|
|
|
|
// Stash the original connection ID as it exists in the source ConnectionService.
|
|
// Telecom will use this to avoid adding duplicates later.
|
|
// See comments on Connection.EXTRA_ORIGINAL_CONNECTION_ID for more information.
|
|
Bundle newExtras = new Bundle();
|
|
newExtras.putString(Connection.EXTRA_ORIGINAL_CONNECTION_ID, callId);
|
|
// Track the fact this request was relayed through the remote connection service.
|
|
newExtras.putParcelable(Connection.EXTRA_REMOTE_PHONE_ACCOUNT_HANDLE,
|
|
parcel.getPhoneAccount());
|
|
conference.putExtras(newExtras);
|
|
|
|
conference.registerCallback(new RemoteConference.Callback() {
|
|
@Override
|
|
public void onDestroyed(RemoteConference c) {
|
|
mConferenceById.remove(callId);
|
|
maybeDisconnectAdapter();
|
|
}
|
|
});
|
|
|
|
mOurConnectionServiceImpl.addRemoteConference(conference);
|
|
}
|
|
|
|
@Override
|
|
public void removeCall(String callId, Session.Info sessionInfo) {
|
|
if (mConnectionById.containsKey(callId)) {
|
|
findConnectionForAction(callId, "removeCall")
|
|
.setDestroyed();
|
|
} else {
|
|
findConferenceForAction(callId, "removeCall")
|
|
.setDestroyed();
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void onPostDialWait(String callId, String remaining, Session.Info sessionInfo) {
|
|
findConnectionForAction(callId, "onPostDialWait")
|
|
.setPostDialWait(remaining);
|
|
}
|
|
|
|
@Override
|
|
public void onPostDialChar(String callId, char nextChar, Session.Info sessionInfo) {
|
|
findConnectionForAction(callId, "onPostDialChar")
|
|
.onPostDialChar(nextChar);
|
|
}
|
|
|
|
@Override
|
|
public void queryRemoteConnectionServices(RemoteServiceCallback callback,
|
|
String callingPackage, Session.Info sessionInfo) {
|
|
// Not supported from remote connection service.
|
|
}
|
|
|
|
@Override
|
|
public void setVideoProvider(String callId, IVideoProvider videoProvider,
|
|
Session.Info sessionInfo) {
|
|
|
|
String callingPackage = mOurConnectionServiceImpl.getApplicationContext()
|
|
.getOpPackageName();
|
|
int targetSdkVersion = mOurConnectionServiceImpl.getApplicationInfo().targetSdkVersion;
|
|
RemoteConnection.VideoProvider remoteVideoProvider = null;
|
|
if (videoProvider != null) {
|
|
remoteVideoProvider = new RemoteConnection.VideoProvider(videoProvider,
|
|
callingPackage, targetSdkVersion);
|
|
}
|
|
findConnectionForAction(callId, "setVideoProvider")
|
|
.setVideoProvider(remoteVideoProvider);
|
|
}
|
|
|
|
@Override
|
|
public void setVideoState(String callId, int videoState, Session.Info sessionInfo) {
|
|
findConnectionForAction(callId, "setVideoState")
|
|
.setVideoState(videoState);
|
|
}
|
|
|
|
@Override
|
|
public void setIsVoipAudioMode(String callId, boolean isVoip, Session.Info sessionInfo) {
|
|
findConnectionForAction(callId, "setIsVoipAudioMode")
|
|
.setIsVoipAudioMode(isVoip);
|
|
}
|
|
|
|
@Override
|
|
public void setStatusHints(String callId, StatusHints statusHints,
|
|
Session.Info sessionInfo) {
|
|
findConnectionForAction(callId, "setStatusHints")
|
|
.setStatusHints(statusHints);
|
|
}
|
|
|
|
@Override
|
|
public void setAddress(String callId, Uri address, int presentation,
|
|
Session.Info sessionInfo) {
|
|
findConnectionForAction(callId, "setAddress")
|
|
.setAddress(address, presentation);
|
|
}
|
|
|
|
@Override
|
|
public void setCallerDisplayName(String callId, String callerDisplayName,
|
|
int presentation, Session.Info sessionInfo) {
|
|
findConnectionForAction(callId, "setCallerDisplayName")
|
|
.setCallerDisplayName(callerDisplayName, presentation);
|
|
}
|
|
|
|
@Override
|
|
public IBinder asBinder() {
|
|
throw new UnsupportedOperationException();
|
|
}
|
|
|
|
@Override
|
|
public final void setConferenceableConnections(String callId,
|
|
List<String> conferenceableConnectionIds, Session.Info sessionInfo) {
|
|
List<RemoteConnection> conferenceable = new ArrayList<>();
|
|
for (String id : conferenceableConnectionIds) {
|
|
if (mConnectionById.containsKey(id)) {
|
|
conferenceable.add(mConnectionById.get(id));
|
|
}
|
|
}
|
|
|
|
if (hasConnection(callId)) {
|
|
findConnectionForAction(callId, "setConferenceableConnections")
|
|
.setConferenceableConnections(conferenceable);
|
|
} else {
|
|
findConferenceForAction(callId, "setConferenceableConnections")
|
|
.setConferenceableConnections(conferenceable);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void addExistingConnection(String callId, ParcelableConnection connection,
|
|
Session.Info sessionInfo) {
|
|
Log.i(RemoteConnectionService.this, "addExistingConnection: callId=%s, conn=%s", callId,
|
|
connection);
|
|
String callingPackage = mOurConnectionServiceImpl.getApplicationContext().
|
|
getOpPackageName();
|
|
int callingTargetSdkVersion = mOurConnectionServiceImpl.getApplicationInfo()
|
|
.targetSdkVersion;
|
|
RemoteConnection remoteConnection = new RemoteConnection(callId,
|
|
mOutgoingConnectionServiceRpc, connection, callingPackage,
|
|
callingTargetSdkVersion);
|
|
// Track that it is via a remote connection.
|
|
Bundle newExtras = new Bundle();
|
|
newExtras.putParcelable(Connection.EXTRA_REMOTE_PHONE_ACCOUNT_HANDLE,
|
|
connection.getPhoneAccount());
|
|
if (connection.getParentCallId() != null) {
|
|
RemoteConference parentConf = mConferenceById.get(connection.getParentCallId());
|
|
// If there is a parent being set, we need to stash the conference ID here.
|
|
// Telephony can add an existing connection while specifying a parent conference.
|
|
// There is no equivalent version of that operation as part of the remote connection
|
|
// API, so we will stash the pre-defined parent's ID in the extras. When the
|
|
// connectionmanager copies over the extras from the remote connection to the
|
|
// actual one, it'll get passed to Telecom so that it can make the association.
|
|
if (parentConf != null) {
|
|
newExtras.putString(Connection.EXTRA_ADD_TO_CONFERENCE_ID, parentConf.getId());
|
|
Log.i(this, "addExistingConnection: stash parent of %s as %s",
|
|
connection.getParentCallId(), parentConf.getId());
|
|
}
|
|
}
|
|
remoteConnection.putExtras(newExtras);
|
|
mConnectionById.put(callId, remoteConnection);
|
|
remoteConnection.registerCallback(new RemoteConnection.Callback() {
|
|
@Override
|
|
public void onDestroyed(RemoteConnection connection) {
|
|
mConnectionById.remove(callId);
|
|
maybeDisconnectAdapter();
|
|
}
|
|
});
|
|
mOurConnectionServiceImpl.addRemoteExistingConnection(remoteConnection);
|
|
}
|
|
|
|
@Override
|
|
public void putExtras(String callId, Bundle extras, Session.Info sessionInfo) {
|
|
if (hasConnection(callId)) {
|
|
findConnectionForAction(callId, "putExtras").putExtras(extras);
|
|
} else {
|
|
findConferenceForAction(callId, "putExtras").putExtras(extras);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void removeExtras(String callId, List<String> keys, Session.Info sessionInfo) {
|
|
if (hasConnection(callId)) {
|
|
findConnectionForAction(callId, "removeExtra").removeExtras(keys);
|
|
} else {
|
|
findConferenceForAction(callId, "removeExtra").removeExtras(keys);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void setAudioRoute(String callId, int audioRoute, String bluetoothAddress,
|
|
Session.Info sessionInfo) {
|
|
if (hasConnection(callId)) {
|
|
// TODO(3pcalls): handle this for remote connections.
|
|
// Likely we don't want to do anything since it doesn't make sense for self-managed
|
|
// connections to go through a connection mgr.
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void onConnectionEvent(String callId, String event, Bundle extras,
|
|
Session.Info sessionInfo) {
|
|
if (mConnectionById.containsKey(callId)) {
|
|
findConnectionForAction(callId, "onConnectionEvent").onConnectionEvent(event,
|
|
extras);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void onRttInitiationSuccess(String callId, Session.Info sessionInfo)
|
|
throws RemoteException {
|
|
if (hasConnection(callId)) {
|
|
findConnectionForAction(callId, "onRttInitiationSuccess")
|
|
.onRttInitiationSuccess();
|
|
} else {
|
|
Log.w(this, "onRttInitiationSuccess called on a remote conference");
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void onRttInitiationFailure(String callId, int reason, Session.Info sessionInfo)
|
|
throws RemoteException {
|
|
if (hasConnection(callId)) {
|
|
findConnectionForAction(callId, "onRttInitiationFailure")
|
|
.onRttInitiationFailure(reason);
|
|
} else {
|
|
Log.w(this, "onRttInitiationFailure called on a remote conference");
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void onRttSessionRemotelyTerminated(String callId, Session.Info sessionInfo)
|
|
throws RemoteException {
|
|
if (hasConnection(callId)) {
|
|
findConnectionForAction(callId, "onRttSessionRemotelyTerminated")
|
|
.onRttSessionRemotelyTerminated();
|
|
} else {
|
|
Log.w(this, "onRttSessionRemotelyTerminated called on a remote conference");
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void onRemoteRttRequest(String callId, Session.Info sessionInfo)
|
|
throws RemoteException {
|
|
if (hasConnection(callId)) {
|
|
findConnectionForAction(callId, "onRemoteRttRequest")
|
|
.onRemoteRttRequest();
|
|
} else {
|
|
Log.w(this, "onRemoteRttRequest called on a remote conference");
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void resetConnectionTime(String callId, Session.Info sessionInfo) {
|
|
// Do nothing
|
|
}
|
|
|
|
@Override
|
|
public void setConferenceState(String callId, boolean isConference,
|
|
Session.Info sessionInfo) {
|
|
// Do nothing
|
|
}
|
|
|
|
@Override
|
|
public void setCallDirection(String callId, int direction, Session.Info sessionInfo) {
|
|
// Do nothing
|
|
}
|
|
};
|
|
|
|
private final ConnectionServiceAdapterServant mServant =
|
|
new ConnectionServiceAdapterServant(mServantDelegate);
|
|
|
|
private final DeathRecipient mDeathRecipient = new DeathRecipient() {
|
|
@Override
|
|
public void binderDied() {
|
|
for (RemoteConnection c : mConnectionById.values()) {
|
|
c.setDestroyed();
|
|
}
|
|
for (RemoteConference c : mConferenceById.values()) {
|
|
c.setDestroyed();
|
|
}
|
|
mConnectionById.clear();
|
|
mConferenceById.clear();
|
|
mPendingConnections.clear();
|
|
mOutgoingConnectionServiceRpc.asBinder().unlinkToDeath(mDeathRecipient, 0);
|
|
}
|
|
};
|
|
|
|
private final IConnectionService mOutgoingConnectionServiceRpc;
|
|
private final ConnectionService mOurConnectionServiceImpl;
|
|
private final Map<String, RemoteConnection> mConnectionById = new HashMap<>();
|
|
private final Map<String, RemoteConference> mConferenceById = new HashMap<>();
|
|
private final Set<RemoteConnection> mPendingConnections = new HashSet<>();
|
|
|
|
RemoteConnectionService(
|
|
IConnectionService outgoingConnectionServiceRpc,
|
|
ConnectionService ourConnectionServiceImpl) throws RemoteException {
|
|
mOutgoingConnectionServiceRpc = outgoingConnectionServiceRpc;
|
|
mOutgoingConnectionServiceRpc.asBinder().linkToDeath(mDeathRecipient, 0);
|
|
mOurConnectionServiceImpl = ourConnectionServiceImpl;
|
|
}
|
|
|
|
@Override
|
|
public String toString() {
|
|
return "[RemoteCS - " + mOutgoingConnectionServiceRpc.asBinder().toString() + "]";
|
|
}
|
|
|
|
final RemoteConnection createRemoteConnection(
|
|
PhoneAccountHandle connectionManagerPhoneAccount,
|
|
ConnectionRequest request,
|
|
boolean isIncoming) {
|
|
final String id = UUID.randomUUID().toString();
|
|
Bundle extras = new Bundle();
|
|
if (request.getExtras() != null) {
|
|
extras.putAll(request.getExtras());
|
|
}
|
|
// We will set the package name for the originator of the remote request; this lets the
|
|
// receiving ConnectionService know that the request originated from a remote connection
|
|
// service so that it can provide tracking information for Telecom.
|
|
extras.putString(Connection.EXTRA_REMOTE_CONNECTION_ORIGINATING_PACKAGE_NAME,
|
|
mOurConnectionServiceImpl.getApplicationContext().getOpPackageName());
|
|
|
|
final ConnectionRequest newRequest = new ConnectionRequest.Builder()
|
|
.setAccountHandle(request.getAccountHandle())
|
|
.setAddress(request.getAddress())
|
|
.setExtras(extras)
|
|
.setVideoState(request.getVideoState())
|
|
.setRttPipeFromInCall(request.getRttPipeFromInCall())
|
|
.setRttPipeToInCall(request.getRttPipeToInCall())
|
|
.build();
|
|
try {
|
|
if (mConnectionById.isEmpty()) {
|
|
mOutgoingConnectionServiceRpc.addConnectionServiceAdapter(mServant.getStub(),
|
|
null /*Session.Info*/);
|
|
}
|
|
RemoteConnection connection =
|
|
new RemoteConnection(id, mOutgoingConnectionServiceRpc, newRequest);
|
|
mPendingConnections.add(connection);
|
|
mConnectionById.put(id, connection);
|
|
mOutgoingConnectionServiceRpc.createConnection(
|
|
connectionManagerPhoneAccount,
|
|
id,
|
|
newRequest,
|
|
isIncoming,
|
|
false /* isUnknownCall */,
|
|
null /*Session.info*/);
|
|
connection.registerCallback(new RemoteConnection.Callback() {
|
|
@Override
|
|
public void onDestroyed(RemoteConnection connection) {
|
|
mConnectionById.remove(id);
|
|
maybeDisconnectAdapter();
|
|
}
|
|
});
|
|
return connection;
|
|
} catch (RemoteException e) {
|
|
return RemoteConnection.failure(
|
|
new DisconnectCause(DisconnectCause.ERROR, e.toString()));
|
|
}
|
|
}
|
|
|
|
RemoteConference createRemoteConference(
|
|
PhoneAccountHandle connectionManagerPhoneAccount,
|
|
ConnectionRequest request,
|
|
boolean isIncoming) {
|
|
final String id = UUID.randomUUID().toString();
|
|
try {
|
|
if (mConferenceById.isEmpty()) {
|
|
mOutgoingConnectionServiceRpc.addConnectionServiceAdapter(mServant.getStub(),
|
|
null /*Session.Info*/);
|
|
}
|
|
RemoteConference conference = new RemoteConference(id, mOutgoingConnectionServiceRpc);
|
|
mOutgoingConnectionServiceRpc.createConference(connectionManagerPhoneAccount,
|
|
id,
|
|
request,
|
|
isIncoming,
|
|
false /* isUnknownCall */,
|
|
null /*Session.info*/);
|
|
conference.registerCallback(new RemoteConference.Callback() {
|
|
@Override
|
|
public void onDestroyed(RemoteConference conference) {
|
|
mConferenceById.remove(id);
|
|
maybeDisconnectAdapter();
|
|
}
|
|
});
|
|
conference.putExtras(request.getExtras());
|
|
return conference;
|
|
} catch (RemoteException e) {
|
|
return RemoteConference.failure(
|
|
new DisconnectCause(DisconnectCause.ERROR, e.toString()));
|
|
}
|
|
}
|
|
|
|
private boolean hasConnection(String callId) {
|
|
return mConnectionById.containsKey(callId);
|
|
}
|
|
|
|
private RemoteConnection findConnectionForAction(
|
|
String callId, String action) {
|
|
if (mConnectionById.containsKey(callId)) {
|
|
return mConnectionById.get(callId);
|
|
}
|
|
Log.w(this, "%s - Cannot find Connection %s", action, callId);
|
|
return NULL_CONNECTION;
|
|
}
|
|
|
|
private RemoteConference findConferenceForAction(
|
|
String callId, String action) {
|
|
if (mConferenceById.containsKey(callId)) {
|
|
return mConferenceById.get(callId);
|
|
}
|
|
Log.w(this, "%s - Cannot find Conference %s", action, callId);
|
|
return NULL_CONFERENCE;
|
|
}
|
|
|
|
private void maybeDisconnectAdapter() {
|
|
if (mConnectionById.isEmpty() && mConferenceById.isEmpty()) {
|
|
try {
|
|
mOutgoingConnectionServiceRpc.removeConnectionServiceAdapter(mServant.getStub(),
|
|
null /*Session.info*/);
|
|
} catch (RemoteException e) {
|
|
}
|
|
}
|
|
}
|
|
}
|