Merge "Key Conference Participants by User and Endpoint Uris" into nyc-mr1-dev
diff --git a/res/values/strings.xml b/res/values/strings.xml
index c003662..61e0a5b 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -995,6 +995,8 @@
<string name="incall_error_no_phone_number_supplied">To place a call, enter a valid number.</string>
<!-- In-call screen: call failure message displayed in an error dialog -->
<string name="incall_error_call_failed">Call failed.</string>
+ <!-- In-call screen: call failure message displayed in an error dialog -->
+ <string name="incall_error_cannot_add_call">Call cannot be added at this time.</string>
<!-- In-call screen: status message displayed in a dialog when starting an MMI -->
<string name="incall_status_dialed_mmi">Starting MMI sequence\u2026</string>
<!-- In-call screen: message displayed in an error dialog -->
diff --git a/src/com/android/services/telephony/ImsConferenceController.java b/src/com/android/services/telephony/ImsConferenceController.java
index d75481b..d017a9e 100644
--- a/src/com/android/services/telephony/ImsConferenceController.java
+++ b/src/com/android/services/telephony/ImsConferenceController.java
@@ -29,8 +29,10 @@
import java.util.ArrayList;
import java.util.Collections;
+import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
+import java.util.stream.Collectors;
/**
* Manages conferences for IMS connections.
@@ -169,8 +171,8 @@
*/
private void recalculateConferenceable() {
Log.v(this, "recalculateConferenceable : %d", mTelephonyConnections.size());
- List<Conferenceable> activeConnections = new ArrayList<>(mTelephonyConnections.size());
- List<Conferenceable> backgroundConnections = new ArrayList<>(mTelephonyConnections.size());
+ HashSet<Conferenceable> conferenceableSet = new HashSet<>(mTelephonyConnections.size() +
+ mImsConferences.size());
// Loop through and collect all calls which are active or holding
for (TelephonyConnection connection : mTelephonyConnections) {
@@ -191,23 +193,23 @@
// If this connection does not support being in a conference call, then it is not
// conferenceable with any other connection.
if (!connection.isConferenceSupported()) {
- connection.setConferenceableConnections(Collections.<Connection>emptyList());
+ connection.setConferenceables(Collections.<Conferenceable>emptyList());
continue;
}
switch (connection.getState()) {
case Connection.STATE_ACTIVE:
- activeConnections.add(connection);
- continue;
+ // fall through
case Connection.STATE_HOLDING:
- backgroundConnections.add(connection);
+ conferenceableSet.add(connection);
continue;
default:
break;
}
- connection.setConferenceableConnections(Collections.<Connection>emptyList());
+ // This connection is not active or holding, so clear all conferencable connections
+ connection.setConferenceables(Collections.<Conferenceable>emptyList());
}
-
+ // Also loop through all active conferences and collect the ones that are ACTIVE or HOLDING.
for (ImsConference conference : mImsConferences) {
if (Log.DEBUG) {
Log.d(this, "recalc - %s %s", conference.getState(), conference);
@@ -222,62 +224,37 @@
switch (conference.getState()) {
case Connection.STATE_ACTIVE:
- activeConnections.add(conference);
- continue;
+ //fall through
case Connection.STATE_HOLDING:
- backgroundConnections.add(conference);
+ conferenceableSet.add(conference);
continue;
default:
break;
}
}
- Log.v(this, "active: %d, holding: %d", activeConnections.size(),
- backgroundConnections.size());
+ Log.v(this, "conferenceableSet size: " + conferenceableSet.size());
- // Go through all the active connections and set the background connections as
- // conferenceable.
- for (Conferenceable conferenceable : activeConnections) {
- if (conferenceable instanceof Connection) {
- Connection connection = (Connection) conferenceable;
- connection.setConferenceables(backgroundConnections);
+ for (Conferenceable c : conferenceableSet) {
+ if (c instanceof Connection) {
+ // Remove this connection from the Set and add all others
+ List<Conferenceable> conferenceables = conferenceableSet
+ .stream()
+ .filter(conferenceable -> c != conferenceable)
+ .collect(Collectors.toList());
+ ((Connection) c).setConferenceables(conferenceables);
+ } else if (c instanceof Conference) {
+ // Remove all conferences from the set, since we can not conference a conference
+ // to another conference.
+ List<Connection> connections = conferenceableSet
+ .stream()
+ .filter(conferenceable -> conferenceable instanceof Connection)
+ .map(conferenceable -> (Connection) conferenceable)
+ .collect(Collectors.toList());
+ // Conference equivalent to setConferenceables that only accepts Connections
+ ((Conference) c).setConferenceableConnections(connections);
}
}
-
- // Go through all the background connections and set the active connections as
- // conferenceable.
- for (Conferenceable conferenceable : backgroundConnections) {
- if (conferenceable instanceof Connection) {
- Connection connection = (Connection) conferenceable;
- connection.setConferenceables(activeConnections);
- }
-
- }
-
- // Set the conference as conferenceable with all the connections
- for (ImsConference conference : mImsConferences) {
- // If this conference is not being hosted on the current device, we cannot conference it
- // with any other connections.
- if (!conference.isConferenceHost()) {
- if (Log.VERBOSE) {
- Log.v(this, "skipping conference (not hosted on this device): %s",
- conference);
- }
- continue;
- }
-
- List<Connection> nonConferencedConnections =
- new ArrayList<>(mTelephonyConnections.size());
- for (TelephonyConnection c : mTelephonyConnections) {
- if (c.getConference() == null && c.isConferenceSupported()) {
- nonConferencedConnections.add(c);
- }
- }
- if (Log.VERBOSE) {
- Log.v(this, "conference conferenceable: %s", nonConferencedConnections);
- }
- conference.setConferenceableConnections(nonConferencedConnections);
- }
}
/**
diff --git a/src/com/android/services/telephony/TelephonyConferenceController.java b/src/com/android/services/telephony/TelephonyConferenceController.java
index 7da9ea5..fbf5ad0 100644
--- a/src/com/android/services/telephony/TelephonyConferenceController.java
+++ b/src/com/android/services/telephony/TelephonyConferenceController.java
@@ -23,6 +23,7 @@
import java.util.HashSet;
import java.util.List;
import java.util.Set;
+import java.util.stream.Collectors;
import android.net.Uri;
import android.telecom.Conference;
@@ -113,10 +114,7 @@
*/
private void recalculateConferenceable() {
Log.v(this, "recalculateConferenceable : %d", mTelephonyConnections.size());
-
- List<Connection> activeConnections = new ArrayList<>(mTelephonyConnections.size());
- List<Connection> backgroundConnections = new ArrayList<>(
- mTelephonyConnections.size());
+ HashSet<Connection> conferenceableConnections = new HashSet<>(mTelephonyConnections.size());
// Loop through and collect all calls which are active or holding
for (TelephonyConnection connection : mTelephonyConnections) {
@@ -126,10 +124,9 @@
if (connection.isConferenceSupported() && !participatesInFullConference(connection)) {
switch (connection.getState()) {
case Connection.STATE_ACTIVE:
- activeConnections.add(connection);
- continue;
+ //fall through
case Connection.STATE_HOLDING:
- backgroundConnections.add(connection);
+ conferenceableConnections.add(connection);
continue;
default:
break;
@@ -139,34 +136,30 @@
connection.setConferenceableConnections(Collections.<Connection>emptyList());
}
- Log.v(this, "active: %d, holding: %d",
- activeConnections.size(), backgroundConnections.size());
+ Log.v(this, "conferenceable: " + conferenceableConnections.size());
- // Go through all the active connections and set the background connections as
- // conferenceable.
- for (Connection connection : activeConnections) {
- connection.setConferenceableConnections(backgroundConnections);
+ // Go through all the conferenceable connections and add all other conferenceable
+ // connections that is not the connection itself
+ for (Connection c : conferenceableConnections) {
+ List<Connection> connections = conferenceableConnections
+ .stream()
+ // Filter out this connection from the list of connections
+ .filter(connection -> c != connection)
+ .collect(Collectors.toList());
+ c.setConferenceableConnections(connections);
}
- // Go through all the background connections and set the active connections as
- // conferenceable.
- for (Connection connection : backgroundConnections) {
- connection.setConferenceableConnections(activeConnections);
- }
-
- // Set the conference as conferenceable with all the connections
+ // Set the conference as conferenceable with all of the connections that are not in the
+ // conference.
if (mTelephonyConference != null && !isFullConference(mTelephonyConference)) {
- List<Connection> nonConferencedConnections =
- new ArrayList<>(mTelephonyConnections.size());
- for (TelephonyConnection c : mTelephonyConnections) {
- if (c.isConferenceSupported() && c.getConference() == null) {
- nonConferencedConnections.add(c);
- }
- }
- Log.v(this, "conference conferenceable: %s", nonConferencedConnections);
+ List<Connection> nonConferencedConnections = mTelephonyConnections
+ .stream()
+ // Only retrieve Connections that are not in a conference (but support
+ // conferences).
+ .filter(c -> c.isConferenceSupported() && c.getConference() == null)
+ .collect(Collectors.toList());
mTelephonyConference.setConferenceableConnections(nonConferencedConnections);
}
-
// TODO: Do not allow conferencing of already conferenced connections.
}
diff --git a/src/com/android/services/telephony/TelephonyConnectionService.java b/src/com/android/services/telephony/TelephonyConnectionService.java
index a9f2e14..a8f6bca 100644
--- a/src/com/android/services/telephony/TelephonyConnectionService.java
+++ b/src/com/android/services/telephony/TelephonyConnectionService.java
@@ -53,6 +53,7 @@
import com.android.phone.R;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.List;
import java.util.regex.Pattern;
@@ -242,6 +243,17 @@
// connecting it to the underlying Phone.
return emergencyConnection;
} else {
+ if (!canAddCall() && !isEmergencyNumber) {
+ Log.d(this, "onCreateOutgoingConnection, cannot add call .");
+ return Connection.createFailedConnection(
+ new DisconnectCause(DisconnectCause.ERROR,
+ getApplicationContext().getText(
+ R.string.incall_error_cannot_add_call),
+ getApplicationContext().getText(
+ R.string.incall_error_cannot_add_call),
+ "Add call restricted due to ongoing video call"));
+ }
+
// Get the right phone object from the account data passed in.
final Phone phone = getPhoneForAccount(request.getAccountHandle(), isEmergencyNumber);
Connection resultConnection = getTelephonyConnection(request, number, isEmergencyNumber,
@@ -255,6 +267,21 @@
}
}
+ /**
+ * @return {@code true} if any other call is disabling the ability to add calls, {@code false}
+ * otherwise.
+ */
+ private boolean canAddCall() {
+ Collection<Connection> connections = getAllConnections();
+ for (Connection connection : connections) {
+ if (connection.getExtras() != null &&
+ connection.getExtras().getBoolean(Connection.EXTRA_DISABLE_ADD_CALL, false)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
private Connection getTelephonyConnection(final ConnectionRequest request, final String number,
boolean isEmergencyNumber, final Uri handle, Phone phone) {