Merge "Ims: Add support for Adhoc Conference calls"

This commit is contained in:
Treehugger Robot
2020-01-22 21:16:19 +00:00
committed by Gerrit Code Review
17 changed files with 817 additions and 19 deletions

View File

@@ -43608,6 +43608,7 @@ package android.telecom {
field public static final int PROPERTY_GENERIC_CONFERENCE = 2; // 0x2 field public static final int PROPERTY_GENERIC_CONFERENCE = 2; // 0x2
field public static final int PROPERTY_HAS_CDMA_VOICE_PRIVACY = 128; // 0x80 field public static final int PROPERTY_HAS_CDMA_VOICE_PRIVACY = 128; // 0x80
field public static final int PROPERTY_HIGH_DEF_AUDIO = 16; // 0x10 field public static final int PROPERTY_HIGH_DEF_AUDIO = 16; // 0x10
field public static final int PROPERTY_IS_ADHOC_CONFERENCE = 8192; // 0x2000
field public static final int PROPERTY_IS_EXTERNAL_CALL = 64; // 0x40 field public static final int PROPERTY_IS_EXTERNAL_CALL = 64; // 0x40
field public static final int PROPERTY_NETWORK_IDENTIFIED_EMERGENCY_CALL = 2048; // 0x800 field public static final int PROPERTY_NETWORK_IDENTIFIED_EMERGENCY_CALL = 2048; // 0x800
field public static final int PROPERTY_RTT = 1024; // 0x400 field public static final int PROPERTY_RTT = 1024; // 0x400
@@ -43685,6 +43686,7 @@ package android.telecom {
public abstract class Conference extends android.telecom.Conferenceable { public abstract class Conference extends android.telecom.Conferenceable {
ctor public Conference(android.telecom.PhoneAccountHandle); ctor public Conference(android.telecom.PhoneAccountHandle);
method public final boolean addConnection(android.telecom.Connection); method public final boolean addConnection(android.telecom.Connection);
method @NonNull public static android.telecom.Conference createFailedConference(@NonNull android.telecom.DisconnectCause, @NonNull android.telecom.PhoneAccountHandle);
method public final void destroy(); method public final void destroy();
method public final android.telecom.CallAudioState getCallAudioState(); method public final android.telecom.CallAudioState getCallAudioState();
method public final java.util.List<android.telecom.Connection> getConferenceableConnections(); method public final java.util.List<android.telecom.Connection> getConferenceableConnections();
@@ -43699,6 +43701,8 @@ package android.telecom {
method public final android.telecom.StatusHints getStatusHints(); method public final android.telecom.StatusHints getStatusHints();
method public android.telecom.Connection.VideoProvider getVideoProvider(); method public android.telecom.Connection.VideoProvider getVideoProvider();
method public int getVideoState(); method public int getVideoState();
method public final boolean isRingbackRequested();
method public void onAnswer(int);
method public void onCallAudioStateChanged(android.telecom.CallAudioState); method public void onCallAudioStateChanged(android.telecom.CallAudioState);
method public void onConnectionAdded(android.telecom.Connection); method public void onConnectionAdded(android.telecom.Connection);
method public void onDisconnect(); method public void onDisconnect();
@@ -43707,6 +43711,7 @@ package android.telecom {
method public void onMerge(android.telecom.Connection); method public void onMerge(android.telecom.Connection);
method public void onMerge(); method public void onMerge();
method public void onPlayDtmfTone(char); method public void onPlayDtmfTone(char);
method public void onReject();
method public void onSeparate(android.telecom.Connection); method public void onSeparate(android.telecom.Connection);
method public void onStopDtmfTone(); method public void onStopDtmfTone();
method public void onSwap(); method public void onSwap();
@@ -43726,6 +43731,8 @@ package android.telecom {
method public final void setDisconnected(android.telecom.DisconnectCause); method public final void setDisconnected(android.telecom.DisconnectCause);
method public final void setExtras(@Nullable android.os.Bundle); method public final void setExtras(@Nullable android.os.Bundle);
method public final void setOnHold(); method public final void setOnHold();
method public final void setRingbackRequested(boolean);
method public final void setRinging();
method public final void setStatusHints(android.telecom.StatusHints); method public final void setStatusHints(android.telecom.StatusHints);
method public final void setVideoProvider(android.telecom.Connection, android.telecom.Connection.VideoProvider); method public final void setVideoProvider(android.telecom.Connection, android.telecom.Connection.VideoProvider);
method public final void setVideoState(android.telecom.Connection, int); method public final void setVideoState(android.telecom.Connection, int);
@@ -43883,6 +43890,7 @@ package android.telecom {
field public static final int PROPERTY_ASSISTED_DIALING_USED = 512; // 0x200 field public static final int PROPERTY_ASSISTED_DIALING_USED = 512; // 0x200
field public static final int PROPERTY_HAS_CDMA_VOICE_PRIVACY = 32; // 0x20 field public static final int PROPERTY_HAS_CDMA_VOICE_PRIVACY = 32; // 0x20
field public static final int PROPERTY_HIGH_DEF_AUDIO = 4; // 0x4 field public static final int PROPERTY_HIGH_DEF_AUDIO = 4; // 0x4
field public static final int PROPERTY_IS_ADHOC_CONFERENCE = 4096; // 0x1000
field public static final int PROPERTY_IS_EXTERNAL_CALL = 16; // 0x10 field public static final int PROPERTY_IS_EXTERNAL_CALL = 16; // 0x10
field public static final int PROPERTY_IS_RTT = 256; // 0x100 field public static final int PROPERTY_IS_RTT = 256; // 0x100
field public static final int PROPERTY_NETWORK_IDENTIFIED_EMERGENCY_CALL = 1024; // 0x400 field public static final int PROPERTY_NETWORK_IDENTIFIED_EMERGENCY_CALL = 1024; // 0x400
@@ -43955,8 +43963,10 @@ package android.telecom {
method public android.telecom.PhoneAccountHandle getAccountHandle(); method public android.telecom.PhoneAccountHandle getAccountHandle();
method public android.net.Uri getAddress(); method public android.net.Uri getAddress();
method public android.os.Bundle getExtras(); method public android.os.Bundle getExtras();
method @Nullable public java.util.List<android.net.Uri> getParticipants();
method public android.telecom.Connection.RttTextStream getRttTextStream(); method public android.telecom.Connection.RttTextStream getRttTextStream();
method public int getVideoState(); method public int getVideoState();
method public boolean isAdhocConferenceCall();
method public boolean isRequestingRtt(); method public boolean isRequestingRtt();
method public void writeToParcel(android.os.Parcel, int); method public void writeToParcel(android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.telecom.ConnectionRequest> CREATOR; field @NonNull public static final android.os.Parcelable.Creator<android.telecom.ConnectionRequest> CREATOR;
@@ -43976,9 +43986,13 @@ package android.telecom {
method public void onConference(android.telecom.Connection, android.telecom.Connection); method public void onConference(android.telecom.Connection, android.telecom.Connection);
method public void onConnectionServiceFocusGained(); method public void onConnectionServiceFocusGained();
method public void onConnectionServiceFocusLost(); method public void onConnectionServiceFocusLost();
method @Nullable public android.telecom.Conference onCreateIncomingConference(@Nullable android.telecom.PhoneAccountHandle, @Nullable android.telecom.ConnectionRequest);
method public void onCreateIncomingConferenceFailed(@Nullable android.telecom.PhoneAccountHandle, @Nullable android.telecom.ConnectionRequest);
method public android.telecom.Connection onCreateIncomingConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest); method public android.telecom.Connection onCreateIncomingConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
method public void onCreateIncomingConnectionFailed(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest); method public void onCreateIncomingConnectionFailed(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
method public android.telecom.Connection onCreateIncomingHandoverConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest); method public android.telecom.Connection onCreateIncomingHandoverConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
method @Nullable public android.telecom.Conference onCreateOutgoingConference(@Nullable android.telecom.PhoneAccountHandle, @Nullable android.telecom.ConnectionRequest);
method public void onCreateOutgoingConferenceFailed(@Nullable android.telecom.PhoneAccountHandle, @Nullable android.telecom.ConnectionRequest);
method public android.telecom.Connection onCreateOutgoingConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest); method public android.telecom.Connection onCreateOutgoingConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
method public void onCreateOutgoingConnectionFailed(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest); method public void onCreateOutgoingConnectionFailed(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
method public android.telecom.Connection onCreateOutgoingHandoverConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest); method public android.telecom.Connection onCreateOutgoingHandoverConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
@@ -44093,6 +44107,7 @@ package android.telecom {
method public boolean supportsUriScheme(String); method public boolean supportsUriScheme(String);
method public android.telecom.PhoneAccount.Builder toBuilder(); method public android.telecom.PhoneAccount.Builder toBuilder();
method public void writeToParcel(android.os.Parcel, int); method public void writeToParcel(android.os.Parcel, int);
field public static final int CAPABILITY_ADHOC_CONFERENCE_CALLING = 16384; // 0x4000
field public static final int CAPABILITY_CALL_PROVIDER = 2; // 0x2 field public static final int CAPABILITY_CALL_PROVIDER = 2; // 0x2
field public static final int CAPABILITY_CALL_SUBJECT = 64; // 0x40 field public static final int CAPABILITY_CALL_SUBJECT = 64; // 0x40
field public static final int CAPABILITY_CONNECTION_MANAGER = 1; // 0x1 field public static final int CAPABILITY_CONNECTION_MANAGER = 1; // 0x1
@@ -44288,6 +44303,7 @@ package android.telecom {
method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ANSWER_PHONE_CALLS, android.Manifest.permission.MODIFY_PHONE_STATE}) public void acceptRingingCall(); method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ANSWER_PHONE_CALLS, android.Manifest.permission.MODIFY_PHONE_STATE}) public void acceptRingingCall();
method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ANSWER_PHONE_CALLS, android.Manifest.permission.MODIFY_PHONE_STATE}) public void acceptRingingCall(int); method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ANSWER_PHONE_CALLS, android.Manifest.permission.MODIFY_PHONE_STATE}) public void acceptRingingCall(int);
method public void addNewIncomingCall(android.telecom.PhoneAccountHandle, android.os.Bundle); method public void addNewIncomingCall(android.telecom.PhoneAccountHandle, android.os.Bundle);
method public void addNewIncomingConference(@NonNull android.telecom.PhoneAccountHandle, @NonNull android.os.Bundle);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void cancelMissedCallsNotification(); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void cancelMissedCallsNotification();
method public android.content.Intent createManageBlockedNumbersIntent(); method public android.content.Intent createManageBlockedNumbersIntent();
method @Deprecated @RequiresPermission(android.Manifest.permission.ANSWER_PHONE_CALLS) public boolean endCall(); method @Deprecated @RequiresPermission(android.Manifest.permission.ANSWER_PHONE_CALLS) public boolean endCall();
@@ -44315,6 +44331,7 @@ package android.telecom {
method public void registerPhoneAccount(android.telecom.PhoneAccount); method public void registerPhoneAccount(android.telecom.PhoneAccount);
method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public void showInCallScreen(boolean); method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public void showInCallScreen(boolean);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void silenceRinger(); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void silenceRinger();
method @RequiresPermission(android.Manifest.permission.CALL_PHONE) public void startConference(@NonNull java.util.List<android.net.Uri>, @NonNull android.os.Bundle);
method public void unregisterPhoneAccount(android.telecom.PhoneAccountHandle); method public void unregisterPhoneAccount(android.telecom.PhoneAccountHandle);
field public static final String ACTION_CHANGE_DEFAULT_DIALER = "android.telecom.action.CHANGE_DEFAULT_DIALER"; field public static final String ACTION_CHANGE_DEFAULT_DIALER = "android.telecom.action.CHANGE_DEFAULT_DIALER";
field public static final String ACTION_CHANGE_PHONE_ACCOUNTS = "android.telecom.action.CHANGE_PHONE_ACCOUNTS"; field public static final String ACTION_CHANGE_PHONE_ACCOUNTS = "android.telecom.action.CHANGE_PHONE_ACCOUNTS";
@@ -44793,6 +44810,7 @@ package android.telephony {
field public static final String KEY_SIM_NETWORK_UNLOCK_ALLOW_DISMISS_BOOL = "sim_network_unlock_allow_dismiss_bool"; field public static final String KEY_SIM_NETWORK_UNLOCK_ALLOW_DISMISS_BOOL = "sim_network_unlock_allow_dismiss_bool";
field public static final String KEY_SMS_REQUIRES_DESTINATION_NUMBER_CONVERSION_BOOL = "sms_requires_destination_number_conversion_bool"; field public static final String KEY_SMS_REQUIRES_DESTINATION_NUMBER_CONVERSION_BOOL = "sms_requires_destination_number_conversion_bool";
field public static final String KEY_SUPPORT_3GPP_CALL_FORWARDING_WHILE_ROAMING_BOOL = "support_3gpp_call_forwarding_while_roaming_bool"; field public static final String KEY_SUPPORT_3GPP_CALL_FORWARDING_WHILE_ROAMING_BOOL = "support_3gpp_call_forwarding_while_roaming_bool";
field public static final String KEY_SUPPORT_ADHOC_CONFERENCE_CALLS_BOOL = "support_adhoc_conference_calls_bool";
field public static final String KEY_SUPPORT_CLIR_NETWORK_DEFAULT_BOOL = "support_clir_network_default_bool"; field public static final String KEY_SUPPORT_CLIR_NETWORK_DEFAULT_BOOL = "support_clir_network_default_bool";
field public static final String KEY_SUPPORT_CONFERENCE_CALL_BOOL = "support_conference_call_bool"; field public static final String KEY_SUPPORT_CONFERENCE_CALL_BOOL = "support_conference_call_bool";
field public static final String KEY_SUPPORT_EMERGENCY_SMS_OVER_IMS_BOOL = "support_emergency_sms_over_ims_bool"; field public static final String KEY_SUPPORT_EMERGENCY_SMS_OVER_IMS_BOOL = "support_emergency_sms_over_ims_bool";

View File

@@ -2884,6 +2884,8 @@ package android.telecom {
method @NonNull public android.telecom.ConnectionRequest.Builder setAccountHandle(@NonNull android.telecom.PhoneAccountHandle); method @NonNull public android.telecom.ConnectionRequest.Builder setAccountHandle(@NonNull android.telecom.PhoneAccountHandle);
method @NonNull public android.telecom.ConnectionRequest.Builder setAddress(@NonNull android.net.Uri); method @NonNull public android.telecom.ConnectionRequest.Builder setAddress(@NonNull android.net.Uri);
method @NonNull public android.telecom.ConnectionRequest.Builder setExtras(@NonNull android.os.Bundle); method @NonNull public android.telecom.ConnectionRequest.Builder setExtras(@NonNull android.os.Bundle);
method @NonNull public android.telecom.ConnectionRequest.Builder setIsAdhocConferenceCall(boolean);
method @NonNull public android.telecom.ConnectionRequest.Builder setParticipants(@Nullable java.util.List<android.net.Uri>);
method @NonNull public android.telecom.ConnectionRequest.Builder setRttPipeFromInCall(@NonNull android.os.ParcelFileDescriptor); method @NonNull public android.telecom.ConnectionRequest.Builder setRttPipeFromInCall(@NonNull android.os.ParcelFileDescriptor);
method @NonNull public android.telecom.ConnectionRequest.Builder setRttPipeToInCall(@NonNull android.os.ParcelFileDescriptor); method @NonNull public android.telecom.ConnectionRequest.Builder setRttPipeToInCall(@NonNull android.os.ParcelFileDescriptor);
method @NonNull public android.telecom.ConnectionRequest.Builder setShouldShowIncomingCallUi(boolean); method @NonNull public android.telecom.ConnectionRequest.Builder setShouldShowIncomingCallUi(boolean);

View File

@@ -547,8 +547,14 @@ public final class Call {
*/ */
public static final int PROPERTY_VOIP_AUDIO_MODE = 0x00001000; public static final int PROPERTY_VOIP_AUDIO_MODE = 0x00001000;
/**
* Indicates that the call is an adhoc conference call. This property can be set for both
* incoming and outgoing calls.
*/
public static final int PROPERTY_IS_ADHOC_CONFERENCE = 0x00002000;
//****************************************************************************************** //******************************************************************************************
// Next PROPERTY value: 0x00002000 // Next PROPERTY value: 0x00004000
//****************************************************************************************** //******************************************************************************************
private final String mTelecomCallId; private final String mTelecomCallId;
@@ -726,6 +732,9 @@ public final class Call {
if (hasProperty(properties, PROPERTY_VOIP_AUDIO_MODE)) { if (hasProperty(properties, PROPERTY_VOIP_AUDIO_MODE)) {
builder.append(" PROPERTY_VOIP_AUDIO_MODE"); builder.append(" PROPERTY_VOIP_AUDIO_MODE");
} }
if (hasProperty(properties, PROPERTY_IS_ADHOC_CONFERENCE)) {
builder.append(" PROPERTY_IS_ADHOC_CONFERENCE");
}
builder.append("]"); builder.append("]");
return builder.toString(); return builder.toString();
} }

View File

@@ -69,6 +69,7 @@ public abstract class Conference extends Conferenceable {
public void onConnectionEvent(Conference c, String event, Bundle extras) {} public void onConnectionEvent(Conference c, String event, Bundle extras) {}
public void onCallerDisplayNameChanged( public void onCallerDisplayNameChanged(
Conference c, String callerDisplayName, int presentation) {} Conference c, String callerDisplayName, int presentation) {}
public void onRingbackRequested(Conference c, boolean ringback) {}
} }
private final Set<Listener> mListeners = new CopyOnWriteArraySet<>(); private final Set<Listener> mListeners = new CopyOnWriteArraySet<>();
@@ -97,6 +98,7 @@ public abstract class Conference extends Conferenceable {
private int mAddressPresentation; private int mAddressPresentation;
private String mCallerDisplayName; private String mCallerDisplayName;
private int mCallerDisplayNamePresentation; private int mCallerDisplayNamePresentation;
private boolean mRingbackRequested = false;
private final Connection.Listener mConnectionDeathListener = new Connection.Listener() { private final Connection.Listener mConnectionDeathListener = new Connection.Listener() {
@Override @Override
@@ -169,6 +171,14 @@ public abstract class Conference extends Conferenceable {
return mState; return mState;
} }
/**
* Returns whether this conference is requesting that the system play a ringback tone
* on its behalf.
*/
public final boolean isRingbackRequested() {
return mRingbackRequested;
}
/** /**
* Returns the capabilities of the conference. See {@code CAPABILITY_*} constants in class * Returns the capabilities of the conference. See {@code CAPABILITY_*} constants in class
* {@link Connection} for valid values. * {@link Connection} for valid values.
@@ -307,6 +317,35 @@ public abstract class Conference extends Conferenceable {
*/ */
public void onConnectionAdded(Connection connection) {} public void onConnectionAdded(Connection connection) {}
/**
* Notifies this Conference, which is in {@code STATE_RINGING}, of
* a request to accept.
* For managed {@link ConnectionService}s, this will be called when the user answers a call via
* the default dialer's {@link InCallService}.
*
* @param videoState The video state in which to answer the connection.
*/
public void onAnswer(int videoState) {}
/**
* Notifies this Conference, which is in {@code STATE_RINGING}, of
* a request to accept.
* For managed {@link ConnectionService}s, this will be called when the user answers a call via
* the default dialer's {@link InCallService}.
* @hide
*/
public final void onAnswer() {
onAnswer(VideoProfile.STATE_AUDIO_ONLY);
}
/**
* Notifies this Conference, which is in {@code STATE_RINGING}, of
* a request to reject.
* For managed {@link ConnectionService}s, this will be called when the user rejects a call via
* the default dialer's {@link InCallService}.
*/
public void onReject() {}
/** /**
* Sets state to be on hold. * Sets state to be on hold.
*/ */
@@ -321,10 +360,18 @@ public abstract class Conference extends Conferenceable {
setState(Connection.STATE_DIALING); setState(Connection.STATE_DIALING);
} }
/**
* Sets state to be ringing.
*/
public final void setRinging() {
setState(Connection.STATE_RINGING);
}
/** /**
* Sets state to be active. * Sets state to be active.
*/ */
public final void setActive() { public final void setActive() {
setRingbackRequested(false);
setState(Connection.STATE_ACTIVE); setState(Connection.STATE_ACTIVE);
} }
@@ -435,6 +482,21 @@ public abstract class Conference extends Conferenceable {
fireOnConferenceableConnectionsChanged(); fireOnConferenceableConnectionsChanged();
} }
/**
* Requests that the framework play a ringback tone. This is to be invoked by implementations
* that do not play a ringback tone themselves in the conference's audio stream.
*
* @param ringback Whether the ringback tone is to be played.
*/
public final void setRingbackRequested(boolean ringback) {
if (mRingbackRequested != ringback) {
mRingbackRequested = ringback;
for (Listener l : mListeners) {
l.onRingbackRequested(this, ringback);
}
}
}
/** /**
* Set the video state for the conference. * Set the video state for the conference.
* Valid values: {@link VideoProfile#STATE_AUDIO_ONLY}, * Valid values: {@link VideoProfile#STATE_AUDIO_ONLY},
@@ -640,14 +702,6 @@ public abstract class Conference extends Conferenceable {
} }
private void setState(int newState) { private void setState(int newState) {
if (newState != Connection.STATE_ACTIVE &&
newState != Connection.STATE_HOLDING &&
newState != Connection.STATE_DISCONNECTED) {
Log.w(this, "Unsupported state transition for Conference call.",
Connection.stateToString(newState));
return;
}
if (mState != newState) { if (mState != newState) {
int oldState = mState; int oldState = mState;
mState = newState; mState = newState;
@@ -657,6 +711,37 @@ public abstract class Conference extends Conferenceable {
} }
} }
private static class FailureSignalingConference extends Conference {
private boolean mImmutable = false;
public FailureSignalingConference(DisconnectCause disconnectCause,
PhoneAccountHandle phoneAccount) {
super(phoneAccount);
setDisconnected(disconnectCause);
mImmutable = true;
}
public void checkImmutable() {
if (mImmutable) {
throw new UnsupportedOperationException("Conference is immutable");
}
}
}
/**
* Return a {@code Conference} which represents a failed conference attempt. The returned
* {@code Conference} will have a {@link android.telecom.DisconnectCause} and as specified,
* and a {@link #getState()} of {@code STATE_DISCONNECTED}.
* <p>
* The returned {@code Conference} can be assumed to {@link #destroy()} itself when appropriate,
* so users of this method need not maintain a reference to its return value to destroy it.
*
* @param disconnectCause The disconnect cause, ({@see android.telecomm.DisconnectCause}).
* @return A {@code Conference} which indicates failure.
*/
public @NonNull static Conference createFailedConference(
@NonNull DisconnectCause disconnectCause, @NonNull PhoneAccountHandle phoneAccount) {
return new FailureSignalingConference(disconnectCause, phoneAccount);
}
private final void clearConferenceableList() { private final void clearConferenceableList() {
for (Connection c : mConferenceableConnections) { for (Connection c : mConferenceableConnections) {
c.removeConnectionListener(mConnectionDeathListener); c.removeConnectionListener(mConnectionDeathListener);
@@ -667,11 +752,13 @@ public abstract class Conference extends Conferenceable {
@Override @Override
public String toString() { public String toString() {
return String.format(Locale.US, return String.format(Locale.US,
"[State: %s,Capabilites: %s, VideoState: %s, VideoProvider: %s, ThisObject %s]", "[State: %s,Capabilites: %s, VideoState: %s, VideoProvider: %s,"
+ "isRingbackRequested: %s, ThisObject %s]",
Connection.stateToString(mState), Connection.stateToString(mState),
Call.Details.capabilitiesToString(mConnectionCapabilities), Call.Details.capabilitiesToString(mConnectionCapabilities),
getVideoState(), getVideoState(),
getVideoProvider(), getVideoProvider(),
isRingbackRequested() ? "Y" : "N",
super.toString()); super.toString());
} }

View File

@@ -497,8 +497,17 @@ public abstract class Connection extends Conferenceable {
@TestApi @TestApi
public static final int PROPERTY_REMOTELY_HOSTED = 1 << 11; public static final int PROPERTY_REMOTELY_HOSTED = 1 << 11;
/**
* Set by the framework to indicate that it is an adhoc conference call.
* <p>
* This is used for Outgoing and incoming conference calls.
*
*/
public static final int PROPERTY_IS_ADHOC_CONFERENCE = 1 << 12;
//********************************************************************************************** //**********************************************************************************************
// Next PROPERTY value: 1<<12 // Next PROPERTY value: 1<<13
//********************************************************************************************** //**********************************************************************************************
/** /**
@@ -1018,6 +1027,10 @@ public abstract class Connection extends Conferenceable {
builder.append(isLong ? " PROPERTY_REMOTELY_HOSTED" : " remote_hst"); builder.append(isLong ? " PROPERTY_REMOTELY_HOSTED" : " remote_hst");
} }
if ((properties & PROPERTY_IS_ADHOC_CONFERENCE) == PROPERTY_IS_ADHOC_CONFERENCE) {
builder.append(isLong ? " PROPERTY_IS_ADHOC_CONFERENCE" : " adhoc_conf");
}
builder.append("]"); builder.append("]");
return builder.toString(); return builder.toString();
} }

View File

@@ -26,6 +26,9 @@ import android.os.Parcel;
import android.os.ParcelFileDescriptor; import android.os.ParcelFileDescriptor;
import android.os.Parcelable; import android.os.Parcelable;
import java.util.ArrayList;
import java.util.List;
/** /**
* Simple data container encapsulating a request to some entity to * Simple data container encapsulating a request to some entity to
* create a new {@link Connection}. * create a new {@link Connection}.
@@ -46,6 +49,8 @@ public final class ConnectionRequest implements Parcelable {
private boolean mShouldShowIncomingCallUi = false; private boolean mShouldShowIncomingCallUi = false;
private ParcelFileDescriptor mRttPipeToInCall; private ParcelFileDescriptor mRttPipeToInCall;
private ParcelFileDescriptor mRttPipeFromInCall; private ParcelFileDescriptor mRttPipeFromInCall;
private List<Uri> mParticipants;
private boolean mIsAdhocConference = false;
public Builder() { } public Builder() { }
@@ -58,6 +63,15 @@ public final class ConnectionRequest implements Parcelable {
return this; return this;
} }
/**
* Sets the participants for the resulting {@link ConnectionRequest}
* @param participants The participants to which the {@link Connection} is to connect.
*/
public @NonNull Builder setParticipants(@Nullable List<Uri> participants) {
this.mParticipants = participants;
return this;
}
/** /**
* Sets the address for the resulting {@link ConnectionRequest} * Sets the address for the resulting {@link ConnectionRequest}
* @param address The address(e.g., phone number) to which the {@link Connection} is to * @param address The address(e.g., phone number) to which the {@link Connection} is to
@@ -107,6 +121,16 @@ public final class ConnectionRequest implements Parcelable {
return this; return this;
} }
/**
* Sets isAdhocConference for the resulting {@link ConnectionRequest}
* @param isAdhocConference {@code true} if it is a adhoc conference call
* {@code false}, if not a adhoc conference call
*/
public @NonNull Builder setIsAdhocConferenceCall(boolean isAdhocConference) {
this.mIsAdhocConference = isAdhocConference;
return this;
}
/** /**
* Sets the RTT pipe for transferring text into the {@link ConnectionService} for the * Sets the RTT pipe for transferring text into the {@link ConnectionService} for the
* resulting {@link ConnectionRequest} * resulting {@link ConnectionRequest}
@@ -141,7 +165,9 @@ public final class ConnectionRequest implements Parcelable {
mTelecomCallId, mTelecomCallId,
mShouldShowIncomingCallUi, mShouldShowIncomingCallUi,
mRttPipeFromInCall, mRttPipeFromInCall,
mRttPipeToInCall); mRttPipeToInCall,
mParticipants,
mIsAdhocConference);
} }
} }
@@ -155,6 +181,8 @@ public final class ConnectionRequest implements Parcelable {
private final ParcelFileDescriptor mRttPipeFromInCall; private final ParcelFileDescriptor mRttPipeFromInCall;
// Cached return value of getRttTextStream -- we don't want to wrap it more than once. // Cached return value of getRttTextStream -- we don't want to wrap it more than once.
private Connection.RttTextStream mRttTextStream; private Connection.RttTextStream mRttTextStream;
private List<Uri> mParticipants;
private final boolean mIsAdhocConference;
/** /**
* @param accountHandle The accountHandle which should be used to place the call. * @param accountHandle The accountHandle which should be used to place the call.
@@ -214,6 +242,21 @@ public final class ConnectionRequest implements Parcelable {
boolean shouldShowIncomingCallUi, boolean shouldShowIncomingCallUi,
ParcelFileDescriptor rttPipeFromInCall, ParcelFileDescriptor rttPipeFromInCall,
ParcelFileDescriptor rttPipeToInCall) { ParcelFileDescriptor rttPipeToInCall) {
this(accountHandle, handle, extras, videoState, telecomCallId,
shouldShowIncomingCallUi, rttPipeFromInCall, rttPipeToInCall, null, false);
}
private ConnectionRequest(
PhoneAccountHandle accountHandle,
Uri handle,
Bundle extras,
int videoState,
String telecomCallId,
boolean shouldShowIncomingCallUi,
ParcelFileDescriptor rttPipeFromInCall,
ParcelFileDescriptor rttPipeToInCall,
List<Uri> participants,
boolean isAdhocConference) {
mAccountHandle = accountHandle; mAccountHandle = accountHandle;
mAddress = handle; mAddress = handle;
mExtras = extras; mExtras = extras;
@@ -222,6 +265,8 @@ public final class ConnectionRequest implements Parcelable {
mShouldShowIncomingCallUi = shouldShowIncomingCallUi; mShouldShowIncomingCallUi = shouldShowIncomingCallUi;
mRttPipeFromInCall = rttPipeFromInCall; mRttPipeFromInCall = rttPipeFromInCall;
mRttPipeToInCall = rttPipeToInCall; mRttPipeToInCall = rttPipeToInCall;
mParticipants = participants;
mIsAdhocConference = isAdhocConference;
} }
private ConnectionRequest(Parcel in) { private ConnectionRequest(Parcel in) {
@@ -233,6 +278,11 @@ public final class ConnectionRequest implements Parcelable {
mShouldShowIncomingCallUi = in.readInt() == 1; mShouldShowIncomingCallUi = in.readInt() == 1;
mRttPipeFromInCall = in.readParcelable(getClass().getClassLoader()); mRttPipeFromInCall = in.readParcelable(getClass().getClassLoader());
mRttPipeToInCall = in.readParcelable(getClass().getClassLoader()); mRttPipeToInCall = in.readParcelable(getClass().getClassLoader());
mParticipants = new ArrayList<Uri>();
in.readList(mParticipants, getClass().getClassLoader());
mIsAdhocConference = in.readInt() == 1;
} }
/** /**
@@ -245,6 +295,11 @@ public final class ConnectionRequest implements Parcelable {
*/ */
public Uri getAddress() { return mAddress; } public Uri getAddress() { return mAddress; }
/**
* The participants to which the {@link Connection} is to connect.
*/
public @Nullable List<Uri> getParticipants() { return mParticipants; }
/** /**
* Application-specific extra data. Used for passing back information from an incoming * Application-specific extra data. Used for passing back information from an incoming
* call {@code Intent}, and for any proprietary extensions arranged between a client * call {@code Intent}, and for any proprietary extensions arranged between a client
@@ -289,6 +344,13 @@ public final class ConnectionRequest implements Parcelable {
return mShouldShowIncomingCallUi; return mShouldShowIncomingCallUi;
} }
/**
* @return {@code true} if the call is a adhoc conference call else @return {@code false}
*/
public boolean isAdhocConferenceCall() {
return mIsAdhocConference;
}
/** /**
* Gets the {@link ParcelFileDescriptor} that is used to send RTT text from the connection * Gets the {@link ParcelFileDescriptor} that is used to send RTT text from the connection
* service to the in-call UI. In order to obtain an * service to the in-call UI. In order to obtain an
@@ -345,11 +407,12 @@ public final class ConnectionRequest implements Parcelable {
@Override @Override
public String toString() { public String toString() {
return String.format("ConnectionRequest %s %s", return String.format("ConnectionRequest %s %s isAdhocConf: %s",
mAddress == null mAddress == null
? Uri.EMPTY ? Uri.EMPTY
: Connection.toLogSafePhoneNumber(mAddress.toString()), : Connection.toLogSafePhoneNumber(mAddress.toString()),
bundleToString(mExtras)); bundleToString(mExtras),
isAdhocConferenceCall() ? "Y" : "N");
} }
private static String bundleToString(Bundle extras){ private static String bundleToString(Bundle extras){
@@ -406,5 +469,7 @@ public final class ConnectionRequest implements Parcelable {
destination.writeInt(mShouldShowIncomingCallUi ? 1 : 0); destination.writeInt(mShouldShowIncomingCallUi ? 1 : 0);
destination.writeParcelable(mRttPipeFromInCall, 0); destination.writeParcelable(mRttPipeFromInCall, 0);
destination.writeParcelable(mRttPipeToInCall, 0); destination.writeParcelable(mRttPipeToInCall, 0);
destination.writeList(mParticipants);
destination.writeInt(mIsAdhocConference ? 1 : 0);
} }
} }

View File

@@ -154,6 +154,9 @@ public abstract class ConnectionService extends Service {
private static final String SESSION_CONNECTION_SERVICE_FOCUS_LOST = "CS.cSFL"; private static final String SESSION_CONNECTION_SERVICE_FOCUS_LOST = "CS.cSFL";
private static final String SESSION_CONNECTION_SERVICE_FOCUS_GAINED = "CS.cSFG"; private static final String SESSION_CONNECTION_SERVICE_FOCUS_GAINED = "CS.cSFG";
private static final String SESSION_HANDOVER_FAILED = "CS.haF"; private static final String SESSION_HANDOVER_FAILED = "CS.haF";
private static final String SESSION_CREATE_CONF = "CS.crConf";
private static final String SESSION_CREATE_CONF_COMPLETE = "CS.crConfC";
private static final String SESSION_CREATE_CONF_FAILED = "CS.crConfF";
private static final int MSG_ADD_CONNECTION_SERVICE_ADAPTER = 1; private static final int MSG_ADD_CONNECTION_SERVICE_ADAPTER = 1;
private static final int MSG_CREATE_CONNECTION = 2; private static final int MSG_CREATE_CONNECTION = 2;
@@ -188,6 +191,9 @@ public abstract class ConnectionService extends Service {
private static final int MSG_HANDOVER_FAILED = 32; private static final int MSG_HANDOVER_FAILED = 32;
private static final int MSG_HANDOVER_COMPLETE = 33; private static final int MSG_HANDOVER_COMPLETE = 33;
private static final int MSG_DEFLECT = 34; private static final int MSG_DEFLECT = 34;
private static final int MSG_CREATE_CONFERENCE = 35;
private static final int MSG_CREATE_CONFERENCE_COMPLETE = 36;
private static final int MSG_CREATE_CONFERENCE_FAILED = 37;
private static Connection sNullConnection; private static Connection sNullConnection;
@@ -290,6 +296,63 @@ public abstract class ConnectionService extends Service {
} }
} }
@Override
public void createConference(
PhoneAccountHandle connectionManagerPhoneAccount,
String id,
ConnectionRequest request,
boolean isIncoming,
boolean isUnknown,
Session.Info sessionInfo) {
Log.startSession(sessionInfo, SESSION_CREATE_CONF);
try {
SomeArgs args = SomeArgs.obtain();
args.arg1 = connectionManagerPhoneAccount;
args.arg2 = id;
args.arg3 = request;
args.arg4 = Log.createSubsession();
args.argi1 = isIncoming ? 1 : 0;
args.argi2 = isUnknown ? 1 : 0;
mHandler.obtainMessage(MSG_CREATE_CONFERENCE, args).sendToTarget();
} finally {
Log.endSession();
}
}
@Override
public void createConferenceComplete(String id, Session.Info sessionInfo) {
Log.startSession(sessionInfo, SESSION_CREATE_CONF_COMPLETE);
try {
SomeArgs args = SomeArgs.obtain();
args.arg1 = id;
args.arg2 = Log.createSubsession();
mHandler.obtainMessage(MSG_CREATE_CONFERENCE_COMPLETE, args).sendToTarget();
} finally {
Log.endSession();
}
}
@Override
public void createConferenceFailed(
PhoneAccountHandle connectionManagerPhoneAccount,
String callId,
ConnectionRequest request,
boolean isIncoming,
Session.Info sessionInfo) {
Log.startSession(sessionInfo, SESSION_CREATE_CONF_FAILED);
try {
SomeArgs args = SomeArgs.obtain();
args.arg1 = callId;
args.arg2 = request;
args.arg3 = Log.createSubsession();
args.arg4 = connectionManagerPhoneAccount;
args.argi1 = isIncoming ? 1 : 0;
mHandler.obtainMessage(MSG_CREATE_CONFERENCE_FAILED, args).sendToTarget();
} finally {
Log.endSession();
}
}
@Override @Override
public void handoverFailed(String callId, ConnectionRequest request, int reason, public void handoverFailed(String callId, ConnectionRequest request, int reason,
Session.Info sessionInfo) { Session.Info sessionInfo) {
@@ -802,6 +865,106 @@ public abstract class ConnectionService extends Service {
} }
break; break;
} }
case MSG_CREATE_CONFERENCE: {
SomeArgs args = (SomeArgs) msg.obj;
Log.continueSession((Session) args.arg4, SESSION_HANDLER + SESSION_CREATE_CONN);
try {
final PhoneAccountHandle connectionManagerPhoneAccount =
(PhoneAccountHandle) args.arg1;
final String id = (String) args.arg2;
final ConnectionRequest request = (ConnectionRequest) args.arg3;
final boolean isIncoming = args.argi1 == 1;
final boolean isUnknown = args.argi2 == 1;
if (!mAreAccountsInitialized) {
Log.d(this, "Enqueueing pre-initconference request %s", id);
mPreInitializationConnectionRequests.add(
new android.telecom.Logging.Runnable(
SESSION_HANDLER + SESSION_CREATE_CONF + ".pIConfR",
null /*lock*/) {
@Override
public void loggedRun() {
createConference(connectionManagerPhoneAccount,
id,
request,
isIncoming,
isUnknown);
}
}.prepare());
} else {
createConference(connectionManagerPhoneAccount,
id,
request,
isIncoming,
isUnknown);
}
} finally {
args.recycle();
Log.endSession();
}
break;
}
case MSG_CREATE_CONFERENCE_COMPLETE: {
SomeArgs args = (SomeArgs) msg.obj;
Log.continueSession((Session) args.arg2,
SESSION_HANDLER + SESSION_CREATE_CONN_COMPLETE);
try {
final String id = (String) args.arg1;
if (!mAreAccountsInitialized) {
Log.d(this, "Enqueueing pre-init conference request %s", id);
mPreInitializationConnectionRequests.add(
new android.telecom.Logging.Runnable(
SESSION_HANDLER + SESSION_CREATE_CONF_COMPLETE
+ ".pIConfR",
null /*lock*/) {
@Override
public void loggedRun() {
notifyCreateConferenceComplete(id);
}
}.prepare());
} else {
notifyCreateConferenceComplete(id);
}
} finally {
args.recycle();
Log.endSession();
}
break;
}
case MSG_CREATE_CONFERENCE_FAILED: {
SomeArgs args = (SomeArgs) msg.obj;
Log.continueSession((Session) args.arg3, SESSION_HANDLER +
SESSION_CREATE_CONN_FAILED);
try {
final String id = (String) args.arg1;
final ConnectionRequest request = (ConnectionRequest) args.arg2;
final boolean isIncoming = args.argi1 == 1;
final PhoneAccountHandle connectionMgrPhoneAccount =
(PhoneAccountHandle) args.arg4;
if (!mAreAccountsInitialized) {
Log.d(this, "Enqueueing pre-init conference request %s", id);
mPreInitializationConnectionRequests.add(
new android.telecom.Logging.Runnable(
SESSION_HANDLER + SESSION_CREATE_CONF_FAILED
+ ".pIConfR",
null /*lock*/) {
@Override
public void loggedRun() {
createConferenceFailed(connectionMgrPhoneAccount, id,
request, isIncoming);
}
}.prepare());
} else {
Log.i(this, "createConferenceFailed %s", id);
createConferenceFailed(connectionMgrPhoneAccount, id, request,
isIncoming);
}
} finally {
args.recycle();
Log.endSession();
}
break;
}
case MSG_HANDOVER_FAILED: { case MSG_HANDOVER_FAILED: {
SomeArgs args = (SomeArgs) msg.obj; SomeArgs args = (SomeArgs) msg.obj;
Log.continueSession((Session) args.arg3, SESSION_HANDLER + Log.continueSession((Session) args.arg3, SESSION_HANDLER +
@@ -1162,6 +1325,12 @@ public abstract class ConnectionService extends Service {
public void onStateChanged(Conference conference, int oldState, int newState) { public void onStateChanged(Conference conference, int oldState, int newState) {
String id = mIdByConference.get(conference); String id = mIdByConference.get(conference);
switch (newState) { switch (newState) {
case Connection.STATE_RINGING:
mAdapter.setRinging(id);
break;
case Connection.STATE_DIALING:
mAdapter.setDialing(id);
break;
case Connection.STATE_ACTIVE: case Connection.STATE_ACTIVE:
mAdapter.setActive(id); mAdapter.setActive(id);
break; break;
@@ -1292,6 +1461,13 @@ public abstract class ConnectionService extends Service {
mAdapter.onConnectionEvent(id, event, extras); mAdapter.onConnectionEvent(id, event, extras);
} }
} }
@Override
public void onRingbackRequested(Conference c, boolean ringback) {
String id = mIdByConference.get(c);
Log.d(this, "Adapter conference onRingback %b", ringback);
mAdapter.setRingbackRequested(id, ringback);
}
}; };
private final Connection.Listener mConnectionListener = new Connection.Listener() { private final Connection.Listener mConnectionListener = new Connection.Listener() {
@@ -1534,6 +1710,70 @@ public abstract class ConnectionService extends Service {
return super.onUnbind(intent); return super.onUnbind(intent);
} }
/**
* This can be used by telecom to either create a new outgoing conference call or attach
* to an existing incoming conference call. In either case, telecom will cycle through a
* set of services and call createConference until a connection service cancels the process
* or completes it successfully.
*/
private void createConference(
final PhoneAccountHandle callManagerAccount,
final String callId,
final ConnectionRequest request,
boolean isIncoming,
boolean isUnknown) {
Conference conference = null;
conference = isIncoming ? onCreateIncomingConference(callManagerAccount, request)
: onCreateOutgoingConference(callManagerAccount, request);
Log.d(this, "createConference, conference: %s", conference);
if (conference == null) {
Log.i(this, "createConference, implementation returned null conference.");
conference = Conference.createFailedConference(
new DisconnectCause(DisconnectCause.ERROR, "IMPL_RETURNED_NULL_CONFERENCE"),
request.getAccountHandle());
}
if (conference.getExtras() != null) {
conference.getExtras().putString(Connection.EXTRA_ORIGINAL_CONNECTION_ID, callId);
}
mConferenceById.put(callId, conference);
mIdByConference.put(conference, callId);
conference.addListener(mConferenceListener);
ParcelableConference parcelableConference = new ParcelableConference(
request.getAccountHandle(),
conference.getState(),
conference.getConnectionCapabilities(),
conference.getConnectionProperties(),
Collections.<String>emptyList(), //connectionIds
conference.getVideoProvider() == null ?
null : conference.getVideoProvider().getInterface(),
conference.getVideoState(),
conference.getConnectTimeMillis(),
conference.getConnectionStartElapsedRealTime(),
conference.getStatusHints(),
conference.getExtras(),
conference.getAddress(),
conference.getAddressPresentation(),
conference.getCallerDisplayName(),
conference.getCallerDisplayNamePresentation(),
conference.getDisconnectCause(),
conference.isRingbackRequested());
if (conference.getState() != Connection.STATE_DISCONNECTED) {
conference.setTelecomCallId(callId);
mAdapter.setVideoProvider(callId, conference.getVideoProvider());
mAdapter.setVideoState(callId, conference.getVideoState());
onConferenceAdded(conference);
}
Log.d(this, "createConference, calling handleCreateConferenceSuccessful %s", callId);
mAdapter.handleCreateConferenceComplete(
callId,
request,
parcelableConference);
}
/** /**
* This can be used by telecom to either create a new outgoing call or attach to an existing * This can be used by telecom to either create a new outgoing call or attach to an existing
* incoming call. In either case, telecom will cycle through a set of services and call * incoming call. In either case, telecom will cycle through a set of services and call
@@ -1645,6 +1885,18 @@ public abstract class ConnectionService extends Service {
} }
} }
private void createConferenceFailed(final PhoneAccountHandle callManagerAccount,
final String callId, final ConnectionRequest request,
boolean isIncoming) {
Log.i(this, "createConferenceFailed %s", callId);
if (isIncoming) {
onCreateIncomingConferenceFailed(callManagerAccount, request);
} else {
onCreateOutgoingConferenceFailed(callManagerAccount, request);
}
}
private void handoverFailed(final String callId, final ConnectionRequest request, private void handoverFailed(final String callId, final ConnectionRequest request,
int reason) { int reason) {
@@ -1669,6 +1921,24 @@ public abstract class ConnectionService extends Service {
"notifyCreateConnectionComplete")); "notifyCreateConnectionComplete"));
} }
/**
* Called by Telecom when the creation of a new Conference has completed and it is now added
* to Telecom.
* @param callId The ID of the connection.
*/
private void notifyCreateConferenceComplete(final String callId) {
Log.i(this, "notifyCreateConferenceComplete %s", callId);
if (callId == null) {
// This could happen if the conference fails quickly and is removed from the
// ConnectionService before Telecom sends the create conference complete callback.
Log.w(this, "notifyCreateConferenceComplete: callId is null.");
return;
}
onCreateConferenceComplete(findConferenceForAction(callId,
"notifyCreateConferenceComplete"));
}
private void abort(String callId) { private void abort(String callId) {
Log.d(this, "abort %s", callId); Log.d(this, "abort %s", callId);
findConnectionForAction(callId, "abort").onAbort(); findConnectionForAction(callId, "abort").onAbort();
@@ -1676,12 +1946,20 @@ public abstract class ConnectionService extends Service {
private void answerVideo(String callId, int videoState) { private void answerVideo(String callId, int videoState) {
Log.d(this, "answerVideo %s", callId); Log.d(this, "answerVideo %s", callId);
findConnectionForAction(callId, "answer").onAnswer(videoState); if (mConnectionById.containsKey(callId)) {
findConnectionForAction(callId, "answer").onAnswer(videoState);
} else {
findConferenceForAction(callId, "answer").onAnswer(videoState);
}
} }
private void answer(String callId) { private void answer(String callId) {
Log.d(this, "answer %s", callId); Log.d(this, "answer %s", callId);
findConnectionForAction(callId, "answer").onAnswer(); if (mConnectionById.containsKey(callId)) {
findConnectionForAction(callId, "answer").onAnswer();
} else {
findConferenceForAction(callId, "answer").onAnswer();
}
} }
private void deflect(String callId, Uri address) { private void deflect(String callId, Uri address) {
@@ -1691,7 +1969,11 @@ public abstract class ConnectionService extends Service {
private void reject(String callId) { private void reject(String callId) {
Log.d(this, "reject %s", callId); Log.d(this, "reject %s", callId);
findConnectionForAction(callId, "reject").onReject(); if (mConnectionById.containsKey(callId)) {
findConnectionForAction(callId, "reject").onReject();
} else {
findConferenceForAction(callId, "reject").onReject();
}
} }
private void reject(String callId, String rejectWithMessage) { private void reject(String callId, String rejectWithMessage) {
@@ -2198,6 +2480,21 @@ public abstract class ConnectionService extends Service {
ConnectionRequest request) { ConnectionRequest request) {
return null; return null;
} }
/**
* Create a {@code Connection} given an incoming request. This is used to attach to existing
* incoming conference call.
*
* @param connectionManagerPhoneAccount See description at
* {@link #onCreateOutgoingConnection(PhoneAccountHandle, ConnectionRequest)}.
* @param request Details about the incoming call.
* @return The {@code Connection} object to satisfy this call, or {@code null} to
* not handle the call.
*/
public @Nullable Conference onCreateIncomingConference(
@Nullable PhoneAccountHandle connectionManagerPhoneAccount,
@Nullable ConnectionRequest request) {
return null;
}
/** /**
* Called after the {@link Connection} returned by * Called after the {@link Connection} returned by
@@ -2211,6 +2508,19 @@ public abstract class ConnectionService extends Service {
public void onCreateConnectionComplete(Connection connection) { public void onCreateConnectionComplete(Connection connection) {
} }
/**
* Called after the {@link Conference} returned by
* {@link #onCreateIncomingConference(PhoneAccountHandle, ConnectionRequest)}
* or {@link #onCreateOutgoingConference(PhoneAccountHandle, ConnectionRequest)} has been
* added to the {@link ConnectionService} and sent to Telecom.
*
* @param conference the {@link Conference}.
* @hide
*/
public void onCreateConferenceComplete(Conference conference) {
}
/** /**
* Called by Telecom to inform the {@link ConnectionService} that its request to create a new * Called by Telecom to inform the {@link ConnectionService} that its request to create a new
* incoming {@link Connection} was denied. * incoming {@link Connection} was denied.
@@ -2249,6 +2559,47 @@ public abstract class ConnectionService extends Service {
ConnectionRequest request) { ConnectionRequest request) {
} }
/**
* Called by Telecom to inform the {@link ConnectionService} that its request to create a new
* incoming {@link Conference} was denied.
* <p>
* Used when a self-managed {@link ConnectionService} attempts to create a new incoming
* {@link Conference}, but Telecom has determined that the call cannot be allowed at this time.
* The {@link ConnectionService} is responsible for silently rejecting the new incoming
* {@link Conference}.
* <p>
* See {@link TelecomManager#isIncomingCallPermitted(PhoneAccountHandle)} for more information.
*
* @param connectionManagerPhoneAccount See description at
* {@link #onCreateOutgoingConnection(PhoneAccountHandle, ConnectionRequest)}.
* @param request The incoming connection request.
*/
public void onCreateIncomingConferenceFailed(
@Nullable PhoneAccountHandle connectionManagerPhoneAccount,
@Nullable ConnectionRequest request) {
}
/**
* Called by Telecom to inform the {@link ConnectionService} that its request to create a new
* outgoing {@link Conference} was denied.
* <p>
* Used when a self-managed {@link ConnectionService} attempts to create a new outgoing
* {@link Conference}, but Telecom has determined that the call cannot be placed at this time.
* The {@link ConnectionService} is responisible for informing the user that the
* {@link Conference} cannot be made at this time.
* <p>
* See {@link TelecomManager#isOutgoingCallPermitted(PhoneAccountHandle)} for more information.
*
* @param connectionManagerPhoneAccount See description at
* {@link #onCreateOutgoingConnection(PhoneAccountHandle, ConnectionRequest)}.
* @param request The outgoing connection request.
*/
public void onCreateOutgoingConferenceFailed(
@Nullable PhoneAccountHandle connectionManagerPhoneAccount,
@Nullable ConnectionRequest request) {
}
/** /**
* Trigger recalculate functinality for conference calls. This is used when a Telephony * Trigger recalculate functinality for conference calls. This is used when a Telephony
* Connection is part of a conference controller but is not yet added to Connection * Connection is part of a conference controller but is not yet added to Connection
@@ -2288,6 +2639,36 @@ public abstract class ConnectionService extends Service {
return null; return null;
} }
/**
* Create a {@code Conference} given an outgoing request. This is used to initiate new
* outgoing conference call.
*
* @param connectionManagerPhoneAccount The connection manager account to use for managing
* this call.
* <p>
* If this parameter is not {@code null}, it means that this {@code ConnectionService}
* has registered one or more {@code PhoneAccount}s having
* {@link PhoneAccount#CAPABILITY_CONNECTION_MANAGER}. This parameter will contain
* one of these {@code PhoneAccount}s, while the {@code request} will contain another
* (usually but not always distinct) {@code PhoneAccount} to be used for actually
* making the connection.
* <p>
* If this parameter is {@code null}, it means that this {@code ConnectionService} is
* being asked to make a direct connection. The
* {@link ConnectionRequest#getAccountHandle()} of parameter {@code request} will be
* a {@code PhoneAccount} registered by this {@code ConnectionService} to use for
* making the connection.
* @param request Details about the outgoing call.
* @return The {@code Conference} object to satisfy this call, or the result of an invocation
* of {@link Connection#createFailedConnection(DisconnectCause)} to not handle the call.
*/
public @Nullable Conference onCreateOutgoingConference(
@Nullable PhoneAccountHandle connectionManagerPhoneAccount,
@Nullable ConnectionRequest request) {
return null;
}
/** /**
* Called by Telecom to request that a {@link ConnectionService} creates an instance of an * Called by Telecom to request that a {@link ConnectionService} creates an instance of an
* outgoing handover {@link Connection}. * outgoing handover {@link Connection}.

View File

@@ -100,6 +100,19 @@ final class ConnectionServiceAdapter implements DeathRecipient {
} }
} }
void handleCreateConferenceComplete(
String id,
ConnectionRequest request,
ParcelableConference conference) {
for (IConnectionServiceAdapter adapter : mAdapters) {
try {
adapter.handleCreateConferenceComplete(id, request, conference,
Log.getExternalSession());
} catch (RemoteException e) {
}
}
}
/** /**
* Sets a call's state to active (e.g., an ongoing call where two parties can actively * Sets a call's state to active (e.g., an ongoing call where two parties can actively
* communicate). * communicate).

View File

@@ -75,6 +75,7 @@ final class ConnectionServiceAdapterServant {
private static final int MSG_SET_PHONE_ACCOUNT_CHANGED = 34; private static final int MSG_SET_PHONE_ACCOUNT_CHANGED = 34;
private static final int MSG_CONNECTION_SERVICE_FOCUS_RELEASED = 35; private static final int MSG_CONNECTION_SERVICE_FOCUS_RELEASED = 35;
private static final int MSG_SET_CONFERENCE_STATE = 36; private static final int MSG_SET_CONFERENCE_STATE = 36;
private static final int MSG_HANDLE_CREATE_CONFERENCE_COMPLETE = 37;
private final IConnectionServiceAdapter mDelegate; private final IConnectionServiceAdapter mDelegate;
@@ -103,6 +104,19 @@ final class ConnectionServiceAdapterServant {
} }
break; break;
} }
case MSG_HANDLE_CREATE_CONFERENCE_COMPLETE: {
SomeArgs args = (SomeArgs) msg.obj;
try {
mDelegate.handleCreateConferenceComplete(
(String) args.arg1,
(ConnectionRequest) args.arg2,
(ParcelableConference) args.arg3,
null /*Session.Info*/);
} finally {
args.recycle();
}
break;
}
case MSG_SET_ACTIVE: case MSG_SET_ACTIVE:
mDelegate.setActive((String) msg.obj, null /*Session.Info*/); mDelegate.setActive((String) msg.obj, null /*Session.Info*/);
break; break;
@@ -365,6 +379,20 @@ final class ConnectionServiceAdapterServant {
mHandler.obtainMessage(MSG_HANDLE_CREATE_CONNECTION_COMPLETE, args).sendToTarget(); mHandler.obtainMessage(MSG_HANDLE_CREATE_CONNECTION_COMPLETE, args).sendToTarget();
} }
@Override
public void handleCreateConferenceComplete(
String id,
ConnectionRequest request,
ParcelableConference conference,
Session.Info sessionInfo) {
SomeArgs args = SomeArgs.obtain();
args.arg1 = id;
args.arg2 = request;
args.arg3 = conference;
mHandler.obtainMessage(MSG_HANDLE_CREATE_CONFERENCE_COMPLETE, args).sendToTarget();
}
@Override @Override
public void setActive(String connectionId, Session.Info sessionInfo) { public void setActive(String connectionId, Session.Info sessionInfo) {
mHandler.obtainMessage(MSG_SET_ACTIVE, connectionId).sendToTarget(); mHandler.obtainMessage(MSG_SET_ACTIVE, connectionId).sendToTarget();

View File

@@ -47,6 +47,34 @@ public final class ParcelableConference implements Parcelable {
private final int mAddressPresentation; private final int mAddressPresentation;
private final String mCallerDisplayName; private final String mCallerDisplayName;
private final int mCallerDisplayNamePresentation; private final int mCallerDisplayNamePresentation;
private DisconnectCause mDisconnectCause;
private boolean mRingbackRequested;
public ParcelableConference(
PhoneAccountHandle phoneAccount,
int state,
int connectionCapabilities,
int connectionProperties,
List<String> connectionIds,
IVideoProvider videoProvider,
int videoState,
long connectTimeMillis,
long connectElapsedTimeMillis,
StatusHints statusHints,
Bundle extras,
Uri address,
int addressPresentation,
String callerDisplayName,
int callerDisplayNamePresentation,
DisconnectCause disconnectCause,
boolean ringbackRequested) {
this(phoneAccount, state, connectionCapabilities, connectionProperties, connectionIds,
videoProvider, videoState, connectTimeMillis, connectElapsedTimeMillis,
statusHints, extras, address, addressPresentation, callerDisplayName,
callerDisplayNamePresentation);
mDisconnectCause = disconnectCause;
mRingbackRequested = ringbackRequested;
}
public ParcelableConference( public ParcelableConference(
PhoneAccountHandle phoneAccount, PhoneAccountHandle phoneAccount,
@@ -79,6 +107,8 @@ public final class ParcelableConference implements Parcelable {
mAddressPresentation = addressPresentation; mAddressPresentation = addressPresentation;
mCallerDisplayName = callerDisplayName; mCallerDisplayName = callerDisplayName;
mCallerDisplayNamePresentation = callerDisplayNamePresentation; mCallerDisplayNamePresentation = callerDisplayNamePresentation;
mDisconnectCause = null;
mRingbackRequested = false;
} }
@Override @Override
@@ -100,6 +130,10 @@ public final class ParcelableConference implements Parcelable {
.append(mVideoState) .append(mVideoState)
.append(", VideoProvider: ") .append(", VideoProvider: ")
.append(mVideoProvider) .append(mVideoProvider)
.append(", isRingbackRequested: ")
.append(mRingbackRequested)
.append(", disconnectCause: ")
.append(mDisconnectCause)
.toString(); .toString();
} }
@@ -151,6 +185,13 @@ public final class ParcelableConference implements Parcelable {
return mAddress; return mAddress;
} }
public final DisconnectCause getDisconnectCause() {
return mDisconnectCause;
}
public boolean isRingbackRequested() {
return mRingbackRequested;
}
public int getHandlePresentation() { public int getHandlePresentation() {
return mAddressPresentation; return mAddressPresentation;
} }
@@ -177,11 +218,14 @@ public final class ParcelableConference implements Parcelable {
int addressPresentation = source.readInt(); int addressPresentation = source.readInt();
String callerDisplayName = source.readString(); String callerDisplayName = source.readString();
int callerDisplayNamePresentation = source.readInt(); int callerDisplayNamePresentation = source.readInt();
DisconnectCause disconnectCause = source.readParcelable(classLoader);
boolean isRingbackRequested = source.readInt() == 1;
return new ParcelableConference(phoneAccount, state, capabilities, properties, return new ParcelableConference(phoneAccount, state, capabilities, properties,
connectionIds, videoCallProvider, videoState, connectTimeMillis, connectionIds, videoCallProvider, videoState, connectTimeMillis,
connectElapsedTimeMillis, statusHints, extras, address, addressPresentation, connectElapsedTimeMillis, statusHints, extras, address, addressPresentation,
callerDisplayName, callerDisplayNamePresentation); callerDisplayName, callerDisplayNamePresentation, disconnectCause,
isRingbackRequested);
} }
@Override @Override
@@ -215,5 +259,7 @@ public final class ParcelableConference implements Parcelable {
destination.writeInt(mAddressPresentation); destination.writeInt(mAddressPresentation);
destination.writeString(mCallerDisplayName); destination.writeString(mCallerDisplayName);
destination.writeInt(mCallerDisplayNamePresentation); destination.writeInt(mCallerDisplayNamePresentation);
destination.writeParcelable(mDisconnectCause, 0);
destination.writeInt(mRingbackRequested ? 1 : 0);
} }
} }

View File

@@ -331,7 +331,17 @@ public final class PhoneAccount implements Parcelable {
*/ */
public static final int CAPABILITY_EMERGENCY_PREFERRED = 0x2000; public static final int CAPABILITY_EMERGENCY_PREFERRED = 0x2000;
/* NEXT CAPABILITY: 0x4000 */ /**
* An adhoc conference call is established by providing a list of addresses to
* {@code TelecomManager#startConference(List<Uri>, int videoState)} where the
* {@link ConnectionService} is responsible for connecting all indicated participants
* to a conference simultaneously.
* This is in contrast to conferences formed by merging calls together (e.g. using
* {@link android.telecom.Call#mergeConference()}).
*/
public static final int CAPABILITY_ADHOC_CONFERENCE_CALLING = 0x4000;
/* NEXT CAPABILITY: 0x8000 */
/** /**
* URI scheme for telephone number URIs. * URI scheme for telephone number URIs.
@@ -1054,6 +1064,9 @@ public final class PhoneAccount implements Parcelable {
if (hasCapabilities(CAPABILITY_RTT)) { if (hasCapabilities(CAPABILITY_RTT)) {
sb.append("Rtt"); sb.append("Rtt");
} }
if (hasCapabilities(CAPABILITY_ADHOC_CONFERENCE_CALLING)) {
sb.append("AdhocConf");
}
return sb.toString(); return sb.toString();
} }

View File

@@ -100,6 +100,14 @@ final class RemoteConnectionService {
} }
} }
@Override
public void handleCreateConferenceComplete(
String id,
ConnectionRequest request,
ParcelableConference parcel,
Session.Info info) {
}
@Override @Override
public void setActive(String callId, Session.Info sessionInfo) { public void setActive(String callId, Session.Info sessionInfo) {
if (mConnectionById.containsKey(callId)) { if (mConnectionById.containsKey(callId)) {

View File

@@ -1802,6 +1802,45 @@ public class TelecomManager {
} }
} }
/**
* Registers a new incoming conference. A {@link ConnectionService} should invoke this method
* when it has an incoming conference. For managed {@link ConnectionService}s, the specified
* {@link PhoneAccountHandle} must have been registered with {@link #registerPhoneAccount} and
* the user must have enabled the corresponding {@link PhoneAccount}. This can be checked using
* {@link #getPhoneAccount}. Self-managed {@link ConnectionService}s must have
* {@link android.Manifest.permission#MANAGE_OWN_CALLS} to add a new incoming call.
* <p>
* The incoming conference you are adding is assumed to have a video state of
* {@link VideoProfile#STATE_AUDIO_ONLY}, unless the extra value
* {@link #EXTRA_INCOMING_VIDEO_STATE} is specified.
* <p>
* Once invoked, this method will cause the system to bind to the {@link ConnectionService}
* associated with the {@link PhoneAccountHandle} and request additional information about the
* call (See {@link ConnectionService#onCreateIncomingConference}) before starting the incoming
* call UI.
* <p>
* For a managed {@link ConnectionService}, a {@link SecurityException} will be thrown if either
* the {@link PhoneAccountHandle} does not correspond to a registered {@link PhoneAccount} or
* the associated {@link PhoneAccount} is not currently enabled by the user.
*
* @param phoneAccount A {@link PhoneAccountHandle} registered with
* {@link #registerPhoneAccount}.
* @param extras A bundle that will be passed through to
* {@link ConnectionService#onCreateIncomingConference}.
*/
public void addNewIncomingConference(@NonNull PhoneAccountHandle phoneAccount,
@NonNull Bundle extras) {
try {
if (isServiceConnected()) {
getTelecomService().addNewIncomingConference(
phoneAccount, extras == null ? new Bundle() : extras);
}
} catch (RemoteException e) {
Log.e(TAG, "RemoteException adding a new incoming conference: " + phoneAccount, e);
}
}
/** /**
* Registers a new unknown call with Telecom. This can only be called by the system Telephony * Registers a new unknown call with Telecom. This can only be called by the system Telephony
* service. This is invoked when Telephony detects a new unknown connection that was neither * service. This is invoked when Telephony detects a new unknown connection that was neither
@@ -2006,6 +2045,42 @@ public class TelecomManager {
} }
} }
/**
* Place a new conference call with the provided participants using the system telecom service
* This method doesn't support placing of emergency calls.
*
* An adhoc conference call is established by providing a list of addresses to
* {@code TelecomManager#startConference(List<Uri>, int videoState)} where the
* {@link ConnectionService} is responsible for connecting all indicated participants
* to a conference simultaneously.
* This is in contrast to conferences formed by merging calls together (e.g. using
* {@link android.telecom.Call#mergeConference()}).
*
* The following keys are supported in the supplied extras.
* <ul>
* <li>{@link #EXTRA_PHONE_ACCOUNT_HANDLE}</li>
* <li>{@link #EXTRA_START_CALL_WITH_SPEAKERPHONE}</li>
* <li>{@link #EXTRA_START_CALL_WITH_VIDEO_STATE}</li>
* </ul>
*
* @param participants List of participants to start conference with
* @param extras Bundle of extras to use with the call
*/
@RequiresPermission(android.Manifest.permission.CALL_PHONE)
public void startConference(@NonNull List<Uri> participants,
@NonNull Bundle extras) {
ITelecomService service = getTelecomService();
if (service != null) {
try {
service.startConference(participants, extras,
mContext.getOpPackageName());
} catch (RemoteException e) {
Log.e(TAG, "Error calling ITelecomService#placeCall", e);
}
}
}
/** /**
* Enables and disables specified phone account. * Enables and disables specified phone account.
* *

View File

@@ -53,6 +53,20 @@ oneway interface IConnectionService {
void createConnectionFailed(in PhoneAccountHandle connectionManagerPhoneAccount, String callId, void createConnectionFailed(in PhoneAccountHandle connectionManagerPhoneAccount, String callId,
in ConnectionRequest request, boolean isIncoming, in Session.Info sessionInfo); in ConnectionRequest request, boolean isIncoming, in Session.Info sessionInfo);
void createConference(
in PhoneAccountHandle connectionManagerPhoneAccount,
String callId,
in ConnectionRequest request,
boolean isIncoming,
boolean isUnknown,
in Session.Info sessionInfo);
void createConferenceComplete(String callId, in Session.Info sessionInfo);
void createConferenceFailed(in PhoneAccountHandle connectionManagerPhoneAccount, String callId,
in ConnectionRequest request, boolean isIncoming, in Session.Info sessionInfo);
void abort(String callId, in Session.Info sessionInfo); void abort(String callId, in Session.Info sessionInfo);
void answerVideo(String callId, int videoState, in Session.Info sessionInfo); void answerVideo(String callId, int videoState, in Session.Info sessionInfo);

View File

@@ -44,6 +44,12 @@ oneway interface IConnectionServiceAdapter {
in ParcelableConnection connection, in ParcelableConnection connection,
in Session.Info sessionInfo); in Session.Info sessionInfo);
void handleCreateConferenceComplete(
String callId,
in ConnectionRequest request,
in ParcelableConference connection,
in Session.Info sessionInfo);
void setActive(String callId, in Session.Info sessionInfo); void setActive(String callId, in Session.Info sessionInfo);
void setRinging(String callId, in Session.Info sessionInfo); void setRinging(String callId, in Session.Info sessionInfo);

View File

@@ -241,11 +241,22 @@ interface ITelecomService {
*/ */
void addNewIncomingCall(in PhoneAccountHandle phoneAccount, in Bundle extras); void addNewIncomingCall(in PhoneAccountHandle phoneAccount, in Bundle extras);
/**
* @see TelecomServiceImpl#addNewIncomingConference
*/
void addNewIncomingConference(in PhoneAccountHandle phoneAccount, in Bundle extras);
/** /**
* @see TelecomServiceImpl#addNewUnknownCall * @see TelecomServiceImpl#addNewUnknownCall
*/ */
void addNewUnknownCall(in PhoneAccountHandle phoneAccount, in Bundle extras); void addNewUnknownCall(in PhoneAccountHandle phoneAccount, in Bundle extras);
/**
* @see TelecomServiceImpl#startConference
*/
void startConference(in List<Uri> participants, in Bundle extras,
String callingPackage);
/** /**
* @see TelecomServiceImpl#placeCall * @see TelecomServiceImpl#placeCall
*/ */

View File

@@ -1079,6 +1079,14 @@ public class CarrierConfigManager {
public static final String KEY_IGNORE_RTT_MODE_SETTING_BOOL = public static final String KEY_IGNORE_RTT_MODE_SETTING_BOOL =
"ignore_rtt_mode_setting_bool"; "ignore_rtt_mode_setting_bool";
/**
* Determines whether adhoc conference calls are supported by a carrier. When {@code true},
* adhoc conference calling is supported, {@code false otherwise}.
*/
public static final String KEY_SUPPORT_ADHOC_CONFERENCE_CALLS_BOOL =
"support_adhoc_conference_calls_bool";
/** /**
* Determines whether conference calls are supported by a carrier. When {@code true}, * Determines whether conference calls are supported by a carrier. When {@code true},
* conference calling is supported, {@code false otherwise}. * conference calling is supported, {@code false otherwise}.
@@ -3522,6 +3530,7 @@ public class CarrierConfigManager {
sDefaults.putBoolean(KEY_CALL_FORWARDING_MAP_NON_NUMBER_TO_VOICEMAIL_BOOL, false); sDefaults.putBoolean(KEY_CALL_FORWARDING_MAP_NON_NUMBER_TO_VOICEMAIL_BOOL, false);
sDefaults.putBoolean(KEY_IGNORE_RTT_MODE_SETTING_BOOL, false); sDefaults.putBoolean(KEY_IGNORE_RTT_MODE_SETTING_BOOL, false);
sDefaults.putInt(KEY_CDMA_3WAYCALL_FLASH_DELAY_INT , 0); sDefaults.putInt(KEY_CDMA_3WAYCALL_FLASH_DELAY_INT , 0);
sDefaults.putBoolean(KEY_SUPPORT_ADHOC_CONFERENCE_CALLS_BOOL, false);
sDefaults.putBoolean(KEY_SUPPORT_CONFERENCE_CALL_BOOL, true); sDefaults.putBoolean(KEY_SUPPORT_CONFERENCE_CALL_BOOL, true);
sDefaults.putBoolean(KEY_SUPPORT_IMS_CONFERENCE_CALL_BOOL, true); sDefaults.putBoolean(KEY_SUPPORT_IMS_CONFERENCE_CALL_BOOL, true);
sDefaults.putBoolean(KEY_SUPPORT_MANAGE_IMS_CONFERENCE_CALL_BOOL, true); sDefaults.putBoolean(KEY_SUPPORT_MANAGE_IMS_CONFERENCE_CALL_BOOL, true);