blob: d9605522b3b0023c430c621beb070f3fbfae722a [file] [log] [blame]
Santos Cordon823fd3c2014-08-07 18:35:18 -07001/*
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
Tyler Gunnef9f6f92014-09-12 22:16:17 -070017package android.telecom;
Santos Cordon823fd3c2014-08-07 18:35:18 -070018
Tyler Gunnc9503d62020-01-27 10:30:51 -080019import static android.Manifest.permission.MODIFY_PHONE_STATE;
20
21import android.annotation.ElapsedRealtimeLong;
22import android.annotation.IntRange;
Tyler Gunndee56a82016-03-23 16:06:34 -070023import android.annotation.NonNull;
Santos Cordon6b7f9552015-05-27 17:21:45 -070024import android.annotation.Nullable;
Tyler Gunnc9503d62020-01-27 10:30:51 -080025import android.annotation.RequiresPermission;
Santos Cordon5d2e4f22015-05-12 12:32:51 -070026import android.annotation.SystemApi;
Tyler Gunn6c14a6992019-02-04 15:12:06 -080027import android.annotation.TestApi;
Tyler Gunn68a73a42018-10-03 15:38:57 -070028import android.net.Uri;
Santos Cordon6b7f9552015-05-27 17:21:45 -070029import android.os.Bundle;
Tyler Gunn3fa819c2017-08-04 09:27:26 -070030import android.os.SystemClock;
Rekha Kumar07366812015-03-24 16:42:31 -070031import android.telecom.Connection.VideoProvider;
Tyler Gunndee56a82016-03-23 16:06:34 -070032import android.util.ArraySet;
Evan Charlton0e094d92014-11-08 15:49:16 -080033
Ihab Awad50e35062014-09-30 09:17:03 -070034import java.util.ArrayList;
Tyler Gunn071be6f2016-05-10 14:52:33 -070035import java.util.Arrays;
Santos Cordon823fd3c2014-08-07 18:35:18 -070036import java.util.Collections;
Santos Cordon823fd3c2014-08-07 18:35:18 -070037import java.util.List;
Rekha Kumar07366812015-03-24 16:42:31 -070038import java.util.Locale;
Santos Cordon823fd3c2014-08-07 18:35:18 -070039import java.util.Set;
40import java.util.concurrent.CopyOnWriteArrayList;
41import java.util.concurrent.CopyOnWriteArraySet;
42
43/**
44 * Represents a conference call which can contain any number of {@link Connection} objects.
45 */
Yorke Leeabfcfdc2015-05-13 18:55:18 -070046public abstract class Conference extends Conferenceable {
Santos Cordon823fd3c2014-08-07 18:35:18 -070047
Tyler Gunncd5d33c2015-01-12 09:02:01 -080048 /**
49 * Used to indicate that the conference connection time is not specified. If not specified,
50 * Telecom will set the connect time.
51 */
Jay Shrauner164a0ac2015-04-14 18:16:10 -070052 public static final long CONNECT_TIME_NOT_SPECIFIED = 0;
Tyler Gunncd5d33c2015-01-12 09:02:01 -080053
Santos Cordon823fd3c2014-08-07 18:35:18 -070054 /** @hide */
Tyler Gunn5567d742019-10-31 13:04:37 -070055 abstract static class Listener {
Santos Cordon823fd3c2014-08-07 18:35:18 -070056 public void onStateChanged(Conference conference, int oldState, int newState) {}
Andrew Lee7f3d41f2014-09-11 17:33:16 -070057 public void onDisconnected(Conference conference, DisconnectCause disconnectCause) {}
Santos Cordon823fd3c2014-08-07 18:35:18 -070058 public void onConnectionAdded(Conference conference, Connection connection) {}
59 public void onConnectionRemoved(Conference conference, Connection connection) {}
Ihab Awad50e35062014-09-30 09:17:03 -070060 public void onConferenceableConnectionsChanged(
61 Conference conference, List<Connection> conferenceableConnections) {}
Santos Cordon823fd3c2014-08-07 18:35:18 -070062 public void onDestroyed(Conference conference) {}
Ihab Awad5c9c86e2014-11-12 13:41:16 -080063 public void onConnectionCapabilitiesChanged(
64 Conference conference, int connectionCapabilities) {}
Tyler Gunn720c6642016-03-22 09:02:47 -070065 public void onConnectionPropertiesChanged(
66 Conference conference, int connectionProperties) {}
Rekha Kumar07366812015-03-24 16:42:31 -070067 public void onVideoStateChanged(Conference c, int videoState) { }
68 public void onVideoProviderChanged(Conference c, Connection.VideoProvider videoProvider) {}
Andrew Leeedc625f2015-04-14 13:38:12 -070069 public void onStatusHintsChanged(Conference conference, StatusHints statusHints) {}
Tyler Gunndee56a82016-03-23 16:06:34 -070070 public void onExtrasChanged(Conference c, Bundle extras) {}
71 public void onExtrasRemoved(Conference c, List<String> keys) {}
Tyler Gunn68a73a42018-10-03 15:38:57 -070072 public void onConferenceStateChanged(Conference c, boolean isConference) {}
73 public void onAddressChanged(Conference c, Uri newAddress, int presentation) {}
Hall Liuc9bc1c62019-04-16 14:00:55 -070074 public void onConnectionEvent(Conference c, String event, Bundle extras) {}
Tyler Gunn68a73a42018-10-03 15:38:57 -070075 public void onCallerDisplayNameChanged(
76 Conference c, String callerDisplayName, int presentation) {}
Brad Ebingere0c12f42020-04-08 16:25:12 -070077 public void onCallDirectionChanged(Conference c, int callDirection) {}
Ravi Paluri80aa2142019-12-02 11:57:37 +053078 public void onRingbackRequested(Conference c, boolean ringback) {}
Santos Cordon823fd3c2014-08-07 18:35:18 -070079 }
80
81 private final Set<Listener> mListeners = new CopyOnWriteArraySet<>();
82 private final List<Connection> mChildConnections = new CopyOnWriteArrayList<>();
Ihab Awadb8e85c72014-08-23 20:34:57 -070083 private final List<Connection> mUnmodifiableChildConnections =
Santos Cordon823fd3c2014-08-07 18:35:18 -070084 Collections.unmodifiableList(mChildConnections);
Ihab Awad50e35062014-09-30 09:17:03 -070085 private final List<Connection> mConferenceableConnections = new ArrayList<>();
86 private final List<Connection> mUnmodifiableConferenceableConnections =
87 Collections.unmodifiableList(mConferenceableConnections);
Santos Cordon823fd3c2014-08-07 18:35:18 -070088
Jack Yu67140302015-12-10 12:27:58 -080089 private String mTelecomCallId;
Jay Shrauner164a0ac2015-04-14 18:16:10 -070090 private PhoneAccountHandle mPhoneAccount;
Yorke Lee4af59352015-05-13 14:14:54 -070091 private CallAudioState mCallAudioState;
Santos Cordon823fd3c2014-08-07 18:35:18 -070092 private int mState = Connection.STATE_NEW;
Andrew Lee7f3d41f2014-09-11 17:33:16 -070093 private DisconnectCause mDisconnectCause;
Ihab Awad5c9c86e2014-11-12 13:41:16 -080094 private int mConnectionCapabilities;
Tyler Gunn720c6642016-03-22 09:02:47 -070095 private int mConnectionProperties;
Santos Cordon823fd3c2014-08-07 18:35:18 -070096 private String mDisconnectMessage;
Tyler Gunncd5d33c2015-01-12 09:02:01 -080097 private long mConnectTimeMillis = CONNECT_TIME_NOT_SPECIFIED;
Tyler Gunn17541392018-02-01 08:58:38 -080098 private long mConnectionStartElapsedRealTime = CONNECT_TIME_NOT_SPECIFIED;
Andrew Leeedc625f2015-04-14 13:38:12 -070099 private StatusHints mStatusHints;
Santos Cordon6b7f9552015-05-27 17:21:45 -0700100 private Bundle mExtras;
Tyler Gunndee56a82016-03-23 16:06:34 -0700101 private Set<String> mPreviousExtraKeys;
Brad Ebinger4fa6a012016-06-14 17:04:01 -0700102 private final Object mExtrasLock = new Object();
Tyler Gunnac60f952019-05-31 07:23:16 -0700103 private Uri mAddress;
104 private int mAddressPresentation;
105 private String mCallerDisplayName;
106 private int mCallerDisplayNamePresentation;
Brad Ebingere0c12f42020-04-08 16:25:12 -0700107 private int mCallDirection;
Ravi Paluri80aa2142019-12-02 11:57:37 +0530108 private boolean mRingbackRequested = false;
Tyler Gunn10362372020-04-08 13:12:30 -0700109 private boolean mIsMultiparty = true;
Santos Cordon823fd3c2014-08-07 18:35:18 -0700110
Ihab Awad50e35062014-09-30 09:17:03 -0700111 private final Connection.Listener mConnectionDeathListener = new Connection.Listener() {
112 @Override
113 public void onDestroyed(Connection c) {
114 if (mConferenceableConnections.remove(c)) {
115 fireOnConferenceableConnectionsChanged();
116 }
117 }
118 };
119
Nancy Chen56fc25d2014-09-09 12:24:51 -0700120 /**
121 * Constructs a new Conference with a mandatory {@link PhoneAccountHandle}
122 *
123 * @param phoneAccount The {@code PhoneAccountHandle} associated with the conference.
124 */
Santos Cordon823fd3c2014-08-07 18:35:18 -0700125 public Conference(PhoneAccountHandle phoneAccount) {
126 mPhoneAccount = phoneAccount;
127 }
128
Nancy Chen56fc25d2014-09-09 12:24:51 -0700129 /**
Jack Yu67140302015-12-10 12:27:58 -0800130 * Returns the telecom internal call ID associated with this conference.
Tyler Gunn5567d742019-10-31 13:04:37 -0700131 * <p>
132 * Note: This is ONLY used for debugging purposes so that the Telephony stack can better
133 * associate logs in Telephony with those in Telecom.
134 * The ID returned should not be used for any other purpose.
Jack Yu67140302015-12-10 12:27:58 -0800135 *
136 * @return The telecom call ID.
137 * @hide
138 */
Tyler Gunn5567d742019-10-31 13:04:37 -0700139 @SystemApi
140 @TestApi
141 public final @NonNull String getTelecomCallId() {
Jack Yu67140302015-12-10 12:27:58 -0800142 return mTelecomCallId;
143 }
144
145 /**
146 * Sets the telecom internal call ID associated with this conference.
147 *
148 * @param telecomCallId The telecom call ID.
149 * @hide
150 */
151 public final void setTelecomCallId(String telecomCallId) {
152 mTelecomCallId = telecomCallId;
153 }
154
155 /**
Nancy Chen56fc25d2014-09-09 12:24:51 -0700156 * Returns the {@link PhoneAccountHandle} the conference call is being placed through.
157 *
158 * @return A {@code PhoneAccountHandle} object representing the PhoneAccount of the conference.
159 */
Nancy Chenea38cca2014-09-05 16:38:49 -0700160 public final PhoneAccountHandle getPhoneAccountHandle() {
Santos Cordon823fd3c2014-08-07 18:35:18 -0700161 return mPhoneAccount;
162 }
163
Nancy Chen56fc25d2014-09-09 12:24:51 -0700164 /**
165 * Returns the list of connections currently associated with the conference call.
166 *
167 * @return A list of {@code Connection} objects which represent the children of the conference.
168 */
Santos Cordon823fd3c2014-08-07 18:35:18 -0700169 public final List<Connection> getConnections() {
Ihab Awadb8e85c72014-08-23 20:34:57 -0700170 return mUnmodifiableChildConnections;
Santos Cordon823fd3c2014-08-07 18:35:18 -0700171 }
172
Nancy Chen56fc25d2014-09-09 12:24:51 -0700173 /**
174 * Gets the state of the conference call. See {@link Connection} for valid values.
175 *
176 * @return A constant representing the state the conference call is currently in.
177 */
Santos Cordon823fd3c2014-08-07 18:35:18 -0700178 public final int getState() {
179 return mState;
180 }
181
Nancy Chen56fc25d2014-09-09 12:24:51 -0700182 /**
Ravi Paluri80aa2142019-12-02 11:57:37 +0530183 * Returns whether this conference is requesting that the system play a ringback tone
184 * on its behalf.
Tyler Gunna967af52020-02-10 15:19:07 -0800185 * @hide
Ravi Paluri80aa2142019-12-02 11:57:37 +0530186 */
187 public final boolean isRingbackRequested() {
188 return mRingbackRequested;
189 }
190
191 /**
Santos Cordon5d2e4f22015-05-12 12:32:51 -0700192 * Returns the capabilities of the conference. See {@code CAPABILITY_*} constants in class
Ihab Awad5c9c86e2014-11-12 13:41:16 -0800193 * {@link Connection} for valid values.
Nancy Chen56fc25d2014-09-09 12:24:51 -0700194 *
Ihab Awad5c9c86e2014-11-12 13:41:16 -0800195 * @return A bitmask of the capabilities of the conference call.
Nancy Chen56fc25d2014-09-09 12:24:51 -0700196 */
Ihab Awad5c9c86e2014-11-12 13:41:16 -0800197 public final int getConnectionCapabilities() {
198 return mConnectionCapabilities;
199 }
200
201 /**
Tyler Gunn720c6642016-03-22 09:02:47 -0700202 * Returns the properties of the conference. See {@code PROPERTY_*} constants in class
203 * {@link Connection} for valid values.
204 *
205 * @return A bitmask of the properties of the conference call.
206 */
207 public final int getConnectionProperties() {
208 return mConnectionProperties;
209 }
210
211 /**
Yorke Leea0d3ca92014-09-15 19:18:13 -0700212 * @return The audio state of the conference, describing how its audio is currently
213 * being routed by the system. This is {@code null} if this Conference
214 * does not directly know about its audio state.
Yorke Lee4af59352015-05-13 14:14:54 -0700215 * @deprecated Use {@link #getCallAudioState()} instead.
216 * @hide
Yorke Leea0d3ca92014-09-15 19:18:13 -0700217 */
Yorke Lee4af59352015-05-13 14:14:54 -0700218 @Deprecated
219 @SystemApi
Yorke Leea0d3ca92014-09-15 19:18:13 -0700220 public final AudioState getAudioState() {
Yorke Lee4af59352015-05-13 14:14:54 -0700221 return new AudioState(mCallAudioState);
222 }
223
224 /**
225 * @return The audio state of the conference, describing how its audio is currently
226 * being routed by the system. This is {@code null} if this Conference
227 * does not directly know about its audio state.
228 */
229 public final CallAudioState getCallAudioState() {
230 return mCallAudioState;
Yorke Leea0d3ca92014-09-15 19:18:13 -0700231 }
232
233 /**
Rekha Kumar07366812015-03-24 16:42:31 -0700234 * Returns VideoProvider of the primary call. This can be null.
Rekha Kumar07366812015-03-24 16:42:31 -0700235 */
236 public VideoProvider getVideoProvider() {
237 return null;
238 }
239
240 /**
241 * Returns video state of the primary call.
Rekha Kumar07366812015-03-24 16:42:31 -0700242 */
243 public int getVideoState() {
Tyler Gunn87b73f32015-06-03 10:09:59 -0700244 return VideoProfile.STATE_AUDIO_ONLY;
Rekha Kumar07366812015-03-24 16:42:31 -0700245 }
246
247 /**
Tyler Gunn9c0eb0b2016-06-29 11:23:25 -0700248 * Notifies the {@link Conference} when the Conference and all it's {@link Connection}s should
249 * be disconnected.
Santos Cordon823fd3c2014-08-07 18:35:18 -0700250 */
251 public void onDisconnect() {}
252
253 /**
Tyler Gunn9c0eb0b2016-06-29 11:23:25 -0700254 * Notifies the {@link Conference} when the specified {@link Connection} should be separated
255 * from the conference call.
Santos Cordon823fd3c2014-08-07 18:35:18 -0700256 *
257 * @param connection The connection to separate.
258 */
259 public void onSeparate(Connection connection) {}
260
261 /**
Tyler Gunn9c0eb0b2016-06-29 11:23:25 -0700262 * Notifies the {@link Conference} when the specified {@link Connection} should merged with the
263 * conference call.
Ihab Awad50e35062014-09-30 09:17:03 -0700264 *
265 * @param connection The {@code Connection} to merge.
266 */
267 public void onMerge(Connection connection) {}
268
269 /**
Tyler Gunn9c0eb0b2016-06-29 11:23:25 -0700270 * Notifies the {@link Conference} when it should be put on hold.
Santos Cordon823fd3c2014-08-07 18:35:18 -0700271 */
272 public void onHold() {}
273
274 /**
Tyler Gunn9c0eb0b2016-06-29 11:23:25 -0700275 * Notifies the {@link Conference} when it should be moved from a held to active state.
Santos Cordon823fd3c2014-08-07 18:35:18 -0700276 */
277 public void onUnhold() {}
278
279 /**
Tyler Gunn9c0eb0b2016-06-29 11:23:25 -0700280 * Notifies the {@link Conference} when the child calls should be merged. Only invoked if the
281 * conference contains the capability {@link Connection#CAPABILITY_MERGE_CONFERENCE}.
Santos Cordona4868042014-09-04 17:39:22 -0700282 */
283 public void onMerge() {}
284
285 /**
Tyler Gunn9c0eb0b2016-06-29 11:23:25 -0700286 * Notifies the {@link Conference} when the child calls should be swapped. Only invoked if the
287 * conference contains the capability {@link Connection#CAPABILITY_SWAP_CONFERENCE}.
Santos Cordona4868042014-09-04 17:39:22 -0700288 */
289 public void onSwap() {}
290
291 /**
Tyler Gunn9c0eb0b2016-06-29 11:23:25 -0700292 * Notifies the {@link Conference} of a request to play a DTMF tone.
Yorke Leea0d3ca92014-09-15 19:18:13 -0700293 *
294 * @param c A DTMF character.
295 */
296 public void onPlayDtmfTone(char c) {}
297
298 /**
Tyler Gunn9c0eb0b2016-06-29 11:23:25 -0700299 * Notifies the {@link Conference} of a request to stop any currently playing DTMF tones.
Yorke Leea0d3ca92014-09-15 19:18:13 -0700300 */
301 public void onStopDtmfTone() {}
302
303 /**
Tyler Gunn9c0eb0b2016-06-29 11:23:25 -0700304 * Notifies the {@link Conference} that the {@link #getAudioState()} property has a new value.
Yorke Leea0d3ca92014-09-15 19:18:13 -0700305 *
306 * @param state The new call audio state.
Yorke Lee4af59352015-05-13 14:14:54 -0700307 * @deprecated Use {@link #onCallAudioStateChanged(CallAudioState)} instead.
308 * @hide
Yorke Leea0d3ca92014-09-15 19:18:13 -0700309 */
Yorke Lee4af59352015-05-13 14:14:54 -0700310 @SystemApi
311 @Deprecated
Yorke Leea0d3ca92014-09-15 19:18:13 -0700312 public void onAudioStateChanged(AudioState state) {}
313
314 /**
Tyler Gunn9c0eb0b2016-06-29 11:23:25 -0700315 * Notifies the {@link Conference} that the {@link #getCallAudioState()} property has a new
316 * value.
Yorke Lee4af59352015-05-13 14:14:54 -0700317 *
318 * @param state The new call audio state.
319 */
320 public void onCallAudioStateChanged(CallAudioState state) {}
321
322 /**
Tyler Gunn9c0eb0b2016-06-29 11:23:25 -0700323 * Notifies the {@link Conference} that a {@link Connection} has been added to it.
Andrew Lee46f7f5d2014-11-06 17:00:25 -0800324 *
325 * @param connection The newly added connection.
326 */
327 public void onConnectionAdded(Connection connection) {}
328
329 /**
Tyler Gunn0c62ef02020-02-11 14:39:43 -0800330 * Notifies the {@link Conference} of a request to add a new participants to the conference call
331 * @param participants that will be added to this conference call
332 * @hide
Ravi Paluri404babb2020-01-23 19:02:44 +0530333 */
334 public void onAddConferenceParticipants(@NonNull List<Uri> participants) {}
335
336 /**
Ravi Paluri80aa2142019-12-02 11:57:37 +0530337 * Notifies this Conference, which is in {@code STATE_RINGING}, of
338 * a request to accept.
339 * For managed {@link ConnectionService}s, this will be called when the user answers a call via
340 * the default dialer's {@link InCallService}.
341 *
342 * @param videoState The video state in which to answer the connection.
Tyler Gunna967af52020-02-10 15:19:07 -0800343 * @hide
Ravi Paluri80aa2142019-12-02 11:57:37 +0530344 */
345 public void onAnswer(int videoState) {}
346
347 /**
348 * Notifies this Conference, which is in {@code STATE_RINGING}, of
349 * a request to accept.
350 * For managed {@link ConnectionService}s, this will be called when the user answers a call via
351 * the default dialer's {@link InCallService}.
352 * @hide
353 */
354 public final void onAnswer() {
355 onAnswer(VideoProfile.STATE_AUDIO_ONLY);
356 }
357
358 /**
359 * Notifies this Conference, which is in {@code STATE_RINGING}, of
360 * a request to reject.
361 * For managed {@link ConnectionService}s, this will be called when the user rejects a call via
362 * the default dialer's {@link InCallService}.
Tyler Gunna967af52020-02-10 15:19:07 -0800363 * @hide
Ravi Paluri80aa2142019-12-02 11:57:37 +0530364 */
365 public void onReject() {}
366
367 /**
Santos Cordon823fd3c2014-08-07 18:35:18 -0700368 * Sets state to be on hold.
369 */
370 public final void setOnHold() {
371 setState(Connection.STATE_HOLDING);
372 }
373
374 /**
Tyler Gunnd46595a2015-06-01 14:29:11 -0700375 * Sets state to be dialing.
376 */
377 public final void setDialing() {
378 setState(Connection.STATE_DIALING);
379 }
380
381 /**
Ravi Paluri80aa2142019-12-02 11:57:37 +0530382 * Sets state to be ringing.
Tyler Gunna967af52020-02-10 15:19:07 -0800383 * @hide
Ravi Paluri80aa2142019-12-02 11:57:37 +0530384 */
385 public final void setRinging() {
386 setState(Connection.STATE_RINGING);
387 }
388
389 /**
Santos Cordon823fd3c2014-08-07 18:35:18 -0700390 * Sets state to be active.
391 */
392 public final void setActive() {
Ravi Paluri80aa2142019-12-02 11:57:37 +0530393 setRingbackRequested(false);
Santos Cordon823fd3c2014-08-07 18:35:18 -0700394 setState(Connection.STATE_ACTIVE);
395 }
396
397 /**
398 * Sets state to disconnected.
399 *
Andrew Lee7f3d41f2014-09-11 17:33:16 -0700400 * @param disconnectCause The reason for the disconnection, as described by
401 * {@link android.telecom.DisconnectCause}.
Santos Cordon823fd3c2014-08-07 18:35:18 -0700402 */
Andrew Lee7f3d41f2014-09-11 17:33:16 -0700403 public final void setDisconnected(DisconnectCause disconnectCause) {
404 mDisconnectCause = disconnectCause;;
Santos Cordon823fd3c2014-08-07 18:35:18 -0700405 setState(Connection.STATE_DISCONNECTED);
406 for (Listener l : mListeners) {
Andrew Lee7f3d41f2014-09-11 17:33:16 -0700407 l.onDisconnected(this, mDisconnectCause);
Santos Cordon823fd3c2014-08-07 18:35:18 -0700408 }
409 }
410
411 /**
mike dooley1cf14ac2014-11-04 10:59:53 -0800412 * @return The {@link DisconnectCause} for this connection.
413 */
414 public final DisconnectCause getDisconnectCause() {
415 return mDisconnectCause;
416 }
417
418 /**
Ihab Awad5c9c86e2014-11-12 13:41:16 -0800419 * Sets the capabilities of a conference. See {@code CAPABILITY_*} constants of class
420 * {@link Connection} for valid values.
Nancy Chen56fc25d2014-09-09 12:24:51 -0700421 *
Tyler Gunn720c6642016-03-22 09:02:47 -0700422 * @param connectionCapabilities A bitmask of the {@code Capabilities} of the conference call.
Santos Cordon823fd3c2014-08-07 18:35:18 -0700423 */
Ihab Awad5c9c86e2014-11-12 13:41:16 -0800424 public final void setConnectionCapabilities(int connectionCapabilities) {
425 if (connectionCapabilities != mConnectionCapabilities) {
426 mConnectionCapabilities = connectionCapabilities;
Santos Cordon823fd3c2014-08-07 18:35:18 -0700427
428 for (Listener l : mListeners) {
Ihab Awad5c9c86e2014-11-12 13:41:16 -0800429 l.onConnectionCapabilitiesChanged(this, mConnectionCapabilities);
Santos Cordon823fd3c2014-08-07 18:35:18 -0700430 }
431 }
432 }
433
434 /**
Tyler Gunn720c6642016-03-22 09:02:47 -0700435 * Sets the properties of a conference. See {@code PROPERTY_*} constants of class
436 * {@link Connection} for valid values.
437 *
438 * @param connectionProperties A bitmask of the {@code Properties} of the conference call.
439 */
440 public final void setConnectionProperties(int connectionProperties) {
441 if (connectionProperties != mConnectionProperties) {
442 mConnectionProperties = connectionProperties;
443
444 for (Listener l : mListeners) {
445 l.onConnectionPropertiesChanged(this, mConnectionProperties);
446 }
447 }
448 }
449
450 /**
Santos Cordon823fd3c2014-08-07 18:35:18 -0700451 * Adds the specified connection as a child of this conference.
452 *
453 * @param connection The connection to add.
454 * @return True if the connection was successfully added.
455 */
Santos Cordona4868042014-09-04 17:39:22 -0700456 public final boolean addConnection(Connection connection) {
Rekha Kumar07366812015-03-24 16:42:31 -0700457 Log.d(this, "Connection=%s, connection=", connection);
Santos Cordon823fd3c2014-08-07 18:35:18 -0700458 if (connection != null && !mChildConnections.contains(connection)) {
459 if (connection.setConference(this)) {
460 mChildConnections.add(connection);
Andrew Lee46f7f5d2014-11-06 17:00:25 -0800461 onConnectionAdded(connection);
Santos Cordon823fd3c2014-08-07 18:35:18 -0700462 for (Listener l : mListeners) {
463 l.onConnectionAdded(this, connection);
464 }
465 return true;
466 }
467 }
468 return false;
469 }
470
471 /**
472 * Removes the specified connection as a child of this conference.
473 *
474 * @param connection The connection to remove.
Santos Cordon823fd3c2014-08-07 18:35:18 -0700475 */
Santos Cordona4868042014-09-04 17:39:22 -0700476 public final void removeConnection(Connection connection) {
Santos Cordon0159ac02014-08-21 14:28:11 -0700477 Log.d(this, "removing %s from %s", connection, mChildConnections);
Santos Cordon823fd3c2014-08-07 18:35:18 -0700478 if (connection != null && mChildConnections.remove(connection)) {
479 connection.resetConference();
480 for (Listener l : mListeners) {
481 l.onConnectionRemoved(this, connection);
482 }
483 }
484 }
485
486 /**
Ihab Awad50e35062014-09-30 09:17:03 -0700487 * Sets the connections with which this connection can be conferenced.
488 *
489 * @param conferenceableConnections The set of connections this connection can conference with.
490 */
491 public final void setConferenceableConnections(List<Connection> conferenceableConnections) {
492 clearConferenceableList();
493 for (Connection c : conferenceableConnections) {
494 // If statement checks for duplicates in input. It makes it N^2 but we're dealing with a
495 // small amount of items here.
496 if (!mConferenceableConnections.contains(c)) {
497 c.addConnectionListener(mConnectionDeathListener);
498 mConferenceableConnections.add(c);
499 }
500 }
501 fireOnConferenceableConnectionsChanged();
502 }
503
Rekha Kumar07366812015-03-24 16:42:31 -0700504 /**
Ravi Paluri80aa2142019-12-02 11:57:37 +0530505 * Requests that the framework play a ringback tone. This is to be invoked by implementations
506 * that do not play a ringback tone themselves in the conference's audio stream.
507 *
508 * @param ringback Whether the ringback tone is to be played.
Tyler Gunna967af52020-02-10 15:19:07 -0800509 * @hide
Ravi Paluri80aa2142019-12-02 11:57:37 +0530510 */
511 public final void setRingbackRequested(boolean ringback) {
512 if (mRingbackRequested != ringback) {
513 mRingbackRequested = ringback;
514 for (Listener l : mListeners) {
515 l.onRingbackRequested(this, ringback);
516 }
517 }
518 }
519
520 /**
Rekha Kumar07366812015-03-24 16:42:31 -0700521 * Set the video state for the conference.
Yorke Lee32f24732015-05-12 16:18:03 -0700522 * Valid values: {@link VideoProfile#STATE_AUDIO_ONLY},
523 * {@link VideoProfile#STATE_BIDIRECTIONAL},
524 * {@link VideoProfile#STATE_TX_ENABLED},
525 * {@link VideoProfile#STATE_RX_ENABLED}.
Rekha Kumar07366812015-03-24 16:42:31 -0700526 *
527 * @param videoState The new video state.
Rekha Kumar07366812015-03-24 16:42:31 -0700528 */
529 public final void setVideoState(Connection c, int videoState) {
530 Log.d(this, "setVideoState Conference: %s Connection: %s VideoState: %s",
531 this, c, videoState);
532 for (Listener l : mListeners) {
533 l.onVideoStateChanged(this, videoState);
534 }
535 }
536
537 /**
538 * Sets the video connection provider.
539 *
540 * @param videoProvider The video provider.
Rekha Kumar07366812015-03-24 16:42:31 -0700541 */
542 public final void setVideoProvider(Connection c, Connection.VideoProvider videoProvider) {
543 Log.d(this, "setVideoProvider Conference: %s Connection: %s VideoState: %s",
544 this, c, videoProvider);
545 for (Listener l : mListeners) {
546 l.onVideoProviderChanged(this, videoProvider);
547 }
548 }
549
Ihab Awad50e35062014-09-30 09:17:03 -0700550 private final void fireOnConferenceableConnectionsChanged() {
551 for (Listener l : mListeners) {
552 l.onConferenceableConnectionsChanged(this, getConferenceableConnections());
553 }
554 }
555
556 /**
557 * Returns the connections with which this connection can be conferenced.
558 */
559 public final List<Connection> getConferenceableConnections() {
560 return mUnmodifiableConferenceableConnections;
561 }
562
563 /**
Nancy Chenea38cca2014-09-05 16:38:49 -0700564 * Tears down the conference object and any of its current connections.
Santos Cordon823fd3c2014-08-07 18:35:18 -0700565 */
Santos Cordona4868042014-09-04 17:39:22 -0700566 public final void destroy() {
Santos Cordon823fd3c2014-08-07 18:35:18 -0700567 Log.d(this, "destroying conference : %s", this);
568 // Tear down the children.
Santos Cordon0159ac02014-08-21 14:28:11 -0700569 for (Connection connection : mChildConnections) {
Santos Cordon823fd3c2014-08-07 18:35:18 -0700570 Log.d(this, "removing connection %s", connection);
571 removeConnection(connection);
572 }
573
574 // If not yet disconnected, set the conference call as disconnected first.
575 if (mState != Connection.STATE_DISCONNECTED) {
576 Log.d(this, "setting to disconnected");
Andrew Lee7f3d41f2014-09-11 17:33:16 -0700577 setDisconnected(new DisconnectCause(DisconnectCause.LOCAL));
Santos Cordon823fd3c2014-08-07 18:35:18 -0700578 }
579
580 // ...and notify.
581 for (Listener l : mListeners) {
582 l.onDestroyed(this);
583 }
584 }
585
586 /**
587 * Add a listener to be notified of a state change.
588 *
589 * @param listener The new listener.
590 * @return This conference.
591 * @hide
592 */
Tyler Gunn5567d742019-10-31 13:04:37 -0700593 final Conference addListener(Listener listener) {
Santos Cordon823fd3c2014-08-07 18:35:18 -0700594 mListeners.add(listener);
595 return this;
596 }
597
598 /**
599 * Removes the specified listener.
600 *
601 * @param listener The listener to remove.
602 * @return This conference.
603 * @hide
604 */
Tyler Gunn5567d742019-10-31 13:04:37 -0700605 final Conference removeListener(Listener listener) {
Santos Cordon823fd3c2014-08-07 18:35:18 -0700606 mListeners.remove(listener);
607 return this;
608 }
609
Yorke Leea0d3ca92014-09-15 19:18:13 -0700610 /**
Tyler Gunn4a57b9b2014-10-30 14:27:48 -0700611 * Retrieves the primary connection associated with the conference. The primary connection is
612 * the connection from which the conference will retrieve its current state.
613 *
614 * @return The primary connection.
Santos Cordon5d2e4f22015-05-12 12:32:51 -0700615 * @hide
Tyler Gunn4a57b9b2014-10-30 14:27:48 -0700616 */
Tyler Gunn6c14a6992019-02-04 15:12:06 -0800617 @TestApi
Santos Cordon5d2e4f22015-05-12 12:32:51 -0700618 @SystemApi
Santos Cordon4055d642015-05-12 14:19:24 -0700619 public Connection getPrimaryConnection() {
Tyler Gunn4a57b9b2014-10-30 14:27:48 -0700620 if (mUnmodifiableChildConnections == null || mUnmodifiableChildConnections.isEmpty()) {
621 return null;
622 }
623 return mUnmodifiableChildConnections.get(0);
624 }
625
626 /**
Santos Cordon5d2e4f22015-05-12 12:32:51 -0700627 * @hide
628 * @deprecated Use {@link #setConnectionTime}.
Tyler Gunncd5d33c2015-01-12 09:02:01 -0800629 */
Santos Cordon5d2e4f22015-05-12 12:32:51 -0700630 @Deprecated
631 @SystemApi
632 public final void setConnectTimeMillis(long connectTimeMillis) {
633 setConnectionTime(connectTimeMillis);
Tyler Gunncd5d33c2015-01-12 09:02:01 -0800634 }
635
636 /**
Tyler Gunn17541392018-02-01 08:58:38 -0800637 * Sets the connection start time of the {@code Conference}. This is used in the call log to
638 * indicate the date and time when the conference took place.
639 * <p>
640 * Should be specified in wall-clock time returned by {@link System#currentTimeMillis()}.
Tyler Gunn3fa819c2017-08-04 09:27:26 -0700641 * <p>
642 * When setting the connection time, you should always set the connection elapsed time via
Tyler Gunnc9503d62020-01-27 10:30:51 -0800643 * {@link #setConnectionStartElapsedRealtimeMillis(long)} to ensure the duration is reflected.
Santos Cordon5d2e4f22015-05-12 12:32:51 -0700644 *
Tyler Gunn17541392018-02-01 08:58:38 -0800645 * @param connectionTimeMillis The connection time, in milliseconds, as returned by
646 * {@link System#currentTimeMillis()}.
Santos Cordon5d2e4f22015-05-12 12:32:51 -0700647 */
Tyler Gunnc9503d62020-01-27 10:30:51 -0800648 public final void setConnectionTime(@IntRange(from = 0) long connectionTimeMillis) {
Santos Cordon5d2e4f22015-05-12 12:32:51 -0700649 mConnectTimeMillis = connectionTimeMillis;
650 }
651
652 /**
Tyler Gunn17541392018-02-01 08:58:38 -0800653 * Sets the start time of the {@link Conference} which is the basis for the determining the
654 * duration of the {@link Conference}.
Tyler Gunn3fa819c2017-08-04 09:27:26 -0700655 * <p>
Tyler Gunn17541392018-02-01 08:58:38 -0800656 * You should use a value returned by {@link SystemClock#elapsedRealtime()} to ensure that time
657 * zone changes do not impact the conference duration.
658 * <p>
659 * When setting this, you should also set the connection time via
Tyler Gunn3fa819c2017-08-04 09:27:26 -0700660 * {@link #setConnectionTime(long)}.
661 *
Tyler Gunn17541392018-02-01 08:58:38 -0800662 * @param connectionStartElapsedRealTime The connection time, as measured by
Tyler Gunn3fa819c2017-08-04 09:27:26 -0700663 * {@link SystemClock#elapsedRealtime()}.
Tyler Gunnc9503d62020-01-27 10:30:51 -0800664 * @deprecated use {@link #setConnectionStartElapsedRealtimeMillis(long)} instead.
Tyler Gunn3fa819c2017-08-04 09:27:26 -0700665 */
Tyler Gunnc9503d62020-01-27 10:30:51 -0800666 @Deprecated
Tyler Gunn17541392018-02-01 08:58:38 -0800667 public final void setConnectionStartElapsedRealTime(long connectionStartElapsedRealTime) {
Tyler Gunnc9503d62020-01-27 10:30:51 -0800668 setConnectionStartElapsedRealtimeMillis(connectionStartElapsedRealTime);
669 }
670
671 /**
672 * Sets the start time of the {@link Conference} which is the basis for the determining the
673 * duration of the {@link Conference}.
674 * <p>
675 * You should use a value returned by {@link SystemClock#elapsedRealtime()} to ensure that time
676 * zone changes do not impact the conference duration.
677 * <p>
678 * When setting this, you should also set the connection time via
679 * {@link #setConnectionTime(long)}.
680 *
681 * @param connectionStartElapsedRealTime The connection time, as measured by
682 * {@link SystemClock#elapsedRealtime()}.
683 */
684 public final void setConnectionStartElapsedRealtimeMillis(
685 @ElapsedRealtimeLong long connectionStartElapsedRealTime) {
Tyler Gunn17541392018-02-01 08:58:38 -0800686 mConnectionStartElapsedRealTime = connectionStartElapsedRealTime;
Tyler Gunn3fa819c2017-08-04 09:27:26 -0700687 }
688
689 /**
Santos Cordon5d2e4f22015-05-12 12:32:51 -0700690 * @hide
691 * @deprecated Use {@link #getConnectionTime}.
692 */
693 @Deprecated
694 @SystemApi
695 public final long getConnectTimeMillis() {
696 return getConnectionTime();
697 }
698
699 /**
700 * Retrieves the connection start time of the {@code Conference}, if specified. A value of
Tyler Gunncd5d33c2015-01-12 09:02:01 -0800701 * {@link #CONNECT_TIME_NOT_SPECIFIED} indicates that Telecom should determine the start time
702 * of the conference.
703 *
Santos Cordon5d2e4f22015-05-12 12:32:51 -0700704 * @return The time at which the {@code Conference} was connected.
Tyler Gunncd5d33c2015-01-12 09:02:01 -0800705 */
Tyler Gunnc9503d62020-01-27 10:30:51 -0800706 public final @IntRange(from = 0) long getConnectionTime() {
Tyler Gunncd5d33c2015-01-12 09:02:01 -0800707 return mConnectTimeMillis;
708 }
709
710 /**
Tyler Gunn3fa819c2017-08-04 09:27:26 -0700711 * Retrieves the connection start time of the {@link Conference}, if specified. A value of
712 * {@link #CONNECT_TIME_NOT_SPECIFIED} indicates that Telecom should determine the start time
713 * of the conference.
Tyler Gunn5567d742019-10-31 13:04:37 -0700714 * <p>
Tyler Gunn3fa819c2017-08-04 09:27:26 -0700715 * This is based on the value of {@link SystemClock#elapsedRealtime()} to ensure that it is not
716 * impacted by wall clock changes (user initiated, network initiated, time zone change, etc).
Tyler Gunn5567d742019-10-31 13:04:37 -0700717 * <p>
718 * Note: This is only exposed for use by the Telephony framework which needs it to copy
719 * conference start times among conference participants. It is exposed as a system API since it
720 * has no general use other than to the Telephony framework.
Tyler Gunn3fa819c2017-08-04 09:27:26 -0700721 *
722 * @return The elapsed time at which the {@link Conference} was connected.
Tyler Gunn3fa819c2017-08-04 09:27:26 -0700723 */
Tyler Gunnc9503d62020-01-27 10:30:51 -0800724 public final @ElapsedRealtimeLong long getConnectionStartElapsedRealtimeMillis() {
Tyler Gunn17541392018-02-01 08:58:38 -0800725 return mConnectionStartElapsedRealTime;
Tyler Gunn3fa819c2017-08-04 09:27:26 -0700726 }
727
728 /**
Yorke Leea0d3ca92014-09-15 19:18:13 -0700729 * Inform this Conference that the state of its audio output has been changed externally.
730 *
731 * @param state The new audio state.
732 * @hide
733 */
Yorke Lee4af59352015-05-13 14:14:54 -0700734 final void setCallAudioState(CallAudioState state) {
735 Log.d(this, "setCallAudioState %s", state);
736 mCallAudioState = state;
737 onAudioStateChanged(getAudioState());
738 onCallAudioStateChanged(state);
Yorke Leea0d3ca92014-09-15 19:18:13 -0700739 }
740
Santos Cordon823fd3c2014-08-07 18:35:18 -0700741 private void setState(int newState) {
Santos Cordon823fd3c2014-08-07 18:35:18 -0700742 if (mState != newState) {
743 int oldState = mState;
744 mState = newState;
745 for (Listener l : mListeners) {
746 l.onStateChanged(this, oldState, newState);
747 }
748 }
749 }
Ihab Awad50e35062014-09-30 09:17:03 -0700750
Ravi Paluri80aa2142019-12-02 11:57:37 +0530751 private static class FailureSignalingConference extends Conference {
752 private boolean mImmutable = false;
753 public FailureSignalingConference(DisconnectCause disconnectCause,
754 PhoneAccountHandle phoneAccount) {
755 super(phoneAccount);
756 setDisconnected(disconnectCause);
757 mImmutable = true;
758 }
759 public void checkImmutable() {
760 if (mImmutable) {
761 throw new UnsupportedOperationException("Conference is immutable");
762 }
763 }
764 }
765
766 /**
767 * Return a {@code Conference} which represents a failed conference attempt. The returned
768 * {@code Conference} will have a {@link android.telecom.DisconnectCause} and as specified,
769 * and a {@link #getState()} of {@code STATE_DISCONNECTED}.
770 * <p>
771 * The returned {@code Conference} can be assumed to {@link #destroy()} itself when appropriate,
772 * so users of this method need not maintain a reference to its return value to destroy it.
773 *
774 * @param disconnectCause The disconnect cause, ({@see android.telecomm.DisconnectCause}).
775 * @return A {@code Conference} which indicates failure.
Tyler Gunna967af52020-02-10 15:19:07 -0800776 * @hide
Ravi Paluri80aa2142019-12-02 11:57:37 +0530777 */
778 public @NonNull static Conference createFailedConference(
779 @NonNull DisconnectCause disconnectCause, @NonNull PhoneAccountHandle phoneAccount) {
780 return new FailureSignalingConference(disconnectCause, phoneAccount);
781 }
782
Ihab Awad50e35062014-09-30 09:17:03 -0700783 private final void clearConferenceableList() {
784 for (Connection c : mConferenceableConnections) {
785 c.removeConnectionListener(mConnectionDeathListener);
786 }
787 mConferenceableConnections.clear();
788 }
Rekha Kumar07366812015-03-24 16:42:31 -0700789
790 @Override
791 public String toString() {
792 return String.format(Locale.US,
Ravi Paluri80aa2142019-12-02 11:57:37 +0530793 "[State: %s,Capabilites: %s, VideoState: %s, VideoProvider: %s,"
794 + "isRingbackRequested: %s, ThisObject %s]",
Rekha Kumar07366812015-03-24 16:42:31 -0700795 Connection.stateToString(mState),
796 Call.Details.capabilitiesToString(mConnectionCapabilities),
797 getVideoState(),
798 getVideoProvider(),
Ravi Paluri80aa2142019-12-02 11:57:37 +0530799 isRingbackRequested() ? "Y" : "N",
Rekha Kumar07366812015-03-24 16:42:31 -0700800 super.toString());
801 }
Andrew Lee0f51da32015-04-16 13:11:55 -0700802
Andrew Leeedc625f2015-04-14 13:38:12 -0700803 /**
804 * Sets the label and icon status to display in the InCall UI.
805 *
806 * @param statusHints The status label and icon to set.
807 */
808 public final void setStatusHints(StatusHints statusHints) {
809 mStatusHints = statusHints;
810 for (Listener l : mListeners) {
811 l.onStatusHintsChanged(this, statusHints);
812 }
813 }
814
815 /**
816 * @return The status hints for this conference.
817 */
818 public final StatusHints getStatusHints() {
819 return mStatusHints;
820 }
Santos Cordon6b7f9552015-05-27 17:21:45 -0700821
822 /**
Tyler Gunndee56a82016-03-23 16:06:34 -0700823 * Replaces all the extras associated with this {@code Conference}.
824 * <p>
825 * New or existing keys are replaced in the {@code Conference} extras. Keys which are no longer
826 * in the new extras, but were present the last time {@code setExtras} was called are removed.
827 * <p>
Tyler Gunn9c0eb0b2016-06-29 11:23:25 -0700828 * Alternatively you may use the {@link #putExtras(Bundle)}, and
829 * {@link #removeExtras(String...)} methods to modify the extras.
830 * <p>
Tyler Gunndee56a82016-03-23 16:06:34 -0700831 * No assumptions should be made as to how an In-Call UI or service will handle these extras.
Tyler Gunn9c0eb0b2016-06-29 11:23:25 -0700832 * Keys should be fully qualified (e.g., com.example.extras.MY_EXTRA) to avoid conflicts.
Santos Cordon6b7f9552015-05-27 17:21:45 -0700833 *
Tyler Gunndee56a82016-03-23 16:06:34 -0700834 * @param extras The extras associated with this {@code Conference}.
Santos Cordon6b7f9552015-05-27 17:21:45 -0700835 */
836 public final void setExtras(@Nullable Bundle extras) {
Brad Ebinger4fa6a012016-06-14 17:04:01 -0700837 // Keeping putExtras and removeExtras in the same lock so that this operation happens as a
838 // block instead of letting other threads put/remove while this method is running.
839 synchronized (mExtrasLock) {
840 // Add/replace any new or changed extras values.
841 putExtras(extras);
842 // If we have used "setExtras" in the past, compare the key set from the last invocation
843 // to the current one and remove any keys that went away.
844 if (mPreviousExtraKeys != null) {
845 List<String> toRemove = new ArrayList<String>();
846 for (String oldKey : mPreviousExtraKeys) {
847 if (extras == null || !extras.containsKey(oldKey)) {
848 toRemove.add(oldKey);
849 }
850 }
Tyler Gunndee56a82016-03-23 16:06:34 -0700851
Brad Ebinger4fa6a012016-06-14 17:04:01 -0700852 if (!toRemove.isEmpty()) {
853 removeExtras(toRemove);
Tyler Gunndee56a82016-03-23 16:06:34 -0700854 }
855 }
856
Brad Ebinger4fa6a012016-06-14 17:04:01 -0700857 // Track the keys the last time set called setExtras. This way, the next time setExtras
858 // is called we can see if the caller has removed any extras values.
859 if (mPreviousExtraKeys == null) {
860 mPreviousExtraKeys = new ArraySet<String>();
Tyler Gunndee56a82016-03-23 16:06:34 -0700861 }
Brad Ebinger4fa6a012016-06-14 17:04:01 -0700862 mPreviousExtraKeys.clear();
863 if (extras != null) {
864 mPreviousExtraKeys.addAll(extras.keySet());
865 }
Tyler Gunna8fb8ab2016-03-29 10:24:22 -0700866 }
Tyler Gunndee56a82016-03-23 16:06:34 -0700867 }
868
869 /**
870 * Adds some extras to this {@link Conference}. Existing keys are replaced and new ones are
871 * added.
872 * <p>
873 * No assumptions should be made as to how an In-Call UI or service will handle these extras.
874 * Keys should be fully qualified (e.g., com.example.MY_EXTRA) to avoid conflicts.
875 *
876 * @param extras The extras to add.
877 */
878 public final void putExtras(@NonNull Bundle extras) {
879 if (extras == null) {
880 return;
881 }
882
Brad Ebinger4fa6a012016-06-14 17:04:01 -0700883 // Creating a Bundle clone so we don't have to synchronize on mExtrasLock while calling
884 // onExtrasChanged.
885 Bundle listenersBundle;
886 synchronized (mExtrasLock) {
887 if (mExtras == null) {
888 mExtras = new Bundle();
889 }
890 mExtras.putAll(extras);
891 listenersBundle = new Bundle(mExtras);
Tyler Gunndee56a82016-03-23 16:06:34 -0700892 }
Tyler Gunndee56a82016-03-23 16:06:34 -0700893
Santos Cordon6b7f9552015-05-27 17:21:45 -0700894 for (Listener l : mListeners) {
Brad Ebinger4fa6a012016-06-14 17:04:01 -0700895 l.onExtrasChanged(this, new Bundle(listenersBundle));
Santos Cordon6b7f9552015-05-27 17:21:45 -0700896 }
897 }
898
899 /**
Tyler Gunndee56a82016-03-23 16:06:34 -0700900 * Adds a boolean extra to this {@link Conference}.
901 *
902 * @param key The extra key.
903 * @param value The value.
904 * @hide
905 */
906 public final void putExtra(String key, boolean value) {
907 Bundle newExtras = new Bundle();
908 newExtras.putBoolean(key, value);
909 putExtras(newExtras);
910 }
911
912 /**
913 * Adds an integer extra to this {@link Conference}.
914 *
915 * @param key The extra key.
916 * @param value The value.
917 * @hide
918 */
919 public final void putExtra(String key, int value) {
920 Bundle newExtras = new Bundle();
921 newExtras.putInt(key, value);
922 putExtras(newExtras);
923 }
924
925 /**
926 * Adds a string extra to this {@link Conference}.
927 *
928 * @param key The extra key.
929 * @param value The value.
930 * @hide
931 */
932 public final void putExtra(String key, String value) {
933 Bundle newExtras = new Bundle();
934 newExtras.putString(key, value);
935 putExtras(newExtras);
936 }
937
938 /**
Tyler Gunn071be6f2016-05-10 14:52:33 -0700939 * Removes extras from this {@link Conference}.
Tyler Gunndee56a82016-03-23 16:06:34 -0700940 *
Tyler Gunn071be6f2016-05-10 14:52:33 -0700941 * @param keys The keys of the extras to remove.
Tyler Gunndee56a82016-03-23 16:06:34 -0700942 */
943 public final void removeExtras(List<String> keys) {
944 if (keys == null || keys.isEmpty()) {
945 return;
946 }
947
Brad Ebinger4fa6a012016-06-14 17:04:01 -0700948 synchronized (mExtrasLock) {
949 if (mExtras != null) {
950 for (String key : keys) {
951 mExtras.remove(key);
952 }
Tyler Gunndee56a82016-03-23 16:06:34 -0700953 }
954 }
955
Brad Ebinger4fa6a012016-06-14 17:04:01 -0700956 List<String> unmodifiableKeys = Collections.unmodifiableList(keys);
Tyler Gunndee56a82016-03-23 16:06:34 -0700957 for (Listener l : mListeners) {
Brad Ebinger4fa6a012016-06-14 17:04:01 -0700958 l.onExtrasRemoved(this, unmodifiableKeys);
Tyler Gunndee56a82016-03-23 16:06:34 -0700959 }
960 }
961
962 /**
Tyler Gunn071be6f2016-05-10 14:52:33 -0700963 * Removes extras from this {@link Conference}.
964 *
965 * @param keys The keys of the extras to remove.
966 */
967 public final void removeExtras(String ... keys) {
968 removeExtras(Arrays.asList(keys));
969 }
970
971 /**
Tyler Gunndee56a82016-03-23 16:06:34 -0700972 * Returns the extras associated with this conference.
Tyler Gunn2cbe2b52016-05-04 15:48:10 +0000973 * <p>
974 * Extras should be updated using {@link #putExtras(Bundle)} and {@link #removeExtras(List)}.
975 * <p>
976 * Telecom or an {@link InCallService} can also update the extras via
977 * {@link android.telecom.Call#putExtras(Bundle)}, and
978 * {@link Call#removeExtras(List)}.
979 * <p>
980 * The conference is notified of changes to the extras made by Telecom or an
981 * {@link InCallService} by {@link #onExtrasChanged(Bundle)}.
Tyler Gunndee56a82016-03-23 16:06:34 -0700982 *
983 * @return The extras associated with this connection.
Santos Cordon6b7f9552015-05-27 17:21:45 -0700984 */
985 public final Bundle getExtras() {
986 return mExtras;
987 }
Tyler Gunndee56a82016-03-23 16:06:34 -0700988
989 /**
990 * Notifies this {@link Conference} of a change to the extras made outside the
991 * {@link ConnectionService}.
992 * <p>
993 * These extras changes can originate from Telecom itself, or from an {@link InCallService} via
994 * {@link android.telecom.Call#putExtras(Bundle)}, and
995 * {@link Call#removeExtras(List)}.
996 *
997 * @param extras The new extras bundle.
998 */
999 public void onExtrasChanged(Bundle extras) {}
1000
1001 /**
Tyler Gunn10362372020-04-08 13:12:30 -07001002 * Set whether Telecom should treat this {@link Conference} as a multiparty conference call or
1003 * if it should treat it as a single-party call.
Tyler Gunn68a73a42018-10-03 15:38:57 -07001004 * This method is used as part of a workaround regarding IMS conference calls and user
1005 * expectation. In IMS, once a conference is formed, the UE is connected to an IMS conference
1006 * server. If all participants of the conference drop out of the conference except for one, the
1007 * UE is still connected to the IMS conference server. At this point, the user logically
1008 * assumes they're no longer in a conference, yet the underlying network actually is.
1009 * To help provide a better user experiece, IMS conference calls can pretend to actually be a
1010 * single-party call when the participant count drops to 1. Although the dialer/phone app
1011 * could perform this trickery, it makes sense to do this in Telephony since a fix there will
1012 * ensure that bluetooth head units, auto and wearable apps all behave consistently.
Tyler Gunn5567d742019-10-31 13:04:37 -07001013 * <p>
1014 * This API is intended for use by the platform Telephony stack only.
Tyler Gunn68a73a42018-10-03 15:38:57 -07001015 *
1016 * @param isConference {@code true} if this {@link Conference} should be treated like a
1017 * conference call, {@code false} if it should be treated like a single-party call.
1018 * @hide
1019 */
Tyler Gunn5567d742019-10-31 13:04:37 -07001020 @SystemApi
1021 @TestApi
Tyler Gunnc9503d62020-01-27 10:30:51 -08001022 @RequiresPermission(MODIFY_PHONE_STATE)
Tyler Gunn68a73a42018-10-03 15:38:57 -07001023 public void setConferenceState(boolean isConference) {
Tyler Gunn10362372020-04-08 13:12:30 -07001024 mIsMultiparty = isConference;
Tyler Gunn68a73a42018-10-03 15:38:57 -07001025 for (Listener l : mListeners) {
1026 l.onConferenceStateChanged(this, isConference);
1027 }
1028 }
1029
1030 /**
Brad Ebingere0c12f42020-04-08 16:25:12 -07001031 * Sets the call direction of this {@link Conference}. By default, all {@link Conference}s have
1032 * a direction of {@link android.telecom.Call.Details.CallDirection#DIRECTION_UNKNOWN}. The
1033 * direction of a {@link Conference} is only applicable to the case where
1034 * {@link #setConferenceState(boolean)} has been set to {@code false}, otherwise the direction
1035 * will be ignored.
1036 * @param callDirection The direction of the conference.
1037 * @hide
1038 */
1039 @RequiresPermission(MODIFY_PHONE_STATE)
1040 public final void setCallDirection(@Call.Details.CallDirection int callDirection) {
1041 Log.d(this, "setDirection %d", callDirection);
1042 mCallDirection = callDirection;
1043 for (Listener l : mListeners) {
1044 l.onCallDirectionChanged(this, callDirection);
1045 }
1046 }
1047
Tyler Gunn10362372020-04-08 13:12:30 -07001048 /**
1049 * Determines if the {@link Conference} is considered "multiparty" or not. By default all
1050 * conferences are considered multiparty. A multiparty conference is one where there are
1051 * multiple conference participants (other than the host) in the conference.
1052 * This is tied to {@link #setConferenceState(boolean)}, which is used for some use cases to
1053 * have a conference appear as if it is a standalone call, in which case the conference will
1054 * no longer be multiparty.
1055 * @return {@code true} if conference is treated as a conference (i.e. it is multiparty),
1056 * {@code false} if it should emulate a standalone call (i.e. not multiparty).
1057 * @hide
1058 */
1059 public boolean isMultiparty() {
1060 return mIsMultiparty;
1061 }
Brad Ebingere0c12f42020-04-08 16:25:12 -07001062
1063 /**
Tyler Gunn68a73a42018-10-03 15:38:57 -07001064 * Sets the address of this {@link Conference}. Used when {@link #setConferenceState(boolean)}
1065 * is called to mark a conference temporarily as NOT a conference.
Tyler Gunn5567d742019-10-31 13:04:37 -07001066 * <p>
1067 * Note: This is a Telephony-specific implementation detail related to IMS conferences. It is
1068 * not intended for use outside of the Telephony stack.
Tyler Gunn68a73a42018-10-03 15:38:57 -07001069 *
1070 * @param address The new address.
1071 * @param presentation The presentation requirements for the address.
1072 * See {@link TelecomManager} for valid values.
1073 * @hide
1074 */
Tyler Gunn5567d742019-10-31 13:04:37 -07001075 @SystemApi
1076 @TestApi
Tyler Gunnc9503d62020-01-27 10:30:51 -08001077 @RequiresPermission(MODIFY_PHONE_STATE)
Tyler Gunn5567d742019-10-31 13:04:37 -07001078 public final void setAddress(@NonNull Uri address,
1079 @TelecomManager.Presentation int presentation) {
Tyler Gunn68a73a42018-10-03 15:38:57 -07001080 Log.d(this, "setAddress %s", address);
Tyler Gunnac60f952019-05-31 07:23:16 -07001081 mAddress = address;
1082 mAddressPresentation = presentation;
Tyler Gunn68a73a42018-10-03 15:38:57 -07001083 for (Listener l : mListeners) {
1084 l.onAddressChanged(this, address, presentation);
1085 }
1086 }
1087
1088 /**
Tyler Gunnac60f952019-05-31 07:23:16 -07001089 * Returns the "address" associated with the conference. This is applicable in two cases:
1090 * <ol>
1091 * <li>When {@link #setConferenceState(boolean)} is used to mark a conference as
1092 * temporarily "not a conference"; we need to present the correct address in the in-call
1093 * UI.</li>
1094 * <li>When the conference is not hosted on the current device, we need to know the address
1095 * information for the purpose of showing the original address to the user, as well as for
1096 * logging to the call log.</li>
1097 * </ol>
1098 * @return The address of the conference, or {@code null} if not applicable.
1099 * @hide
1100 */
1101 public final Uri getAddress() {
1102 return mAddress;
1103 }
1104
1105 /**
1106 * Returns the address presentation associated with the conference.
1107 * <p>
1108 * This is applicable in two cases:
1109 * <ol>
1110 * <li>When {@link #setConferenceState(boolean)} is used to mark a conference as
Brad Ebinger0ae44ed2020-04-09 15:30:57 -07001111 * temporarily "not a conference"; we need to present the correct address presentation in
1112 * the in-call UI.</li>
Tyler Gunnac60f952019-05-31 07:23:16 -07001113 * <li>When the conference is not hosted on the current device, we need to know the address
Brad Ebinger0ae44ed2020-04-09 15:30:57 -07001114 * presentation information for the purpose of showing the original address to the user, as
1115 * well as for logging to the call log.</li>
Tyler Gunnac60f952019-05-31 07:23:16 -07001116 * </ol>
Brad Ebinger0ae44ed2020-04-09 15:30:57 -07001117 * @return The address presentation of the conference.
Tyler Gunnac60f952019-05-31 07:23:16 -07001118 * @hide
1119 */
Brad Ebinger0ae44ed2020-04-09 15:30:57 -07001120 public final @TelecomManager.Presentation int getAddressPresentation() {
Tyler Gunnac60f952019-05-31 07:23:16 -07001121 return mAddressPresentation;
1122 }
1123
1124 /**
1125 * @return The caller display name (CNAP).
1126 * @hide
1127 */
1128 public final String getCallerDisplayName() {
1129 return mCallerDisplayName;
1130 }
1131
1132 /**
1133 * @return The presentation requirements for the handle.
1134 * See {@link TelecomManager} for valid values.
1135 * @hide
1136 */
1137 public final int getCallerDisplayNamePresentation() {
1138 return mCallerDisplayNamePresentation;
1139 }
1140
1141 /**
Brad Ebingere0c12f42020-04-08 16:25:12 -07001142 * @return The call direction of this conference. Only applicable when
1143 * {@link #setConferenceState(boolean)} is set to false.
1144 * @hide
1145 */
1146 public final @Call.Details.CallDirection int getCallDirection() {
1147 return mCallDirection;
1148 }
1149
1150 /**
Tyler Gunn68a73a42018-10-03 15:38:57 -07001151 * Sets the caller display name (CNAP) of this {@link Conference}. Used when
1152 * {@link #setConferenceState(boolean)} is called to mark a conference temporarily as NOT a
1153 * conference.
Tyler Gunn5567d742019-10-31 13:04:37 -07001154 * <p>
1155 * Note: This is a Telephony-specific implementation detail related to IMS conferences. It is
1156 * not intended for use outside of the Telephony stack.
Tyler Gunn68a73a42018-10-03 15:38:57 -07001157 *
1158 * @param callerDisplayName The new display name.
1159 * @param presentation The presentation requirements for the handle.
1160 * See {@link TelecomManager} for valid values.
1161 * @hide
1162 */
Tyler Gunn5567d742019-10-31 13:04:37 -07001163 @SystemApi
1164 @TestApi
1165 public final void setCallerDisplayName(@NonNull String callerDisplayName,
1166 @TelecomManager.Presentation int presentation) {
Tyler Gunn68a73a42018-10-03 15:38:57 -07001167 Log.d(this, "setCallerDisplayName %s", callerDisplayName);
Tyler Gunnac60f952019-05-31 07:23:16 -07001168 mCallerDisplayName = callerDisplayName;
1169 mCallerDisplayNamePresentation = presentation;
Tyler Gunn68a73a42018-10-03 15:38:57 -07001170 for (Listener l : mListeners) {
1171 l.onCallerDisplayNameChanged(this, callerDisplayName, presentation);
1172 }
1173 }
1174
1175 /**
Tyler Gunndee56a82016-03-23 16:06:34 -07001176 * Handles a change to extras received from Telecom.
1177 *
1178 * @param extras The new extras.
1179 * @hide
1180 */
1181 final void handleExtrasChanged(Bundle extras) {
Brad Ebinger4fa6a012016-06-14 17:04:01 -07001182 Bundle b = null;
1183 synchronized (mExtrasLock) {
1184 mExtras = extras;
1185 if (mExtras != null) {
1186 b = new Bundle(mExtras);
1187 }
1188 }
1189 onExtrasChanged(b);
Tyler Gunndee56a82016-03-23 16:06:34 -07001190 }
Hall Liuc9bc1c62019-04-16 14:00:55 -07001191
1192 /**
Tyler Gunnc9503d62020-01-27 10:30:51 -08001193 * Sends an event associated with this {@link Conference} with associated event extras to the
1194 * {@link InCallService}.
1195 * <p>
1196 * Connection events are used to communicate point in time information from a
1197 * {@link ConnectionService} to an {@link InCallService} implementation. An example of a
1198 * custom connection event includes notifying the UI when a WIFI call has been handed over to
1199 * LTE, which the InCall UI might use to inform the user that billing charges may apply. The
1200 * Android Telephony framework will send the {@link Connection#EVENT_MERGE_COMPLETE}
1201 * connection event when a call to {@link Call#mergeConference()} has completed successfully.
1202 * <p>
1203 * Events are exposed to {@link InCallService} implementations via
1204 * {@link Call.Callback#onConnectionEvent(Call, String, Bundle)}.
1205 * <p>
1206 * No assumptions should be made as to how an In-Call UI or service will handle these events.
1207 * The {@link ConnectionService} must assume that the In-Call UI could even chose to ignore
1208 * some events altogether.
1209 * <p>
1210 * Events should be fully qualified (e.g. {@code com.example.event.MY_EVENT}) to avoid
1211 * conflicts between {@link ConnectionService} implementations. Further, custom
1212 * {@link ConnectionService} implementations shall not re-purpose events in the
1213 * {@code android.*} namespace, nor shall they define new event types in this namespace. When
1214 * defining a custom event type, ensure the contents of the extras {@link Bundle} is clearly
1215 * defined. Extra keys for this bundle should be named similar to the event type (e.g.
1216 * {@code com.example.extra.MY_EXTRA}).
1217 * <p>
1218 * When defining events and the associated extras, it is important to keep their behavior
1219 * consistent when the associated {@link ConnectionService} is updated. Support for deprecated
1220 * events/extras should me maintained to ensure backwards compatibility with older
1221 * {@link InCallService} implementations which were built to support the older behavior.
1222 * <p>
1223 * Expected connection events from the Telephony stack are:
1224 * <p>
1225 * <ul>
1226 * <li>{@link Connection#EVENT_CALL_HOLD_FAILED} with {@code null} {@code extras} when the
1227 * {@link Conference} could not be held.</li>
1228 * <li>{@link Connection#EVENT_MERGE_START} with {@code null} {@code extras} when a new
1229 * call is being merged into the conference.</li>
1230 * <li>{@link Connection#EVENT_MERGE_COMPLETE} with {@code null} {@code extras} a new call
1231 * has completed being merged into the conference.</li>
1232 * <li>{@link Connection#EVENT_CALL_MERGE_FAILED} with {@code null} {@code extras} a new
1233 * call has failed to merge into the conference (the dialer app can determine which call
1234 * failed to merge based on the fact that the call still exists outside of the conference
1235 * at the end of the merge process).</li>
1236 * </ul>
Tyler Gunn5567d742019-10-31 13:04:37 -07001237 *
Tyler Gunnc9503d62020-01-27 10:30:51 -08001238 * @param event The conference event.
Tyler Gunn5567d742019-10-31 13:04:37 -07001239 * @param extras Optional bundle containing extra information associated with the event.
Hall Liuc9bc1c62019-04-16 14:00:55 -07001240 */
Tyler Gunn5567d742019-10-31 13:04:37 -07001241 public void sendConferenceEvent(@NonNull String event, @Nullable Bundle extras) {
Hall Liuc9bc1c62019-04-16 14:00:55 -07001242 for (Listener l : mListeners) {
1243 l.onConnectionEvent(this, event, extras);
1244 }
1245 }
Santos Cordon823fd3c2014-08-07 18:35:18 -07001246}