GsmConferenceController.java revision 8a76b6b8715188f00fff4c0e52d579f10cc53de3
1aa7340388473c1676495a60e30dc6a48d318a489Ihab Awad/* 2aa7340388473c1676495a60e30dc6a48d318a489Ihab Awad * Copyright (C) 2014 The Android Open Source Project 3aa7340388473c1676495a60e30dc6a48d318a489Ihab Awad * 4aa7340388473c1676495a60e30dc6a48d318a489Ihab Awad * Licensed under the Apache License, Version 2.0 (the "License"); 5aa7340388473c1676495a60e30dc6a48d318a489Ihab Awad * you may not use this file except in compliance with the License. 6aa7340388473c1676495a60e30dc6a48d318a489Ihab Awad * You may obtain a copy of the License at 7aa7340388473c1676495a60e30dc6a48d318a489Ihab Awad * 8aa7340388473c1676495a60e30dc6a48d318a489Ihab Awad * http://www.apache.org/licenses/LICENSE-2.0 9aa7340388473c1676495a60e30dc6a48d318a489Ihab Awad * 10aa7340388473c1676495a60e30dc6a48d318a489Ihab Awad * Unless required by applicable law or agreed to in writing, software 11aa7340388473c1676495a60e30dc6a48d318a489Ihab Awad * distributed under the License is distributed on an "AS IS" BASIS, 12aa7340388473c1676495a60e30dc6a48d318a489Ihab Awad * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13aa7340388473c1676495a60e30dc6a48d318a489Ihab Awad * See the License for the specific language governing permissions and 14aa7340388473c1676495a60e30dc6a48d318a489Ihab Awad * limitations under the License. 15aa7340388473c1676495a60e30dc6a48d318a489Ihab Awad */ 16aa7340388473c1676495a60e30dc6a48d318a489Ihab Awad 17aa7340388473c1676495a60e30dc6a48d318a489Ihab Awadpackage com.android.services.telephony; 18aa7340388473c1676495a60e30dc6a48d318a489Ihab Awad 19aa7340388473c1676495a60e30dc6a48d318a489Ihab Awadimport java.util.ArrayList; 206059c9310c85986f38c22940470e5a0ff280806fSantos Cordonimport java.util.Collections; 2153b84fe2dc796ef172d7c0f4b9bdc177cdeb0c0fSantos Cordonimport java.util.HashSet; 22aa7340388473c1676495a60e30dc6a48d318a489Ihab Awadimport java.util.List; 2353b84fe2dc796ef172d7c0f4b9bdc177cdeb0c0fSantos Cordonimport java.util.Set; 24aa7340388473c1676495a60e30dc6a48d318a489Ihab Awad 2553b84fe2dc796ef172d7c0f4b9bdc177cdeb0c0fSantos Cordonimport android.telecomm.Conference; 26aa7340388473c1676495a60e30dc6a48d318a489Ihab Awadimport android.telecomm.Connection; 27aa7340388473c1676495a60e30dc6a48d318a489Ihab Awad 2853b84fe2dc796ef172d7c0f4b9bdc177cdeb0c0fSantos Cordonimport com.android.internal.telephony.Call; 2953b84fe2dc796ef172d7c0f4b9bdc177cdeb0c0fSantos Cordon 30aa7340388473c1676495a60e30dc6a48d318a489Ihab Awad/** 31aa7340388473c1676495a60e30dc6a48d318a489Ihab Awad * Maintains a list of all the known GSM connections and implements GSM-specific conference 32aa7340388473c1676495a60e30dc6a48d318a489Ihab Awad * call functionality. 33aa7340388473c1676495a60e30dc6a48d318a489Ihab Awad */ 343199aa7f8bcb48569eb8289abc055ba0f8496ba8Sailesh Nepalfinal class GsmConferenceController { 352093a451b17c26f4341e9565b65dcaa0e20bbd7dSailesh Nepal private final Connection.Listener mConnectionListener = new Connection.Listener() { 36aa7340388473c1676495a60e30dc6a48d318a489Ihab Awad @Override 37aa7340388473c1676495a60e30dc6a48d318a489Ihab Awad public void onStateChanged(Connection c, int state) { 3853b84fe2dc796ef172d7c0f4b9bdc177cdeb0c0fSantos Cordon recalculate(); 39aa7340388473c1676495a60e30dc6a48d318a489Ihab Awad } 40aa7340388473c1676495a60e30dc6a48d318a489Ihab Awad 41aa7340388473c1676495a60e30dc6a48d318a489Ihab Awad /** ${inheritDoc} */ 42aa7340388473c1676495a60e30dc6a48d318a489Ihab Awad @Override 432093a451b17c26f4341e9565b65dcaa0e20bbd7dSailesh Nepal public void onDisconnected(Connection c, int cause, String message) { 4453b84fe2dc796ef172d7c0f4b9bdc177cdeb0c0fSantos Cordon recalculate(); 45aa7340388473c1676495a60e30dc6a48d318a489Ihab Awad } 46aa7340388473c1676495a60e30dc6a48d318a489Ihab Awad }; 47aa7340388473c1676495a60e30dc6a48d318a489Ihab Awad 48aa7340388473c1676495a60e30dc6a48d318a489Ihab Awad /** The known GSM connections. */ 49aa7340388473c1676495a60e30dc6a48d318a489Ihab Awad private final List<GsmConnection> mGsmConnections = new ArrayList<>(); 50aa7340388473c1676495a60e30dc6a48d318a489Ihab Awad 5153b84fe2dc796ef172d7c0f4b9bdc177cdeb0c0fSantos Cordon private final TelephonyConnectionService mConnectionService; 52aa7340388473c1676495a60e30dc6a48d318a489Ihab Awad 5353b84fe2dc796ef172d7c0f4b9bdc177cdeb0c0fSantos Cordon public GsmConferenceController(TelephonyConnectionService connectionService) { 5453b84fe2dc796ef172d7c0f4b9bdc177cdeb0c0fSantos Cordon mConnectionService = connectionService; 55aa7340388473c1676495a60e30dc6a48d318a489Ihab Awad } 56aa7340388473c1676495a60e30dc6a48d318a489Ihab Awad 5753b84fe2dc796ef172d7c0f4b9bdc177cdeb0c0fSantos Cordon /** The GSM conference connection object. */ 5853b84fe2dc796ef172d7c0f4b9bdc177cdeb0c0fSantos Cordon private Conference mGsmConference; 59aa7340388473c1676495a60e30dc6a48d318a489Ihab Awad 6053b84fe2dc796ef172d7c0f4b9bdc177cdeb0c0fSantos Cordon void add(GsmConnection connection) { 6153b84fe2dc796ef172d7c0f4b9bdc177cdeb0c0fSantos Cordon mGsmConnections.add(connection); 6253b84fe2dc796ef172d7c0f4b9bdc177cdeb0c0fSantos Cordon connection.addConnectionListener(mConnectionListener); 6353b84fe2dc796ef172d7c0f4b9bdc177cdeb0c0fSantos Cordon recalculate(); 643199aa7f8bcb48569eb8289abc055ba0f8496ba8Sailesh Nepal } 653199aa7f8bcb48569eb8289abc055ba0f8496ba8Sailesh Nepal 6653b84fe2dc796ef172d7c0f4b9bdc177cdeb0c0fSantos Cordon void remove(GsmConnection connection) { 6753b84fe2dc796ef172d7c0f4b9bdc177cdeb0c0fSantos Cordon connection.removeConnectionListener(mConnectionListener); 6853b84fe2dc796ef172d7c0f4b9bdc177cdeb0c0fSantos Cordon mGsmConnections.remove(connection); 6953b84fe2dc796ef172d7c0f4b9bdc177cdeb0c0fSantos Cordon recalculate(); 70aa7340388473c1676495a60e30dc6a48d318a489Ihab Awad } 71aa7340388473c1676495a60e30dc6a48d318a489Ihab Awad 726059c9310c85986f38c22940470e5a0ff280806fSantos Cordon private void recalculate() { 736059c9310c85986f38c22940470e5a0ff280806fSantos Cordon recalculateConferenceable(); 7453b84fe2dc796ef172d7c0f4b9bdc177cdeb0c0fSantos Cordon recalculateConference(); 756059c9310c85986f38c22940470e5a0ff280806fSantos Cordon } 766059c9310c85986f38c22940470e5a0ff280806fSantos Cordon 77aa7340388473c1676495a60e30dc6a48d318a489Ihab Awad /** 78aa7340388473c1676495a60e30dc6a48d318a489Ihab Awad * Calculates the conference-capable state of all GSM connections in this connection service. 79aa7340388473c1676495a60e30dc6a48d318a489Ihab Awad */ 806059c9310c85986f38c22940470e5a0ff280806fSantos Cordon private void recalculateConferenceable() { 816059c9310c85986f38c22940470e5a0ff280806fSantos Cordon Log.v(this, "recalculateConferenceable : %d", mGsmConnections.size()); 826059c9310c85986f38c22940470e5a0ff280806fSantos Cordon 836059c9310c85986f38c22940470e5a0ff280806fSantos Cordon List<Connection> activeConnections = new ArrayList<>(mGsmConnections.size()); 846059c9310c85986f38c22940470e5a0ff280806fSantos Cordon List<Connection> backgroundConnections = new ArrayList<>(mGsmConnections.size()); 856059c9310c85986f38c22940470e5a0ff280806fSantos Cordon 866059c9310c85986f38c22940470e5a0ff280806fSantos Cordon // Loop through and collect all calls which are active or holding 87aa7340388473c1676495a60e30dc6a48d318a489Ihab Awad for (GsmConnection connection : mGsmConnections) { 88aa7340388473c1676495a60e30dc6a48d318a489Ihab Awad com.android.internal.telephony.Connection radioConnection = 89aa7340388473c1676495a60e30dc6a48d318a489Ihab Awad connection.getOriginalConnection(); 906059c9310c85986f38c22940470e5a0ff280806fSantos Cordon Log.d(this, "recalc - %s %s", 916059c9310c85986f38c22940470e5a0ff280806fSantos Cordon radioConnection == null ? null : radioConnection.getState(), connection); 92aa7340388473c1676495a60e30dc6a48d318a489Ihab Awad 936059c9310c85986f38c22940470e5a0ff280806fSantos Cordon if (radioConnection != null) { 946059c9310c85986f38c22940470e5a0ff280806fSantos Cordon switch(radioConnection.getState()) { 956059c9310c85986f38c22940470e5a0ff280806fSantos Cordon case ACTIVE: 966059c9310c85986f38c22940470e5a0ff280806fSantos Cordon activeConnections.add(connection); 976059c9310c85986f38c22940470e5a0ff280806fSantos Cordon break; 986059c9310c85986f38c22940470e5a0ff280806fSantos Cordon case HOLDING: 996059c9310c85986f38c22940470e5a0ff280806fSantos Cordon backgroundConnections.add(connection); 1006059c9310c85986f38c22940470e5a0ff280806fSantos Cordon break; 1016059c9310c85986f38c22940470e5a0ff280806fSantos Cordon default: 1026059c9310c85986f38c22940470e5a0ff280806fSantos Cordon connection.setConferenceableConnections( 1036059c9310c85986f38c22940470e5a0ff280806fSantos Cordon Collections.<Connection>emptyList()); 1046059c9310c85986f38c22940470e5a0ff280806fSantos Cordon break; 105aa7340388473c1676495a60e30dc6a48d318a489Ihab Awad } 106aa7340388473c1676495a60e30dc6a48d318a489Ihab Awad } 1076059c9310c85986f38c22940470e5a0ff280806fSantos Cordon } 1086059c9310c85986f38c22940470e5a0ff280806fSantos Cordon 1096059c9310c85986f38c22940470e5a0ff280806fSantos Cordon Log.v(this, "active: %d, holding: %d", 1106059c9310c85986f38c22940470e5a0ff280806fSantos Cordon activeConnections.size(), backgroundConnections.size()); 1116059c9310c85986f38c22940470e5a0ff280806fSantos Cordon 1126059c9310c85986f38c22940470e5a0ff280806fSantos Cordon // Go through all the active connections and set the background connections as 1136059c9310c85986f38c22940470e5a0ff280806fSantos Cordon // conferenceable. 1146059c9310c85986f38c22940470e5a0ff280806fSantos Cordon for (Connection connection : activeConnections) { 1156059c9310c85986f38c22940470e5a0ff280806fSantos Cordon connection.setConferenceableConnections(backgroundConnections); 1166059c9310c85986f38c22940470e5a0ff280806fSantos Cordon } 117aa7340388473c1676495a60e30dc6a48d318a489Ihab Awad 1186059c9310c85986f38c22940470e5a0ff280806fSantos Cordon // Go through all the background connections and set the active connections as 1196059c9310c85986f38c22940470e5a0ff280806fSantos Cordon // conferenceable. 1206059c9310c85986f38c22940470e5a0ff280806fSantos Cordon for (Connection connection : backgroundConnections) { 1216059c9310c85986f38c22940470e5a0ff280806fSantos Cordon connection.setConferenceableConnections(activeConnections); 122aa7340388473c1676495a60e30dc6a48d318a489Ihab Awad } 12353b84fe2dc796ef172d7c0f4b9bdc177cdeb0c0fSantos Cordon // TODO: Do not allow conferencing of already conferenced connections. 12453b84fe2dc796ef172d7c0f4b9bdc177cdeb0c0fSantos Cordon } 12553b84fe2dc796ef172d7c0f4b9bdc177cdeb0c0fSantos Cordon 12653b84fe2dc796ef172d7c0f4b9bdc177cdeb0c0fSantos Cordon private void recalculateConference() { 12753b84fe2dc796ef172d7c0f4b9bdc177cdeb0c0fSantos Cordon Set<GsmConnection> conferencedConnections = new HashSet<>(); 12853b84fe2dc796ef172d7c0f4b9bdc177cdeb0c0fSantos Cordon 12953b84fe2dc796ef172d7c0f4b9bdc177cdeb0c0fSantos Cordon for (GsmConnection connection : mGsmConnections) { 13053b84fe2dc796ef172d7c0f4b9bdc177cdeb0c0fSantos Cordon com.android.internal.telephony.Connection radioConnection = 13153b84fe2dc796ef172d7c0f4b9bdc177cdeb0c0fSantos Cordon connection.getOriginalConnection(); 13253b84fe2dc796ef172d7c0f4b9bdc177cdeb0c0fSantos Cordon 13353b84fe2dc796ef172d7c0f4b9bdc177cdeb0c0fSantos Cordon if (radioConnection != null) { 13453b84fe2dc796ef172d7c0f4b9bdc177cdeb0c0fSantos Cordon Call.State state = radioConnection.getState(); 13553b84fe2dc796ef172d7c0f4b9bdc177cdeb0c0fSantos Cordon Call call = radioConnection.getCall(); 13653b84fe2dc796ef172d7c0f4b9bdc177cdeb0c0fSantos Cordon if ((state == Call.State.ACTIVE || state == Call.State.HOLDING) && 13753b84fe2dc796ef172d7c0f4b9bdc177cdeb0c0fSantos Cordon (call != null && call.isMultiparty())) { 13853b84fe2dc796ef172d7c0f4b9bdc177cdeb0c0fSantos Cordon conferencedConnections.add(connection); 13953b84fe2dc796ef172d7c0f4b9bdc177cdeb0c0fSantos Cordon } 14053b84fe2dc796ef172d7c0f4b9bdc177cdeb0c0fSantos Cordon } 14153b84fe2dc796ef172d7c0f4b9bdc177cdeb0c0fSantos Cordon } 14253b84fe2dc796ef172d7c0f4b9bdc177cdeb0c0fSantos Cordon 14353b84fe2dc796ef172d7c0f4b9bdc177cdeb0c0fSantos Cordon Log.d(this, "Recalculate conference calls %s %s.", 14453b84fe2dc796ef172d7c0f4b9bdc177cdeb0c0fSantos Cordon mGsmConference, conferencedConnections); 14553b84fe2dc796ef172d7c0f4b9bdc177cdeb0c0fSantos Cordon 14653b84fe2dc796ef172d7c0f4b9bdc177cdeb0c0fSantos Cordon if (conferencedConnections.size() < 2) { 14753b84fe2dc796ef172d7c0f4b9bdc177cdeb0c0fSantos Cordon Log.d(this, "less than two conference calls!"); 14853b84fe2dc796ef172d7c0f4b9bdc177cdeb0c0fSantos Cordon // No more connections are conferenced, destroy any existing conference. 14953b84fe2dc796ef172d7c0f4b9bdc177cdeb0c0fSantos Cordon if (mGsmConference != null) { 15053b84fe2dc796ef172d7c0f4b9bdc177cdeb0c0fSantos Cordon Log.d(this, "with a conference to destroy!"); 15153b84fe2dc796ef172d7c0f4b9bdc177cdeb0c0fSantos Cordon mGsmConference.destroy(); 15253b84fe2dc796ef172d7c0f4b9bdc177cdeb0c0fSantos Cordon mGsmConference = null; 15353b84fe2dc796ef172d7c0f4b9bdc177cdeb0c0fSantos Cordon } 15453b84fe2dc796ef172d7c0f4b9bdc177cdeb0c0fSantos Cordon } else { 15553b84fe2dc796ef172d7c0f4b9bdc177cdeb0c0fSantos Cordon if (mGsmConference != null) { 15653b84fe2dc796ef172d7c0f4b9bdc177cdeb0c0fSantos Cordon List<Connection> existingConnections = mGsmConference.getConnections(); 15753b84fe2dc796ef172d7c0f4b9bdc177cdeb0c0fSantos Cordon // Remove any that no longer exist 15853b84fe2dc796ef172d7c0f4b9bdc177cdeb0c0fSantos Cordon for (Connection connection : existingConnections) { 15953b84fe2dc796ef172d7c0f4b9bdc177cdeb0c0fSantos Cordon if (!conferencedConnections.contains(connection)) { 16053b84fe2dc796ef172d7c0f4b9bdc177cdeb0c0fSantos Cordon mGsmConference.removeConnection(connection); 16153b84fe2dc796ef172d7c0f4b9bdc177cdeb0c0fSantos Cordon } 16253b84fe2dc796ef172d7c0f4b9bdc177cdeb0c0fSantos Cordon } 16353b84fe2dc796ef172d7c0f4b9bdc177cdeb0c0fSantos Cordon 16453b84fe2dc796ef172d7c0f4b9bdc177cdeb0c0fSantos Cordon // Add any new ones 16553b84fe2dc796ef172d7c0f4b9bdc177cdeb0c0fSantos Cordon for (Connection connection : conferencedConnections) { 16653b84fe2dc796ef172d7c0f4b9bdc177cdeb0c0fSantos Cordon if (!existingConnections.contains(connection)) { 16753b84fe2dc796ef172d7c0f4b9bdc177cdeb0c0fSantos Cordon mGsmConference.addConnection(connection); 16853b84fe2dc796ef172d7c0f4b9bdc177cdeb0c0fSantos Cordon } 16953b84fe2dc796ef172d7c0f4b9bdc177cdeb0c0fSantos Cordon } 17053b84fe2dc796ef172d7c0f4b9bdc177cdeb0c0fSantos Cordon } else { 17153b84fe2dc796ef172d7c0f4b9bdc177cdeb0c0fSantos Cordon mGsmConference = new GsmConference(null); 17253b84fe2dc796ef172d7c0f4b9bdc177cdeb0c0fSantos Cordon for (Connection connection : conferencedConnections) { 1731c25892dc5f0170441422f15242df8887b7903edSantos Cordon Log.d(this, "Adding a connection to a conference call: %s %s", 1741c25892dc5f0170441422f15242df8887b7903edSantos Cordon mGsmConference, connection); 17553b84fe2dc796ef172d7c0f4b9bdc177cdeb0c0fSantos Cordon mGsmConference.addConnection(connection); 17653b84fe2dc796ef172d7c0f4b9bdc177cdeb0c0fSantos Cordon } 17753b84fe2dc796ef172d7c0f4b9bdc177cdeb0c0fSantos Cordon mConnectionService.addConference(mGsmConference); 17853b84fe2dc796ef172d7c0f4b9bdc177cdeb0c0fSantos Cordon } 1798a76b6b8715188f00fff4c0e52d579f10cc53de3Andrew Lee 1808a76b6b8715188f00fff4c0e52d579f10cc53de3Andrew Lee // Set the conference state to the same state as its child connections. 1818a76b6b8715188f00fff4c0e52d579f10cc53de3Andrew Lee Connection conferencedConnection = mGsmConference.getConnections().get(0); 1828a76b6b8715188f00fff4c0e52d579f10cc53de3Andrew Lee switch (conferencedConnection.getState()) { 1838a76b6b8715188f00fff4c0e52d579f10cc53de3Andrew Lee case Connection.STATE_ACTIVE: 1848a76b6b8715188f00fff4c0e52d579f10cc53de3Andrew Lee mGsmConference.setActive(); 1858a76b6b8715188f00fff4c0e52d579f10cc53de3Andrew Lee break; 1868a76b6b8715188f00fff4c0e52d579f10cc53de3Andrew Lee case Connection.STATE_HOLDING: 1878a76b6b8715188f00fff4c0e52d579f10cc53de3Andrew Lee mGsmConference.setOnHold(); 1888a76b6b8715188f00fff4c0e52d579f10cc53de3Andrew Lee break; 1898a76b6b8715188f00fff4c0e52d579f10cc53de3Andrew Lee } 19053b84fe2dc796ef172d7c0f4b9bdc177cdeb0c0fSantos Cordon } 191aa7340388473c1676495a60e30dc6a48d318a489Ihab Awad } 192aa7340388473c1676495a60e30dc6a48d318a489Ihab Awad} 193