| Ihab Awad | b8e85c7 | 2014-08-23 20:34:57 -0700 | [diff] [blame] | 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 |  | 
| Tyler Gunn | ef9f6f9 | 2014-09-12 22:16:17 -0700 | [diff] [blame] | 17 | package android.telecom; | 
| Ihab Awad | b8e85c7 | 2014-08-23 20:34:57 -0700 | [diff] [blame] | 18 |  | 
| Santos Cordon | 6b7f955 | 2015-05-27 17:21:45 -0700 | [diff] [blame] | 19 | import android.annotation.Nullable; | 
| Yorke Lee | 4af5935 | 2015-05-13 14:14:54 -0700 | [diff] [blame] | 20 | import android.annotation.SystemApi; | 
| Santos Cordon | 6b7f955 | 2015-05-27 17:21:45 -0700 | [diff] [blame] | 21 | import android.os.Bundle; | 
| Andrew Lee | 011728f | 2015-04-23 15:47:06 -0700 | [diff] [blame] | 22 | import android.os.Handler; | 
| Ihab Awad | b8e85c7 | 2014-08-23 20:34:57 -0700 | [diff] [blame] | 23 | import android.os.RemoteException; | 
| Ihab Awad | b8e85c7 | 2014-08-23 20:34:57 -0700 | [diff] [blame] | 24 |  | 
| Grace Jia | 9a09c67 | 2020-08-04 12:52:09 -0700 | [diff] [blame] | 25 | import com.android.internal.telecom.IConnectionService; | 
 | 26 |  | 
| Ihab Awad | 50e3506 | 2014-09-30 09:17:03 -0700 | [diff] [blame] | 27 | import java.util.ArrayList; | 
| Ihab Awad | b8e85c7 | 2014-08-23 20:34:57 -0700 | [diff] [blame] | 28 | import java.util.Collections; | 
 | 29 | import java.util.List; | 
 | 30 | import java.util.Set; | 
 | 31 | import java.util.concurrent.CopyOnWriteArrayList; | 
 | 32 | import java.util.concurrent.CopyOnWriteArraySet; | 
 | 33 |  | 
 | 34 | /** | 
| Santos Cordon | 895d4b8 | 2015-06-25 16:41:48 -0700 | [diff] [blame] | 35 |  * A conference provided to a {@link ConnectionService} by another {@code ConnectionService} through | 
 | 36 |  * {@link ConnectionService#conferenceRemoteConnections}. Once created, a {@code RemoteConference} | 
 | 37 |  * can be used to control the conference call or monitor changes through | 
 | 38 |  * {@link RemoteConnection.Callback}. | 
| Santos Cordon | b804f8d | 2015-05-12 12:09:47 -0700 | [diff] [blame] | 39 |  * | 
 | 40 |  * @see ConnectionService#onRemoteConferenceAdded | 
| Ihab Awad | b8e85c7 | 2014-08-23 20:34:57 -0700 | [diff] [blame] | 41 |  */ | 
 | 42 | public final class RemoteConference { | 
 | 43 |  | 
| Santos Cordon | 895d4b8 | 2015-06-25 16:41:48 -0700 | [diff] [blame] | 44 |     /** | 
 | 45 |      * Callback base class for {@link RemoteConference}. | 
 | 46 |      */ | 
| Nancy Chen | 1d834f5 | 2014-09-05 11:03:21 -0700 | [diff] [blame] | 47 |     public abstract static class Callback { | 
| Santos Cordon | 895d4b8 | 2015-06-25 16:41:48 -0700 | [diff] [blame] | 48 |         /** | 
 | 49 |          * Invoked when the state of this {@code RemoteConferece} has changed. See | 
 | 50 |          * {@link #getState()}. | 
 | 51 |          * | 
 | 52 |          * @param conference The {@code RemoteConference} invoking this method. | 
 | 53 |          * @param oldState The previous state of the {@code RemoteConference}. | 
 | 54 |          * @param newState The new state of the {@code RemoteConference}. | 
 | 55 |          */ | 
| Ihab Awad | b8e85c7 | 2014-08-23 20:34:57 -0700 | [diff] [blame] | 56 |         public void onStateChanged(RemoteConference conference, int oldState, int newState) {} | 
| Santos Cordon | 895d4b8 | 2015-06-25 16:41:48 -0700 | [diff] [blame] | 57 |  | 
 | 58 |         /** | 
 | 59 |          * Invoked when this {@code RemoteConference} is disconnected. | 
 | 60 |          * | 
 | 61 |          * @param conference The {@code RemoteConference} invoking this method. | 
 | 62 |          * @param disconnectCause The ({@see DisconnectCause}) associated with this failed | 
 | 63 |          *     conference. | 
 | 64 |          */ | 
| Andrew Lee | 7f3d41f | 2014-09-11 17:33:16 -0700 | [diff] [blame] | 65 |         public void onDisconnected(RemoteConference conference, DisconnectCause disconnectCause) {} | 
| Santos Cordon | 895d4b8 | 2015-06-25 16:41:48 -0700 | [diff] [blame] | 66 |  | 
 | 67 |         /** | 
 | 68 |          * Invoked when a {@link RemoteConnection} is added to the conference call. | 
 | 69 |          * | 
 | 70 |          * @param conference The {@code RemoteConference} invoking this method. | 
 | 71 |          * @param connection The {@link RemoteConnection} being added. | 
 | 72 |          */ | 
| Ihab Awad | b8e85c7 | 2014-08-23 20:34:57 -0700 | [diff] [blame] | 73 |         public void onConnectionAdded(RemoteConference conference, RemoteConnection connection) {} | 
| Santos Cordon | 895d4b8 | 2015-06-25 16:41:48 -0700 | [diff] [blame] | 74 |  | 
 | 75 |         /** | 
 | 76 |          * Invoked when a {@link RemoteConnection} is removed from the conference call. | 
 | 77 |          * | 
 | 78 |          * @param conference The {@code RemoteConference} invoking this method. | 
 | 79 |          * @param connection The {@link RemoteConnection} being removed. | 
 | 80 |          */ | 
| Ihab Awad | b8e85c7 | 2014-08-23 20:34:57 -0700 | [diff] [blame] | 81 |         public void onConnectionRemoved(RemoteConference conference, RemoteConnection connection) {} | 
| Santos Cordon | 895d4b8 | 2015-06-25 16:41:48 -0700 | [diff] [blame] | 82 |  | 
 | 83 |         /** | 
 | 84 |          * Indicates that the call capabilities of this {@code RemoteConference} have changed. | 
 | 85 |          * See {@link #getConnectionCapabilities()}. | 
 | 86 |          * | 
 | 87 |          * @param conference The {@code RemoteConference} invoking this method. | 
 | 88 |          * @param connectionCapabilities The new capabilities of the {@code RemoteConference}. | 
 | 89 |          */ | 
| Ihab Awad | 5c9c86e | 2014-11-12 13:41:16 -0800 | [diff] [blame] | 90 |         public void onConnectionCapabilitiesChanged( | 
 | 91 |                 RemoteConference conference, | 
 | 92 |                 int connectionCapabilities) {} | 
| Santos Cordon | 895d4b8 | 2015-06-25 16:41:48 -0700 | [diff] [blame] | 93 |  | 
 | 94 |         /** | 
| Tyler Gunn | 720c664 | 2016-03-22 09:02:47 -0700 | [diff] [blame] | 95 |          * Indicates that the call properties of this {@code RemoteConference} have changed. | 
 | 96 |          * See {@link #getConnectionProperties()}. | 
 | 97 |          * | 
 | 98 |          * @param conference The {@code RemoteConference} invoking this method. | 
 | 99 |          * @param connectionProperties The new properties of the {@code RemoteConference}. | 
 | 100 |          */ | 
 | 101 |         public void onConnectionPropertiesChanged( | 
 | 102 |                 RemoteConference conference, | 
 | 103 |                 int connectionProperties) {} | 
 | 104 |  | 
 | 105 |  | 
 | 106 |         /** | 
| Santos Cordon | 895d4b8 | 2015-06-25 16:41:48 -0700 | [diff] [blame] | 107 |          * Invoked when the set of {@link RemoteConnection}s which can be added to this conference | 
 | 108 |          * call have changed. | 
 | 109 |          * | 
 | 110 |          * @param conference The {@code RemoteConference} invoking this method. | 
 | 111 |          * @param conferenceableConnections The list of conferenceable {@link RemoteConnection}s. | 
 | 112 |          */ | 
| Ihab Awad | 50e3506 | 2014-09-30 09:17:03 -0700 | [diff] [blame] | 113 |         public void onConferenceableConnectionsChanged( | 
 | 114 |                 RemoteConference conference, | 
 | 115 |                 List<RemoteConnection> conferenceableConnections) {} | 
| Santos Cordon | 895d4b8 | 2015-06-25 16:41:48 -0700 | [diff] [blame] | 116 |  | 
 | 117 |         /** | 
 | 118 |          * Indicates that this {@code RemoteConference} has been destroyed. No further requests | 
 | 119 |          * should be made to the {@code RemoteConference}, and references to it should be cleared. | 
 | 120 |          * | 
 | 121 |          * @param conference The {@code RemoteConference} invoking this method. | 
 | 122 |          */ | 
| Ihab Awad | b8e85c7 | 2014-08-23 20:34:57 -0700 | [diff] [blame] | 123 |         public void onDestroyed(RemoteConference conference) {} | 
| Santos Cordon | 895d4b8 | 2015-06-25 16:41:48 -0700 | [diff] [blame] | 124 |  | 
 | 125 |         /** | 
 | 126 |          * Handles changes to the {@code RemoteConference} extras. | 
 | 127 |          * | 
 | 128 |          * @param conference The {@code RemoteConference} invoking this method. | 
 | 129 |          * @param extras The extras containing other information associated with the conference. | 
 | 130 |          */ | 
| Santos Cordon | 6b7f955 | 2015-05-27 17:21:45 -0700 | [diff] [blame] | 131 |         public void onExtrasChanged(RemoteConference conference, @Nullable Bundle extras) {} | 
| Ihab Awad | b8e85c7 | 2014-08-23 20:34:57 -0700 | [diff] [blame] | 132 |     } | 
 | 133 |  | 
 | 134 |     private final String mId; | 
 | 135 |     private final IConnectionService mConnectionService; | 
 | 136 |  | 
| Andrew Lee | 011728f | 2015-04-23 15:47:06 -0700 | [diff] [blame] | 137 |     private final Set<CallbackRecord<Callback>> mCallbackRecords = new CopyOnWriteArraySet<>(); | 
| Ihab Awad | b8e85c7 | 2014-08-23 20:34:57 -0700 | [diff] [blame] | 138 |     private final List<RemoteConnection> mChildConnections = new CopyOnWriteArrayList<>(); | 
 | 139 |     private final List<RemoteConnection> mUnmodifiableChildConnections = | 
 | 140 |             Collections.unmodifiableList(mChildConnections); | 
| Ihab Awad | 50e3506 | 2014-09-30 09:17:03 -0700 | [diff] [blame] | 141 |     private final List<RemoteConnection> mConferenceableConnections = new ArrayList<>(); | 
 | 142 |     private final List<RemoteConnection> mUnmodifiableConferenceableConnections = | 
 | 143 |             Collections.unmodifiableList(mConferenceableConnections); | 
| Ihab Awad | b8e85c7 | 2014-08-23 20:34:57 -0700 | [diff] [blame] | 144 |  | 
 | 145 |     private int mState = Connection.STATE_NEW; | 
| Andrew Lee | 7f3d41f | 2014-09-11 17:33:16 -0700 | [diff] [blame] | 146 |     private DisconnectCause mDisconnectCause; | 
| Ihab Awad | 5c9c86e | 2014-11-12 13:41:16 -0800 | [diff] [blame] | 147 |     private int mConnectionCapabilities; | 
| Tyler Gunn | 720c664 | 2016-03-22 09:02:47 -0700 | [diff] [blame] | 148 |     private int mConnectionProperties; | 
| Santos Cordon | 6b7f955 | 2015-05-27 17:21:45 -0700 | [diff] [blame] | 149 |     private Bundle mExtras; | 
| Ihab Awad | b8e85c7 | 2014-08-23 20:34:57 -0700 | [diff] [blame] | 150 |  | 
| Santos Cordon | b804f8d | 2015-05-12 12:09:47 -0700 | [diff] [blame] | 151 |     /** @hide */ | 
| Ihab Awad | b8e85c7 | 2014-08-23 20:34:57 -0700 | [diff] [blame] | 152 |     RemoteConference(String id, IConnectionService connectionService) { | 
 | 153 |         mId = id; | 
 | 154 |         mConnectionService = connectionService; | 
 | 155 |     } | 
 | 156 |  | 
| Santos Cordon | b804f8d | 2015-05-12 12:09:47 -0700 | [diff] [blame] | 157 |     /** @hide */ | 
| Grace Jia | 9a09c67 | 2020-08-04 12:52:09 -0700 | [diff] [blame] | 158 |     RemoteConference(DisconnectCause disconnectCause) { | 
 | 159 |         mId = "NULL"; | 
 | 160 |         mConnectionService = null; | 
 | 161 |         mState = Connection.STATE_DISCONNECTED; | 
 | 162 |         mDisconnectCause = disconnectCause; | 
 | 163 |     } | 
 | 164 |  | 
 | 165 |     /** @hide */ | 
| Ihab Awad | b8e85c7 | 2014-08-23 20:34:57 -0700 | [diff] [blame] | 166 |     String getId() { | 
 | 167 |         return mId; | 
 | 168 |     } | 
 | 169 |  | 
| Santos Cordon | b804f8d | 2015-05-12 12:09:47 -0700 | [diff] [blame] | 170 |     /** @hide */ | 
| Ihab Awad | b8e85c7 | 2014-08-23 20:34:57 -0700 | [diff] [blame] | 171 |     void setDestroyed() { | 
 | 172 |         for (RemoteConnection connection : mChildConnections) { | 
 | 173 |             connection.setConference(null); | 
 | 174 |         } | 
| Andrew Lee | 011728f | 2015-04-23 15:47:06 -0700 | [diff] [blame] | 175 |         for (CallbackRecord<Callback> record : mCallbackRecords) { | 
 | 176 |             final RemoteConference conference = this; | 
 | 177 |             final Callback callback = record.getCallback(); | 
 | 178 |             record.getHandler().post(new Runnable() { | 
 | 179 |                 @Override | 
 | 180 |                 public void run() { | 
 | 181 |                     callback.onDestroyed(conference); | 
 | 182 |                 } | 
 | 183 |             }); | 
| Ihab Awad | b8e85c7 | 2014-08-23 20:34:57 -0700 | [diff] [blame] | 184 |         } | 
 | 185 |     } | 
 | 186 |  | 
| Santos Cordon | b804f8d | 2015-05-12 12:09:47 -0700 | [diff] [blame] | 187 |     /** @hide */ | 
| Andrew Lee | 011728f | 2015-04-23 15:47:06 -0700 | [diff] [blame] | 188 |     void setState(final int newState) { | 
| Ihab Awad | b8e85c7 | 2014-08-23 20:34:57 -0700 | [diff] [blame] | 189 |         if (newState != Connection.STATE_ACTIVE && | 
 | 190 |                 newState != Connection.STATE_HOLDING && | 
 | 191 |                 newState != Connection.STATE_DISCONNECTED) { | 
 | 192 |             Log.w(this, "Unsupported state transition for Conference call.", | 
 | 193 |                     Connection.stateToString(newState)); | 
 | 194 |             return; | 
 | 195 |         } | 
 | 196 |  | 
 | 197 |         if (mState != newState) { | 
| Andrew Lee | 011728f | 2015-04-23 15:47:06 -0700 | [diff] [blame] | 198 |             final int oldState = mState; | 
| Ihab Awad | b8e85c7 | 2014-08-23 20:34:57 -0700 | [diff] [blame] | 199 |             mState = newState; | 
| Andrew Lee | 011728f | 2015-04-23 15:47:06 -0700 | [diff] [blame] | 200 |             for (CallbackRecord<Callback> record : mCallbackRecords) { | 
 | 201 |                 final RemoteConference conference = this; | 
 | 202 |                 final Callback callback = record.getCallback(); | 
 | 203 |                 record.getHandler().post(new Runnable() { | 
 | 204 |                     @Override | 
 | 205 |                     public void run() { | 
 | 206 |                         callback.onStateChanged(conference, oldState, newState); | 
 | 207 |                     } | 
 | 208 |                 }); | 
| Ihab Awad | b8e85c7 | 2014-08-23 20:34:57 -0700 | [diff] [blame] | 209 |             } | 
 | 210 |         } | 
 | 211 |     } | 
 | 212 |  | 
| Santos Cordon | b804f8d | 2015-05-12 12:09:47 -0700 | [diff] [blame] | 213 |     /** @hide */ | 
| Andrew Lee | 011728f | 2015-04-23 15:47:06 -0700 | [diff] [blame] | 214 |     void addConnection(final RemoteConnection connection) { | 
| Ihab Awad | b8e85c7 | 2014-08-23 20:34:57 -0700 | [diff] [blame] | 215 |         if (!mChildConnections.contains(connection)) { | 
 | 216 |             mChildConnections.add(connection); | 
 | 217 |             connection.setConference(this); | 
| Andrew Lee | 011728f | 2015-04-23 15:47:06 -0700 | [diff] [blame] | 218 |             for (CallbackRecord<Callback> record : mCallbackRecords) { | 
 | 219 |                 final RemoteConference conference = this; | 
 | 220 |                 final Callback callback = record.getCallback(); | 
 | 221 |                 record.getHandler().post(new Runnable() { | 
 | 222 |                     @Override | 
 | 223 |                     public void run() { | 
 | 224 |                         callback.onConnectionAdded(conference, connection); | 
 | 225 |                     } | 
 | 226 |                 }); | 
| Ihab Awad | b8e85c7 | 2014-08-23 20:34:57 -0700 | [diff] [blame] | 227 |             } | 
 | 228 |         } | 
 | 229 |     } | 
 | 230 |  | 
| Santos Cordon | b804f8d | 2015-05-12 12:09:47 -0700 | [diff] [blame] | 231 |     /** @hide */ | 
| Andrew Lee | 011728f | 2015-04-23 15:47:06 -0700 | [diff] [blame] | 232 |     void removeConnection(final RemoteConnection connection) { | 
| Ihab Awad | b8e85c7 | 2014-08-23 20:34:57 -0700 | [diff] [blame] | 233 |         if (mChildConnections.contains(connection)) { | 
 | 234 |             mChildConnections.remove(connection); | 
 | 235 |             connection.setConference(null); | 
| Andrew Lee | 011728f | 2015-04-23 15:47:06 -0700 | [diff] [blame] | 236 |             for (CallbackRecord<Callback> record : mCallbackRecords) { | 
 | 237 |                 final RemoteConference conference = this; | 
 | 238 |                 final Callback callback = record.getCallback(); | 
 | 239 |                 record.getHandler().post(new Runnable() { | 
 | 240 |                     @Override | 
 | 241 |                     public void run() { | 
 | 242 |                         callback.onConnectionRemoved(conference, connection); | 
 | 243 |                     } | 
 | 244 |                 }); | 
| Ihab Awad | b8e85c7 | 2014-08-23 20:34:57 -0700 | [diff] [blame] | 245 |             } | 
 | 246 |         } | 
 | 247 |     } | 
 | 248 |  | 
| Santos Cordon | b804f8d | 2015-05-12 12:09:47 -0700 | [diff] [blame] | 249 |     /** @hide */ | 
| Andrew Lee | 011728f | 2015-04-23 15:47:06 -0700 | [diff] [blame] | 250 |     void setConnectionCapabilities(final int connectionCapabilities) { | 
| Ihab Awad | 5c9c86e | 2014-11-12 13:41:16 -0800 | [diff] [blame] | 251 |         if (mConnectionCapabilities != connectionCapabilities) { | 
 | 252 |             mConnectionCapabilities = connectionCapabilities; | 
| Andrew Lee | 011728f | 2015-04-23 15:47:06 -0700 | [diff] [blame] | 253 |             for (CallbackRecord<Callback> record : mCallbackRecords) { | 
 | 254 |                 final RemoteConference conference = this; | 
 | 255 |                 final Callback callback = record.getCallback(); | 
 | 256 |                 record.getHandler().post(new Runnable() { | 
 | 257 |                     @Override | 
 | 258 |                     public void run() { | 
 | 259 |                         callback.onConnectionCapabilitiesChanged( | 
 | 260 |                                 conference, mConnectionCapabilities); | 
 | 261 |                     } | 
 | 262 |                 }); | 
| Ihab Awad | b8e85c7 | 2014-08-23 20:34:57 -0700 | [diff] [blame] | 263 |             } | 
 | 264 |         } | 
 | 265 |     } | 
 | 266 |  | 
| Ihab Awad | 50e3506 | 2014-09-30 09:17:03 -0700 | [diff] [blame] | 267 |     /** @hide */ | 
| Tyler Gunn | 720c664 | 2016-03-22 09:02:47 -0700 | [diff] [blame] | 268 |     void setConnectionProperties(final int connectionProperties) { | 
 | 269 |         if (mConnectionProperties != connectionProperties) { | 
 | 270 |             mConnectionProperties = connectionProperties; | 
 | 271 |             for (CallbackRecord<Callback> record : mCallbackRecords) { | 
 | 272 |                 final RemoteConference conference = this; | 
 | 273 |                 final Callback callback = record.getCallback(); | 
 | 274 |                 record.getHandler().post(new Runnable() { | 
 | 275 |                     @Override | 
 | 276 |                     public void run() { | 
 | 277 |                         callback.onConnectionPropertiesChanged( | 
 | 278 |                                 conference, mConnectionProperties); | 
 | 279 |                     } | 
 | 280 |                 }); | 
 | 281 |             } | 
 | 282 |         } | 
 | 283 |     } | 
 | 284 |  | 
 | 285 |     /** @hide */ | 
| Ihab Awad | 50e3506 | 2014-09-30 09:17:03 -0700 | [diff] [blame] | 286 |     void setConferenceableConnections(List<RemoteConnection> conferenceableConnections) { | 
 | 287 |         mConferenceableConnections.clear(); | 
 | 288 |         mConferenceableConnections.addAll(conferenceableConnections); | 
| Andrew Lee | 011728f | 2015-04-23 15:47:06 -0700 | [diff] [blame] | 289 |         for (CallbackRecord<Callback> record : mCallbackRecords) { | 
 | 290 |             final RemoteConference conference = this; | 
 | 291 |             final Callback callback = record.getCallback(); | 
 | 292 |             record.getHandler().post(new Runnable() { | 
 | 293 |                 @Override | 
 | 294 |                 public void run() { | 
 | 295 |                     callback.onConferenceableConnectionsChanged( | 
 | 296 |                             conference, mUnmodifiableConferenceableConnections); | 
 | 297 |                 } | 
 | 298 |             }); | 
| Ihab Awad | 50e3506 | 2014-09-30 09:17:03 -0700 | [diff] [blame] | 299 |         } | 
 | 300 |     } | 
 | 301 |  | 
| Santos Cordon | b804f8d | 2015-05-12 12:09:47 -0700 | [diff] [blame] | 302 |     /** @hide */ | 
| Andrew Lee | 011728f | 2015-04-23 15:47:06 -0700 | [diff] [blame] | 303 |     void setDisconnected(final DisconnectCause disconnectCause) { | 
| Ihab Awad | b8e85c7 | 2014-08-23 20:34:57 -0700 | [diff] [blame] | 304 |         if (mState != Connection.STATE_DISCONNECTED) { | 
| Andrew Lee | 7f3d41f | 2014-09-11 17:33:16 -0700 | [diff] [blame] | 305 |             mDisconnectCause = disconnectCause; | 
| Ihab Awad | b8e85c7 | 2014-08-23 20:34:57 -0700 | [diff] [blame] | 306 |             setState(Connection.STATE_DISCONNECTED); | 
| Andrew Lee | 011728f | 2015-04-23 15:47:06 -0700 | [diff] [blame] | 307 |             for (CallbackRecord<Callback> record : mCallbackRecords) { | 
 | 308 |                 final RemoteConference conference = this; | 
 | 309 |                 final Callback callback = record.getCallback(); | 
 | 310 |                 record.getHandler().post(new Runnable() { | 
 | 311 |                     @Override | 
 | 312 |                     public void run() { | 
 | 313 |                         callback.onDisconnected(conference, disconnectCause); | 
 | 314 |                     } | 
 | 315 |                 }); | 
| Ihab Awad | b8e85c7 | 2014-08-23 20:34:57 -0700 | [diff] [blame] | 316 |             } | 
 | 317 |         } | 
 | 318 |     } | 
 | 319 |  | 
| Santos Cordon | 6b7f955 | 2015-05-27 17:21:45 -0700 | [diff] [blame] | 320 |     /** @hide */ | 
| Tyler Gunn | dee56a8 | 2016-03-23 16:06:34 -0700 | [diff] [blame] | 321 |     void putExtras(final Bundle extras) { | 
| Tyler Gunn | 2282bb9 | 2016-10-17 15:48:19 -0700 | [diff] [blame] | 322 |         if (extras == null) { | 
 | 323 |             return; | 
 | 324 |         } | 
| Tyler Gunn | dee56a8 | 2016-03-23 16:06:34 -0700 | [diff] [blame] | 325 |         if (mExtras == null) { | 
 | 326 |             mExtras = new Bundle(); | 
 | 327 |         } | 
 | 328 |         mExtras.putAll(extras); | 
 | 329 |  | 
 | 330 |         notifyExtrasChanged(); | 
 | 331 |     } | 
 | 332 |  | 
 | 333 |     /** @hide */ | 
 | 334 |     void removeExtras(List<String> keys) { | 
 | 335 |         if (mExtras == null || keys == null || keys.isEmpty()) { | 
 | 336 |             return; | 
 | 337 |         } | 
 | 338 |         for (String key : keys) { | 
 | 339 |             mExtras.remove(key); | 
 | 340 |         } | 
 | 341 |  | 
 | 342 |         notifyExtrasChanged(); | 
 | 343 |     } | 
 | 344 |  | 
 | 345 |     private void notifyExtrasChanged() { | 
| Santos Cordon | 6b7f955 | 2015-05-27 17:21:45 -0700 | [diff] [blame] | 346 |         for (CallbackRecord<Callback> record : mCallbackRecords) { | 
 | 347 |             final RemoteConference conference = this; | 
 | 348 |             final Callback callback = record.getCallback(); | 
 | 349 |             record.getHandler().post(new Runnable() { | 
 | 350 |                 @Override | 
 | 351 |                 public void run() { | 
| Tyler Gunn | dee56a8 | 2016-03-23 16:06:34 -0700 | [diff] [blame] | 352 |                     callback.onExtrasChanged(conference, mExtras); | 
| Santos Cordon | 6b7f955 | 2015-05-27 17:21:45 -0700 | [diff] [blame] | 353 |                 } | 
 | 354 |             }); | 
 | 355 |         } | 
 | 356 |     } | 
 | 357 |  | 
| Santos Cordon | b804f8d | 2015-05-12 12:09:47 -0700 | [diff] [blame] | 358 |     /** | 
 | 359 |      * Returns the list of {@link RemoteConnection}s contained in this conference. | 
 | 360 |      * | 
 | 361 |      * @return A list of child connections. | 
 | 362 |      */ | 
| Ihab Awad | b8e85c7 | 2014-08-23 20:34:57 -0700 | [diff] [blame] | 363 |     public final List<RemoteConnection> getConnections() { | 
 | 364 |         return mUnmodifiableChildConnections; | 
 | 365 |     } | 
 | 366 |  | 
| Santos Cordon | b804f8d | 2015-05-12 12:09:47 -0700 | [diff] [blame] | 367 |     /** | 
 | 368 |      * Gets the state of the conference call. See {@link Connection} for valid values. | 
 | 369 |      * | 
 | 370 |      * @return A constant representing the state the conference call is currently in. | 
 | 371 |      */ | 
| Ihab Awad | b8e85c7 | 2014-08-23 20:34:57 -0700 | [diff] [blame] | 372 |     public final int getState() { | 
 | 373 |         return mState; | 
 | 374 |     } | 
 | 375 |  | 
| Santos Cordon | b804f8d | 2015-05-12 12:09:47 -0700 | [diff] [blame] | 376 |     /** | 
 | 377 |      * Returns the capabilities of the conference. See {@code CAPABILITY_*} constants in class | 
 | 378 |      * {@link Connection} for valid values. | 
 | 379 |      * | 
 | 380 |      * @return A bitmask of the capabilities of the conference call. | 
 | 381 |      */ | 
| Ihab Awad | 5c9c86e | 2014-11-12 13:41:16 -0800 | [diff] [blame] | 382 |     public final int getConnectionCapabilities() { | 
 | 383 |         return mConnectionCapabilities; | 
| Ihab Awad | b8e85c7 | 2014-08-23 20:34:57 -0700 | [diff] [blame] | 384 |     } | 
 | 385 |  | 
| Santos Cordon | b804f8d | 2015-05-12 12:09:47 -0700 | [diff] [blame] | 386 |     /** | 
| Tyler Gunn | 720c664 | 2016-03-22 09:02:47 -0700 | [diff] [blame] | 387 |      * Returns the properties of the conference. See {@code PROPERTY_*} constants in class | 
 | 388 |      * {@link Connection} for valid values. | 
 | 389 |      * | 
 | 390 |      * @return A bitmask of the properties of the conference call. | 
 | 391 |      */ | 
 | 392 |     public final int getConnectionProperties() { | 
 | 393 |         return mConnectionProperties; | 
 | 394 |     } | 
 | 395 |  | 
 | 396 |     /** | 
| Santos Cordon | 6b7f955 | 2015-05-27 17:21:45 -0700 | [diff] [blame] | 397 |      * Obtain the extras associated with this {@code RemoteConnection}. | 
 | 398 |      * | 
 | 399 |      * @return The extras for this connection. | 
 | 400 |      */ | 
 | 401 |     public final Bundle getExtras() { | 
 | 402 |         return mExtras; | 
 | 403 |     } | 
 | 404 |  | 
 | 405 |     /** | 
| Santos Cordon | b804f8d | 2015-05-12 12:09:47 -0700 | [diff] [blame] | 406 |      * Disconnects the conference call as well as the child {@link RemoteConnection}s. | 
 | 407 |      */ | 
| Ihab Awad | b8e85c7 | 2014-08-23 20:34:57 -0700 | [diff] [blame] | 408 |     public void disconnect() { | 
 | 409 |         try { | 
| Brad Ebinger | b32d4f8 | 2016-10-24 16:40:49 -0700 | [diff] [blame] | 410 |             mConnectionService.disconnect(mId, null /*Session.Info*/); | 
| Ihab Awad | b8e85c7 | 2014-08-23 20:34:57 -0700 | [diff] [blame] | 411 |         } catch (RemoteException e) { | 
 | 412 |         } | 
 | 413 |     } | 
 | 414 |  | 
| Santos Cordon | b804f8d | 2015-05-12 12:09:47 -0700 | [diff] [blame] | 415 |     /** | 
 | 416 |      * Removes the specified {@link RemoteConnection} from the conference. This causes the | 
 | 417 |      * {@link RemoteConnection} to become a standalone connection. This is a no-op if the | 
 | 418 |      * {@link RemoteConnection} does not belong to this conference. | 
 | 419 |      * | 
 | 420 |      * @param connection The remote-connection to remove. | 
 | 421 |      */ | 
| Ihab Awad | b8e85c7 | 2014-08-23 20:34:57 -0700 | [diff] [blame] | 422 |     public void separate(RemoteConnection connection) { | 
 | 423 |         if (mChildConnections.contains(connection)) { | 
 | 424 |             try { | 
| Brad Ebinger | b32d4f8 | 2016-10-24 16:40:49 -0700 | [diff] [blame] | 425 |                 mConnectionService.splitFromConference(connection.getId(), null /*Session.Info*/); | 
| Ihab Awad | b8e85c7 | 2014-08-23 20:34:57 -0700 | [diff] [blame] | 426 |             } catch (RemoteException e) { | 
 | 427 |             } | 
 | 428 |         } | 
 | 429 |     } | 
 | 430 |  | 
| Santos Cordon | b804f8d | 2015-05-12 12:09:47 -0700 | [diff] [blame] | 431 |     /** | 
 | 432 |      * Merges all {@link RemoteConnection}s of this conference into a single call. This should be | 
 | 433 |      * invoked only if the conference contains the capability | 
 | 434 |      * {@link Connection#CAPABILITY_MERGE_CONFERENCE}, otherwise it is a no-op. The presence of said | 
 | 435 |      * capability indicates that the connections of this conference, despite being part of the | 
 | 436 |      * same conference object, are yet to have their audio streams merged; this is a common pattern | 
 | 437 |      * for CDMA conference calls, but the capability is not used for GSM and SIP conference calls. | 
 | 438 |      * Invoking this method will cause the unmerged child connections to merge their audio | 
 | 439 |      * streams. | 
 | 440 |      */ | 
| mike dooley | 95ea576 | 2014-09-25 14:49:21 -0700 | [diff] [blame] | 441 |     public void merge() { | 
 | 442 |         try { | 
| Brad Ebinger | b32d4f8 | 2016-10-24 16:40:49 -0700 | [diff] [blame] | 443 |             mConnectionService.mergeConference(mId, null /*Session.Info*/); | 
| mike dooley | 95ea576 | 2014-09-25 14:49:21 -0700 | [diff] [blame] | 444 |         } catch (RemoteException e) { | 
 | 445 |         } | 
 | 446 |     } | 
 | 447 |  | 
| Santos Cordon | b804f8d | 2015-05-12 12:09:47 -0700 | [diff] [blame] | 448 |     /** | 
 | 449 |      * Swaps the active audio stream between the conference's child {@link RemoteConnection}s. | 
 | 450 |      * This should be invoked only if the conference contains the capability | 
 | 451 |      * {@link Connection#CAPABILITY_SWAP_CONFERENCE}, otherwise it is a no-op. This is only used by | 
 | 452 |      * {@link ConnectionService}s that create conferences for connections that do not yet have | 
 | 453 |      * their audio streams merged; this is a common pattern for CDMA conference calls, but the | 
 | 454 |      * capability is not used for GSM and SIP conference calls. Invoking this method will change the | 
 | 455 |      * active audio stream to a different child connection. | 
 | 456 |      */ | 
| mike dooley | 95ea576 | 2014-09-25 14:49:21 -0700 | [diff] [blame] | 457 |     public void swap() { | 
 | 458 |         try { | 
| Brad Ebinger | b32d4f8 | 2016-10-24 16:40:49 -0700 | [diff] [blame] | 459 |             mConnectionService.swapConference(mId, null /*Session.Info*/); | 
| mike dooley | 95ea576 | 2014-09-25 14:49:21 -0700 | [diff] [blame] | 460 |         } catch (RemoteException e) { | 
 | 461 |         } | 
 | 462 |     } | 
 | 463 |  | 
| Santos Cordon | b804f8d | 2015-05-12 12:09:47 -0700 | [diff] [blame] | 464 |     /** | 
 | 465 |      * Puts the conference on hold. | 
 | 466 |      */ | 
| Ihab Awad | b8e85c7 | 2014-08-23 20:34:57 -0700 | [diff] [blame] | 467 |     public void hold() { | 
 | 468 |         try { | 
| Brad Ebinger | b32d4f8 | 2016-10-24 16:40:49 -0700 | [diff] [blame] | 469 |             mConnectionService.hold(mId, null /*Session.Info*/); | 
| Ihab Awad | b8e85c7 | 2014-08-23 20:34:57 -0700 | [diff] [blame] | 470 |         } catch (RemoteException e) { | 
 | 471 |         } | 
 | 472 |     } | 
 | 473 |  | 
| Santos Cordon | b804f8d | 2015-05-12 12:09:47 -0700 | [diff] [blame] | 474 |     /** | 
 | 475 |      * Unholds the conference call. | 
 | 476 |      */ | 
| Ihab Awad | b8e85c7 | 2014-08-23 20:34:57 -0700 | [diff] [blame] | 477 |     public void unhold() { | 
 | 478 |         try { | 
| Brad Ebinger | b32d4f8 | 2016-10-24 16:40:49 -0700 | [diff] [blame] | 479 |             mConnectionService.unhold(mId, null /*Session.Info*/); | 
| Ihab Awad | b8e85c7 | 2014-08-23 20:34:57 -0700 | [diff] [blame] | 480 |         } catch (RemoteException e) { | 
 | 481 |         } | 
 | 482 |     } | 
 | 483 |  | 
| Santos Cordon | b804f8d | 2015-05-12 12:09:47 -0700 | [diff] [blame] | 484 |     /** | 
 | 485 |      * Returns the {@link DisconnectCause} for the conference if it is in the state | 
 | 486 |      * {@link Connection#STATE_DISCONNECTED}. If the conference is not disconnected, this will | 
 | 487 |      * return null. | 
 | 488 |      * | 
 | 489 |      * @return The disconnect cause. | 
 | 490 |      */ | 
| Andrew Lee | 7f3d41f | 2014-09-11 17:33:16 -0700 | [diff] [blame] | 491 |     public DisconnectCause getDisconnectCause() { | 
| Ihab Awad | b8e85c7 | 2014-08-23 20:34:57 -0700 | [diff] [blame] | 492 |         return mDisconnectCause; | 
 | 493 |     } | 
 | 494 |  | 
| Santos Cordon | b804f8d | 2015-05-12 12:09:47 -0700 | [diff] [blame] | 495 |     /** | 
 | 496 |      * Requests that the conference start playing the specified DTMF tone. | 
 | 497 |      * | 
 | 498 |      * @param digit The digit for which to play a DTMF tone. | 
 | 499 |      */ | 
| Yorke Lee | 58bacc5 | 2014-09-16 10:43:06 -0700 | [diff] [blame] | 500 |     public void playDtmfTone(char digit) { | 
 | 501 |         try { | 
| Brad Ebinger | b32d4f8 | 2016-10-24 16:40:49 -0700 | [diff] [blame] | 502 |             mConnectionService.playDtmfTone(mId, digit, null /*Session.Info*/); | 
| Yorke Lee | 58bacc5 | 2014-09-16 10:43:06 -0700 | [diff] [blame] | 503 |         } catch (RemoteException e) { | 
 | 504 |         } | 
 | 505 |     } | 
 | 506 |  | 
| Santos Cordon | b804f8d | 2015-05-12 12:09:47 -0700 | [diff] [blame] | 507 |     /** | 
 | 508 |      * Stops the most recent request to play a DTMF tone. | 
 | 509 |      * | 
 | 510 |      * @see #playDtmfTone | 
 | 511 |      */ | 
| Yorke Lee | 58bacc5 | 2014-09-16 10:43:06 -0700 | [diff] [blame] | 512 |     public void stopDtmfTone() { | 
 | 513 |         try { | 
| Brad Ebinger | b32d4f8 | 2016-10-24 16:40:49 -0700 | [diff] [blame] | 514 |             mConnectionService.stopDtmfTone(mId, null /*Session.Info*/); | 
| Yorke Lee | 58bacc5 | 2014-09-16 10:43:06 -0700 | [diff] [blame] | 515 |         } catch (RemoteException e) { | 
 | 516 |         } | 
 | 517 |     } | 
 | 518 |  | 
| Santos Cordon | b804f8d | 2015-05-12 12:09:47 -0700 | [diff] [blame] | 519 |     /** | 
 | 520 |      * Request to change the conference's audio routing to the specified state. The specified state | 
 | 521 |      * can include audio routing (Bluetooth, Speaker, etc) and muting state. | 
 | 522 |      * | 
 | 523 |      * @see android.telecom.AudioState | 
| Yorke Lee | 4af5935 | 2015-05-13 14:14:54 -0700 | [diff] [blame] | 524 |      * @deprecated Use {@link #setCallAudioState(CallAudioState)} instead. | 
 | 525 |      * @hide | 
| Santos Cordon | b804f8d | 2015-05-12 12:09:47 -0700 | [diff] [blame] | 526 |      */ | 
| Yorke Lee | 4af5935 | 2015-05-13 14:14:54 -0700 | [diff] [blame] | 527 |     @SystemApi | 
 | 528 |     @Deprecated | 
| Yorke Lee | 58bacc5 | 2014-09-16 10:43:06 -0700 | [diff] [blame] | 529 |     public void setAudioState(AudioState state) { | 
| Yorke Lee | 4af5935 | 2015-05-13 14:14:54 -0700 | [diff] [blame] | 530 |         setCallAudioState(new CallAudioState(state)); | 
 | 531 |     } | 
 | 532 |  | 
 | 533 |     /** | 
 | 534 |      * Request to change the conference's audio routing to the specified state. The specified state | 
 | 535 |      * can include audio routing (Bluetooth, Speaker, etc) and muting state. | 
 | 536 |      */ | 
 | 537 |     public void setCallAudioState(CallAudioState state) { | 
| Yorke Lee | 58bacc5 | 2014-09-16 10:43:06 -0700 | [diff] [blame] | 538 |         try { | 
| Brad Ebinger | b32d4f8 | 2016-10-24 16:40:49 -0700 | [diff] [blame] | 539 |             mConnectionService.onCallAudioStateChanged(mId, state, null /*Session.Info*/); | 
| Yorke Lee | 58bacc5 | 2014-09-16 10:43:06 -0700 | [diff] [blame] | 540 |         } catch (RemoteException e) { | 
 | 541 |         } | 
 | 542 |     } | 
 | 543 |  | 
| Yorke Lee | 4af5935 | 2015-05-13 14:14:54 -0700 | [diff] [blame] | 544 |  | 
| Santos Cordon | b804f8d | 2015-05-12 12:09:47 -0700 | [diff] [blame] | 545 |     /** | 
 | 546 |      * Returns a list of independent connections that can me merged with this conference. | 
 | 547 |      * | 
 | 548 |      * @return A list of conferenceable connections. | 
 | 549 |      */ | 
| Ihab Awad | 50e3506 | 2014-09-30 09:17:03 -0700 | [diff] [blame] | 550 |     public List<RemoteConnection> getConferenceableConnections() { | 
 | 551 |         return mUnmodifiableConferenceableConnections; | 
 | 552 |     } | 
 | 553 |  | 
| Santos Cordon | b804f8d | 2015-05-12 12:09:47 -0700 | [diff] [blame] | 554 |     /** | 
 | 555 |      * Register a callback through which to receive state updates for this conference. | 
 | 556 |      * | 
 | 557 |      * @param callback The callback to notify of state changes. | 
 | 558 |      */ | 
| Andrew Lee | 100e293 | 2014-09-08 15:34:24 -0700 | [diff] [blame] | 559 |     public final void registerCallback(Callback callback) { | 
| Andrew Lee | 011728f | 2015-04-23 15:47:06 -0700 | [diff] [blame] | 560 |         registerCallback(callback, new Handler()); | 
 | 561 |     } | 
 | 562 |  | 
| Santos Cordon | b804f8d | 2015-05-12 12:09:47 -0700 | [diff] [blame] | 563 |     /** | 
 | 564 |      * Registers a callback through which to receive state updates for this conference. | 
 | 565 |      * Callbacks will be notified using the specified handler, if provided. | 
 | 566 |      * | 
 | 567 |      * @param callback The callback to notify of state changes. | 
 | 568 |      * @param handler The handler on which to execute the callbacks. | 
 | 569 |      */ | 
| Andrew Lee | 011728f | 2015-04-23 15:47:06 -0700 | [diff] [blame] | 570 |     public final void registerCallback(Callback callback, Handler handler) { | 
 | 571 |         unregisterCallback(callback); | 
 | 572 |         if (callback != null && handler != null) { | 
 | 573 |             mCallbackRecords.add(new CallbackRecord(callback, handler)); | 
 | 574 |         } | 
| Ihab Awad | b8e85c7 | 2014-08-23 20:34:57 -0700 | [diff] [blame] | 575 |     } | 
 | 576 |  | 
| Santos Cordon | b804f8d | 2015-05-12 12:09:47 -0700 | [diff] [blame] | 577 |     /** | 
 | 578 |      * Unregisters a previously registered callback. | 
 | 579 |      * | 
 | 580 |      * @see #registerCallback | 
 | 581 |      * | 
 | 582 |      * @param callback The callback to unregister. | 
 | 583 |      */ | 
| Andrew Lee | 100e293 | 2014-09-08 15:34:24 -0700 | [diff] [blame] | 584 |     public final void unregisterCallback(Callback callback) { | 
| Andrew Lee | 011728f | 2015-04-23 15:47:06 -0700 | [diff] [blame] | 585 |         if (callback != null) { | 
 | 586 |             for (CallbackRecord<Callback> record : mCallbackRecords) { | 
 | 587 |                 if (record.getCallback() == callback) { | 
 | 588 |                     mCallbackRecords.remove(record); | 
 | 589 |                     break; | 
 | 590 |                 } | 
 | 591 |             } | 
 | 592 |         } | 
| Ihab Awad | b8e85c7 | 2014-08-23 20:34:57 -0700 | [diff] [blame] | 593 |     } | 
| Grace Jia | 9a09c67 | 2020-08-04 12:52:09 -0700 | [diff] [blame] | 594 |  | 
 | 595 |     /** | 
 | 596 |      * Create a {@link RemoteConference} represents a failure, and which will | 
 | 597 |      * be in {@link Connection#STATE_DISCONNECTED}. | 
 | 598 |      * | 
 | 599 |      * @param disconnectCause The disconnect cause. | 
 | 600 |      * @return a failed {@link RemoteConference} | 
 | 601 |      * @hide | 
 | 602 |      */ | 
 | 603 |     public static RemoteConference failure(DisconnectCause disconnectCause) { | 
 | 604 |         return new RemoteConference(disconnectCause); | 
 | 605 |     } | 
| Ihab Awad | b8e85c7 | 2014-08-23 20:34:57 -0700 | [diff] [blame] | 606 | } |