• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2014 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.services.telephony;
18 
19 import android.telecom.Conference;
20 import android.telecom.Connection;
21 import android.telecom.PhoneAccountHandle;
22 
23 import com.android.internal.telephony.Call;
24 import com.android.internal.telephony.CallStateException;
25 import com.android.internal.telephony.Phone;
26 
27 import java.util.List;
28 
29 /**
30  * TelephonyConnection-based conference call for GSM conferences and IMS conferences (which may
31  * be either GSM-based or CDMA-based).
32  */
33 public class TelephonyConference extends Conference implements Holdable {
34 
35     private boolean mIsHoldable;
36 
TelephonyConference(PhoneAccountHandle phoneAccount)37     public TelephonyConference(PhoneAccountHandle phoneAccount) {
38         super(phoneAccount);
39         setConnectionCapabilities(
40                 Connection.CAPABILITY_SUPPORT_HOLD |
41                 Connection.CAPABILITY_HOLD |
42                 Connection.CAPABILITY_MUTE |
43                 Connection.CAPABILITY_MANAGE_CONFERENCE);
44         setActive();
45         mIsHoldable = true;
46     }
47 
48     /**
49      * Invoked when the Conference and all it's {@link Connection}s should be disconnected.
50      */
51     @Override
onDisconnect()52     public void onDisconnect() {
53         for (Connection connection : getConnections()) {
54             if (disconnectCall(connection)) {
55                 break;
56             }
57         }
58     }
59 
60     /**
61      * Disconnect the underlying Telephony Call for a connection.
62      *
63      * @param connection The connection.
64      * @return {@code True} if the call was disconnected.
65      */
disconnectCall(Connection connection)66     private boolean disconnectCall(Connection connection) {
67         Call call = getMultipartyCallForConnection(connection, "onDisconnect");
68         if (call != null) {
69             Log.d(this, "Found multiparty call to hangup for conference.");
70             try {
71                 call.hangup();
72                 return true;
73             } catch (CallStateException e) {
74                 Log.e(this, e, "Exception thrown trying to hangup conference");
75             }
76         }
77         return false;
78     }
79 
80     /**
81      * Invoked when the specified {@link Connection} should be separated from the conference call.
82      *
83      * @param connection The connection to separate.
84      */
85     @Override
onSeparate(Connection connection)86     public void onSeparate(Connection connection) {
87         com.android.internal.telephony.Connection radioConnection =
88                 getOriginalConnection(connection);
89         try {
90             radioConnection.separate();
91         } catch (CallStateException e) {
92             Log.e(this, e, "Exception thrown trying to separate a conference call");
93         }
94     }
95 
96     @Override
onMerge(Connection connection)97     public void onMerge(Connection connection) {
98         try {
99             Phone phone = ((TelephonyConnection) connection).getPhone();
100             if (phone != null) {
101                 phone.conference();
102             }
103         } catch (CallStateException e) {
104             Log.e(this, e, "Exception thrown trying to merge call into a conference");
105         }
106     }
107 
108     /**
109      * Invoked when the conference should be put on hold.
110      */
111     @Override
onHold()112     public void onHold() {
113         final TelephonyConnection connection = getFirstConnection();
114         if (connection != null) {
115             connection.performHold();
116         }
117     }
118 
119     /**
120      * Invoked when the conference should be moved from hold to active.
121      */
122     @Override
onUnhold()123     public void onUnhold() {
124         final TelephonyConnection connection = getFirstConnection();
125         if (connection != null) {
126             connection.performUnhold();
127         }
128     }
129 
130     @Override
onPlayDtmfTone(char c)131     public void onPlayDtmfTone(char c) {
132         final TelephonyConnection connection = getFirstConnection();
133         if (connection != null) {
134             connection.onPlayDtmfTone(c);
135         }
136     }
137 
138     @Override
onStopDtmfTone()139     public void onStopDtmfTone() {
140         final TelephonyConnection connection = getFirstConnection();
141         if (connection != null) {
142             connection.onStopDtmfTone();
143         }
144     }
145 
146     @Override
onConnectionAdded(Connection connection)147     public void onConnectionAdded(Connection connection) {
148         // If the conference was an IMS connection currently or before, disable MANAGE_CONFERENCE
149         // as the default behavior. If there is a conference event package, this may be overridden.
150         // If a conference event package was received, do not attempt to remove manage conference.
151         if (connection instanceof TelephonyConnection &&
152                 ((TelephonyConnection) connection).wasImsConnection()) {
153             removeCapability(Connection.CAPABILITY_MANAGE_CONFERENCE);
154         }
155     }
156 
157     @Override
getPrimaryConnection()158     public Connection getPrimaryConnection() {
159 
160         List<Connection> connections = getConnections();
161         if (connections == null || connections.isEmpty()) {
162             return null;
163         }
164 
165         // Default to the first connection.
166         Connection primaryConnection = connections.get(0);
167 
168         // Otherwise look for a connection where the radio connection states it is multiparty.
169         for (Connection connection : connections) {
170             com.android.internal.telephony.Connection radioConnection =
171                     getOriginalConnection(connection);
172 
173             if (radioConnection != null && radioConnection.isMultiparty()) {
174                 primaryConnection = connection;
175                 break;
176             }
177         }
178 
179         return primaryConnection;
180     }
181 
182     @Override
setHoldable(boolean isHoldable)183     public void setHoldable(boolean isHoldable) {
184         mIsHoldable = isHoldable;
185         if (!mIsHoldable) {
186             removeCapability(Connection.CAPABILITY_HOLD);
187         } else {
188             addCapability(Connection.CAPABILITY_HOLD);
189         }
190     }
191 
192     @Override
isChildHoldable()193     public boolean isChildHoldable() {
194         // The conference should not be a child of other conference.
195         return false;
196     }
197 
getMultipartyCallForConnection(Connection connection, String tag)198     private Call getMultipartyCallForConnection(Connection connection, String tag) {
199         com.android.internal.telephony.Connection radioConnection =
200                 getOriginalConnection(connection);
201         if (radioConnection != null) {
202             Call call = radioConnection.getCall();
203             if (call != null && call.isMultiparty()) {
204                 return call;
205             }
206         }
207         return null;
208     }
209 
getOriginalConnection( Connection connection)210     protected com.android.internal.telephony.Connection getOriginalConnection(
211             Connection connection) {
212 
213         if (connection instanceof TelephonyConnection) {
214             return ((TelephonyConnection) connection).getOriginalConnection();
215         } else {
216             return null;
217         }
218     }
219 
getFirstConnection()220     private TelephonyConnection getFirstConnection() {
221         final List<Connection> connections = getConnections();
222         if (connections.isEmpty()) {
223             return null;
224         }
225         return (TelephonyConnection) connections.get(0);
226     }
227 }
228