1 /* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.telecom; 18 19 import android.net.Uri; 20 import android.os.Bundle; 21 import android.os.IBinder.DeathRecipient; 22 import android.os.RemoteException; 23 24 import com.android.internal.telecom.IConnectionServiceAdapter; 25 import com.android.internal.telecom.RemoteServiceCallback; 26 27 import java.util.Collections; 28 import java.util.Iterator; 29 import java.util.List; 30 import java.util.Set; 31 import java.util.concurrent.ConcurrentHashMap; 32 33 /** 34 * Provides methods for IConnectionService implementations to interact with the system phone app. 35 * 36 * @hide 37 */ 38 final class ConnectionServiceAdapter implements DeathRecipient { 39 /** 40 * ConcurrentHashMap constructor params: 8 is initial table size, 0.9f is 41 * load factor before resizing, 1 means we only expect a single thread to 42 * access the map so make only a single shard 43 */ 44 private final Set<IConnectionServiceAdapter> mAdapters = Collections.newSetFromMap( 45 new ConcurrentHashMap<IConnectionServiceAdapter, Boolean>(8, 0.9f, 1)); 46 ConnectionServiceAdapter()47 ConnectionServiceAdapter() { 48 } 49 addAdapter(IConnectionServiceAdapter adapter)50 void addAdapter(IConnectionServiceAdapter adapter) { 51 for (IConnectionServiceAdapter it : mAdapters) { 52 if (it.asBinder() == adapter.asBinder()) { 53 Log.w(this, "Ignoring duplicate adapter addition."); 54 return; 55 } 56 } 57 if (mAdapters.add(adapter)) { 58 try { 59 adapter.asBinder().linkToDeath(this, 0); 60 } catch (RemoteException e) { 61 mAdapters.remove(adapter); 62 } 63 } 64 } 65 removeAdapter(IConnectionServiceAdapter adapter)66 void removeAdapter(IConnectionServiceAdapter adapter) { 67 if (adapter != null) { 68 for (IConnectionServiceAdapter it : mAdapters) { 69 if (it.asBinder() == adapter.asBinder() && mAdapters.remove(it)) { 70 adapter.asBinder().unlinkToDeath(this, 0); 71 break; 72 } 73 } 74 } 75 } 76 77 /** ${inheritDoc} */ 78 @Override binderDied()79 public void binderDied() { 80 Iterator<IConnectionServiceAdapter> it = mAdapters.iterator(); 81 while (it.hasNext()) { 82 IConnectionServiceAdapter adapter = it.next(); 83 if (!adapter.asBinder().isBinderAlive()) { 84 it.remove(); 85 adapter.asBinder().unlinkToDeath(this, 0); 86 } 87 } 88 } 89 handleCreateConnectionComplete( String id, ConnectionRequest request, ParcelableConnection connection)90 void handleCreateConnectionComplete( 91 String id, 92 ConnectionRequest request, 93 ParcelableConnection connection) { 94 for (IConnectionServiceAdapter adapter : mAdapters) { 95 try { 96 adapter.handleCreateConnectionComplete(id, request, connection); 97 } catch (RemoteException e) { 98 } 99 } 100 } 101 102 /** 103 * Sets a call's state to active (e.g., an ongoing call where two parties can actively 104 * communicate). 105 * 106 * @param callId The unique ID of the call whose state is changing to active. 107 */ setActive(String callId)108 void setActive(String callId) { 109 for (IConnectionServiceAdapter adapter : mAdapters) { 110 try { 111 adapter.setActive(callId); 112 } catch (RemoteException e) { 113 } 114 } 115 } 116 117 /** 118 * Sets a call's state to ringing (e.g., an inbound ringing call). 119 * 120 * @param callId The unique ID of the call whose state is changing to ringing. 121 */ setRinging(String callId)122 void setRinging(String callId) { 123 for (IConnectionServiceAdapter adapter : mAdapters) { 124 try { 125 adapter.setRinging(callId); 126 } catch (RemoteException e) { 127 } 128 } 129 } 130 131 /** 132 * Sets a call's state to dialing (e.g., dialing an outbound call). 133 * 134 * @param callId The unique ID of the call whose state is changing to dialing. 135 */ setDialing(String callId)136 void setDialing(String callId) { 137 for (IConnectionServiceAdapter adapter : mAdapters) { 138 try { 139 adapter.setDialing(callId); 140 } catch (RemoteException e) { 141 } 142 } 143 } 144 145 /** 146 * Sets a call's state to disconnected. 147 * 148 * @param callId The unique ID of the call whose state is changing to disconnected. 149 * @param disconnectCause The reason for the disconnection, as described by 150 * {@link android.telecomm.DisconnectCause}. 151 */ setDisconnected(String callId, DisconnectCause disconnectCause)152 void setDisconnected(String callId, DisconnectCause disconnectCause) { 153 for (IConnectionServiceAdapter adapter : mAdapters) { 154 try { 155 adapter.setDisconnected(callId, disconnectCause); 156 } catch (RemoteException e) { 157 } 158 } 159 } 160 161 /** 162 * Sets a call's state to be on hold. 163 * 164 * @param callId - The unique ID of the call whose state is changing to be on hold. 165 */ setOnHold(String callId)166 void setOnHold(String callId) { 167 for (IConnectionServiceAdapter adapter : mAdapters) { 168 try { 169 adapter.setOnHold(callId); 170 } catch (RemoteException e) { 171 } 172 } 173 } 174 175 /** 176 * Asks Telecom to start or stop a ringback tone for a call. 177 * 178 * @param callId The unique ID of the call whose ringback is being changed. 179 * @param ringback Whether Telecom should start playing a ringback tone. 180 */ setRingbackRequested(String callId, boolean ringback)181 void setRingbackRequested(String callId, boolean ringback) { 182 for (IConnectionServiceAdapter adapter : mAdapters) { 183 try { 184 adapter.setRingbackRequested(callId, ringback); 185 } catch (RemoteException e) { 186 } 187 } 188 } 189 setConnectionCapabilities(String callId, int capabilities)190 void setConnectionCapabilities(String callId, int capabilities) { 191 for (IConnectionServiceAdapter adapter : mAdapters) { 192 try { 193 adapter.setConnectionCapabilities(callId, capabilities); 194 } catch (RemoteException ignored) { 195 } 196 } 197 } 198 199 /** 200 * Indicates whether or not the specified call is currently conferenced into the specified 201 * conference call. 202 * 203 * @param callId The unique ID of the call being conferenced. 204 * @param conferenceCallId The unique ID of the conference call. Null if call is not 205 * conferenced. 206 */ setIsConferenced(String callId, String conferenceCallId)207 void setIsConferenced(String callId, String conferenceCallId) { 208 for (IConnectionServiceAdapter adapter : mAdapters) { 209 try { 210 Log.d(this, "sending connection %s with conference %s", callId, conferenceCallId); 211 adapter.setIsConferenced(callId, conferenceCallId); 212 } catch (RemoteException ignored) { 213 } 214 } 215 } 216 217 /** 218 * Indicates that the merge request on this call has failed. 219 * 220 * @param callId The unique ID of the call being conferenced. 221 */ onConferenceMergeFailed(String callId)222 void onConferenceMergeFailed(String callId) { 223 for (IConnectionServiceAdapter adapter : mAdapters) { 224 try { 225 Log.d(this, "merge failed for call %s", callId); 226 adapter.setConferenceMergeFailed(callId); 227 } catch (RemoteException ignored) { 228 } 229 } 230 } 231 232 /** 233 * Indicates that the call no longer exists. Can be used with either a call or a conference 234 * call. 235 * 236 * @param callId The unique ID of the call. 237 */ removeCall(String callId)238 void removeCall(String callId) { 239 for (IConnectionServiceAdapter adapter : mAdapters) { 240 try { 241 adapter.removeCall(callId); 242 } catch (RemoteException ignored) { 243 } 244 } 245 } 246 onPostDialWait(String callId, String remaining)247 void onPostDialWait(String callId, String remaining) { 248 for (IConnectionServiceAdapter adapter : mAdapters) { 249 try { 250 adapter.onPostDialWait(callId, remaining); 251 } catch (RemoteException ignored) { 252 } 253 } 254 } 255 onPostDialChar(String callId, char nextChar)256 void onPostDialChar(String callId, char nextChar) { 257 for (IConnectionServiceAdapter adapter : mAdapters) { 258 try { 259 adapter.onPostDialChar(callId, nextChar); 260 } catch (RemoteException ignored) { 261 } 262 } 263 } 264 265 /** 266 * Indicates that a new conference call has been created. 267 * 268 * @param callId The unique ID of the conference call. 269 */ addConferenceCall(String callId, ParcelableConference parcelableConference)270 void addConferenceCall(String callId, ParcelableConference parcelableConference) { 271 for (IConnectionServiceAdapter adapter : mAdapters) { 272 try { 273 adapter.addConferenceCall(callId, parcelableConference); 274 } catch (RemoteException ignored) { 275 } 276 } 277 } 278 279 /** 280 * Retrieves a list of remote connection services usable to place calls. 281 */ queryRemoteConnectionServices(RemoteServiceCallback callback)282 void queryRemoteConnectionServices(RemoteServiceCallback callback) { 283 // Only supported when there is only one adapter. 284 if (mAdapters.size() == 1) { 285 try { 286 mAdapters.iterator().next().queryRemoteConnectionServices(callback); 287 } catch (RemoteException e) { 288 Log.e(this, e, "Exception trying to query for remote CSs"); 289 } 290 } 291 } 292 293 /** 294 * Sets the call video provider for a call. 295 * 296 * @param callId The unique ID of the call to set with the given call video provider. 297 * @param videoProvider The call video provider instance to set on the call. 298 */ setVideoProvider( String callId, Connection.VideoProvider videoProvider)299 void setVideoProvider( 300 String callId, Connection.VideoProvider videoProvider) { 301 for (IConnectionServiceAdapter adapter : mAdapters) { 302 try { 303 adapter.setVideoProvider( 304 callId, 305 videoProvider == null ? null : videoProvider.getInterface()); 306 } catch (RemoteException e) { 307 } 308 } 309 } 310 311 /** 312 * Requests that the framework use VOIP audio mode for this connection. 313 * 314 * @param callId The unique ID of the call to set with the given call video provider. 315 * @param isVoip True if the audio mode is VOIP. 316 */ setIsVoipAudioMode(String callId, boolean isVoip)317 void setIsVoipAudioMode(String callId, boolean isVoip) { 318 for (IConnectionServiceAdapter adapter : mAdapters) { 319 try { 320 adapter.setIsVoipAudioMode(callId, isVoip); 321 } catch (RemoteException e) { 322 } 323 } 324 } 325 setStatusHints(String callId, StatusHints statusHints)326 void setStatusHints(String callId, StatusHints statusHints) { 327 for (IConnectionServiceAdapter adapter : mAdapters) { 328 try { 329 adapter.setStatusHints(callId, statusHints); 330 } catch (RemoteException e) { 331 } 332 } 333 } 334 setAddress(String callId, Uri address, int presentation)335 void setAddress(String callId, Uri address, int presentation) { 336 for (IConnectionServiceAdapter adapter : mAdapters) { 337 try { 338 adapter.setAddress(callId, address, presentation); 339 } catch (RemoteException e) { 340 } 341 } 342 } 343 setCallerDisplayName(String callId, String callerDisplayName, int presentation)344 void setCallerDisplayName(String callId, String callerDisplayName, int presentation) { 345 for (IConnectionServiceAdapter adapter : mAdapters) { 346 try { 347 adapter.setCallerDisplayName(callId, callerDisplayName, presentation); 348 } catch (RemoteException e) { 349 } 350 } 351 } 352 353 /** 354 * Sets the video state associated with a call. 355 * 356 * Valid values: {@link VideoProfile#STATE_BIDIRECTIONAL}, 357 * {@link VideoProfile#STATE_AUDIO_ONLY}, 358 * {@link VideoProfile#STATE_TX_ENABLED}, 359 * {@link VideoProfile#STATE_RX_ENABLED}. 360 * 361 * @param callId The unique ID of the call to set the video state for. 362 * @param videoState The video state. 363 */ setVideoState(String callId, int videoState)364 void setVideoState(String callId, int videoState) { 365 Log.v(this, "setVideoState: %d", videoState); 366 for (IConnectionServiceAdapter adapter : mAdapters) { 367 try { 368 adapter.setVideoState(callId, videoState); 369 } catch (RemoteException ignored) { 370 } 371 } 372 } 373 setConferenceableConnections(String callId, List<String> conferenceableCallIds)374 void setConferenceableConnections(String callId, List<String> conferenceableCallIds) { 375 Log.v(this, "setConferenceableConnections: %s, %s", callId, conferenceableCallIds); 376 for (IConnectionServiceAdapter adapter : mAdapters) { 377 try { 378 adapter.setConferenceableConnections(callId, conferenceableCallIds); 379 } catch (RemoteException ignored) { 380 } 381 } 382 } 383 384 /** 385 * Informs telecom of an existing connection which was added by the {@link ConnectionService}. 386 * 387 * @param callId The unique ID of the call being added. 388 * @param connection The connection. 389 */ addExistingConnection(String callId, ParcelableConnection connection)390 void addExistingConnection(String callId, ParcelableConnection connection) { 391 Log.v(this, "addExistingConnection: %s", callId); 392 for (IConnectionServiceAdapter adapter : mAdapters) { 393 try { 394 adapter.addExistingConnection(callId, connection); 395 } catch (RemoteException ignored) { 396 } 397 } 398 } 399 400 /** 401 * Sets extras associated with a connection. 402 * 403 * @param callId The unique ID of the call. 404 * @param extras The extras to associate with this call. 405 */ setExtras(String callId, Bundle extras)406 void setExtras(String callId, Bundle extras) { 407 Log.v(this, "setExtras: %s", extras); 408 for (IConnectionServiceAdapter adapter : mAdapters) { 409 try { 410 adapter.setExtras(callId, extras); 411 } catch (RemoteException ignored) { 412 } 413 } 414 } 415 } 416