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 pulling (e.g. a call with {@link Connection#PROPERTY_IS_EXTERNAL_CALL} 147 * is being pulled to the local device. 148 * 149 * @param callId The unique ID of the call whose state is changing to dialing. 150 */ setPulling(String callId)151 void setPulling(String callId) { 152 for (IConnectionServiceAdapter adapter : mAdapters) { 153 try { 154 adapter.setPulling(callId); 155 } catch (RemoteException e) { 156 } 157 } 158 } 159 160 /** 161 * Sets a call's state to disconnected. 162 * 163 * @param callId The unique ID of the call whose state is changing to disconnected. 164 * @param disconnectCause The reason for the disconnection, as described by 165 * {@link android.telecomm.DisconnectCause}. 166 */ setDisconnected(String callId, DisconnectCause disconnectCause)167 void setDisconnected(String callId, DisconnectCause disconnectCause) { 168 for (IConnectionServiceAdapter adapter : mAdapters) { 169 try { 170 adapter.setDisconnected(callId, disconnectCause); 171 } catch (RemoteException e) { 172 } 173 } 174 } 175 176 /** 177 * Sets a call's state to be on hold. 178 * 179 * @param callId - The unique ID of the call whose state is changing to be on hold. 180 */ setOnHold(String callId)181 void setOnHold(String callId) { 182 for (IConnectionServiceAdapter adapter : mAdapters) { 183 try { 184 adapter.setOnHold(callId); 185 } catch (RemoteException e) { 186 } 187 } 188 } 189 190 /** 191 * Asks Telecom to start or stop a ringback tone for a call. 192 * 193 * @param callId The unique ID of the call whose ringback is being changed. 194 * @param ringback Whether Telecom should start playing a ringback tone. 195 */ setRingbackRequested(String callId, boolean ringback)196 void setRingbackRequested(String callId, boolean ringback) { 197 for (IConnectionServiceAdapter adapter : mAdapters) { 198 try { 199 adapter.setRingbackRequested(callId, ringback); 200 } catch (RemoteException e) { 201 } 202 } 203 } 204 setConnectionCapabilities(String callId, int capabilities)205 void setConnectionCapabilities(String callId, int capabilities) { 206 for (IConnectionServiceAdapter adapter : mAdapters) { 207 try { 208 adapter.setConnectionCapabilities(callId, capabilities); 209 } catch (RemoteException ignored) { 210 } 211 } 212 } 213 setConnectionProperties(String callId, int properties)214 void setConnectionProperties(String callId, int properties) { 215 for (IConnectionServiceAdapter adapter : mAdapters) { 216 try { 217 adapter.setConnectionProperties(callId, properties); 218 } catch (RemoteException ignored) { 219 } 220 } 221 } 222 223 /** 224 * Indicates whether or not the specified call is currently conferenced into the specified 225 * conference call. 226 * 227 * @param callId The unique ID of the call being conferenced. 228 * @param conferenceCallId The unique ID of the conference call. Null if call is not 229 * conferenced. 230 */ setIsConferenced(String callId, String conferenceCallId)231 void setIsConferenced(String callId, String conferenceCallId) { 232 for (IConnectionServiceAdapter adapter : mAdapters) { 233 try { 234 Log.d(this, "sending connection %s with conference %s", callId, conferenceCallId); 235 adapter.setIsConferenced(callId, conferenceCallId); 236 } catch (RemoteException ignored) { 237 } 238 } 239 } 240 241 /** 242 * Indicates that the merge request on this call has failed. 243 * 244 * @param callId The unique ID of the call being conferenced. 245 */ onConferenceMergeFailed(String callId)246 void onConferenceMergeFailed(String callId) { 247 for (IConnectionServiceAdapter adapter : mAdapters) { 248 try { 249 Log.d(this, "merge failed for call %s", callId); 250 adapter.setConferenceMergeFailed(callId); 251 } catch (RemoteException ignored) { 252 } 253 } 254 } 255 256 /** 257 * Indicates that the call no longer exists. Can be used with either a call or a conference 258 * call. 259 * 260 * @param callId The unique ID of the call. 261 */ removeCall(String callId)262 void removeCall(String callId) { 263 for (IConnectionServiceAdapter adapter : mAdapters) { 264 try { 265 adapter.removeCall(callId); 266 } catch (RemoteException ignored) { 267 } 268 } 269 } 270 onPostDialWait(String callId, String remaining)271 void onPostDialWait(String callId, String remaining) { 272 for (IConnectionServiceAdapter adapter : mAdapters) { 273 try { 274 adapter.onPostDialWait(callId, remaining); 275 } catch (RemoteException ignored) { 276 } 277 } 278 } 279 onPostDialChar(String callId, char nextChar)280 void onPostDialChar(String callId, char nextChar) { 281 for (IConnectionServiceAdapter adapter : mAdapters) { 282 try { 283 adapter.onPostDialChar(callId, nextChar); 284 } catch (RemoteException ignored) { 285 } 286 } 287 } 288 289 /** 290 * Indicates that a new conference call has been created. 291 * 292 * @param callId The unique ID of the conference call. 293 */ addConferenceCall(String callId, ParcelableConference parcelableConference)294 void addConferenceCall(String callId, ParcelableConference parcelableConference) { 295 for (IConnectionServiceAdapter adapter : mAdapters) { 296 try { 297 adapter.addConferenceCall(callId, parcelableConference); 298 } catch (RemoteException ignored) { 299 } 300 } 301 } 302 303 /** 304 * Retrieves a list of remote connection services usable to place calls. 305 */ queryRemoteConnectionServices(RemoteServiceCallback callback)306 void queryRemoteConnectionServices(RemoteServiceCallback callback) { 307 // Only supported when there is only one adapter. 308 if (mAdapters.size() == 1) { 309 try { 310 mAdapters.iterator().next().queryRemoteConnectionServices(callback); 311 } catch (RemoteException e) { 312 Log.e(this, e, "Exception trying to query for remote CSs"); 313 } 314 } 315 } 316 317 /** 318 * Sets the call video provider for a call. 319 * 320 * @param callId The unique ID of the call to set with the given call video provider. 321 * @param videoProvider The call video provider instance to set on the call. 322 */ setVideoProvider( String callId, Connection.VideoProvider videoProvider)323 void setVideoProvider( 324 String callId, Connection.VideoProvider videoProvider) { 325 for (IConnectionServiceAdapter adapter : mAdapters) { 326 try { 327 adapter.setVideoProvider( 328 callId, 329 videoProvider == null ? null : videoProvider.getInterface()); 330 } catch (RemoteException e) { 331 } 332 } 333 } 334 335 /** 336 * Requests that the framework use VOIP audio mode for this connection. 337 * 338 * @param callId The unique ID of the call to set with the given call video provider. 339 * @param isVoip True if the audio mode is VOIP. 340 */ setIsVoipAudioMode(String callId, boolean isVoip)341 void setIsVoipAudioMode(String callId, boolean isVoip) { 342 for (IConnectionServiceAdapter adapter : mAdapters) { 343 try { 344 adapter.setIsVoipAudioMode(callId, isVoip); 345 } catch (RemoteException e) { 346 } 347 } 348 } 349 setStatusHints(String callId, StatusHints statusHints)350 void setStatusHints(String callId, StatusHints statusHints) { 351 for (IConnectionServiceAdapter adapter : mAdapters) { 352 try { 353 adapter.setStatusHints(callId, statusHints); 354 } catch (RemoteException e) { 355 } 356 } 357 } 358 setAddress(String callId, Uri address, int presentation)359 void setAddress(String callId, Uri address, int presentation) { 360 for (IConnectionServiceAdapter adapter : mAdapters) { 361 try { 362 adapter.setAddress(callId, address, presentation); 363 } catch (RemoteException e) { 364 } 365 } 366 } 367 setCallerDisplayName(String callId, String callerDisplayName, int presentation)368 void setCallerDisplayName(String callId, String callerDisplayName, int presentation) { 369 for (IConnectionServiceAdapter adapter : mAdapters) { 370 try { 371 adapter.setCallerDisplayName(callId, callerDisplayName, presentation); 372 } catch (RemoteException e) { 373 } 374 } 375 } 376 377 /** 378 * Sets the video state associated with a call. 379 * 380 * Valid values: {@link VideoProfile#STATE_BIDIRECTIONAL}, 381 * {@link VideoProfile#STATE_AUDIO_ONLY}, 382 * {@link VideoProfile#STATE_TX_ENABLED}, 383 * {@link VideoProfile#STATE_RX_ENABLED}. 384 * 385 * @param callId The unique ID of the call to set the video state for. 386 * @param videoState The video state. 387 */ setVideoState(String callId, int videoState)388 void setVideoState(String callId, int videoState) { 389 Log.v(this, "setVideoState: %d", videoState); 390 for (IConnectionServiceAdapter adapter : mAdapters) { 391 try { 392 adapter.setVideoState(callId, videoState); 393 } catch (RemoteException ignored) { 394 } 395 } 396 } 397 setConferenceableConnections(String callId, List<String> conferenceableCallIds)398 void setConferenceableConnections(String callId, List<String> conferenceableCallIds) { 399 Log.v(this, "setConferenceableConnections: %s, %s", callId, conferenceableCallIds); 400 for (IConnectionServiceAdapter adapter : mAdapters) { 401 try { 402 adapter.setConferenceableConnections(callId, conferenceableCallIds); 403 } catch (RemoteException ignored) { 404 } 405 } 406 } 407 408 /** 409 * Informs telecom of an existing connection which was added by the {@link ConnectionService}. 410 * 411 * @param callId The unique ID of the call being added. 412 * @param connection The connection. 413 */ addExistingConnection(String callId, ParcelableConnection connection)414 void addExistingConnection(String callId, ParcelableConnection connection) { 415 Log.v(this, "addExistingConnection: %s", callId); 416 for (IConnectionServiceAdapter adapter : mAdapters) { 417 try { 418 adapter.addExistingConnection(callId, connection); 419 } catch (RemoteException ignored) { 420 } 421 } 422 } 423 424 /** 425 * Adds some extras associated with a {@code Connection}. 426 * 427 * @param callId The unique ID of the call. 428 * @param extras The extras to add. 429 */ putExtras(String callId, Bundle extras)430 void putExtras(String callId, Bundle extras) { 431 Log.v(this, "putExtras: %s", callId); 432 for (IConnectionServiceAdapter adapter : mAdapters) { 433 try { 434 adapter.putExtras(callId, extras); 435 } catch (RemoteException ignored) { 436 } 437 } 438 } 439 440 /** 441 * Adds an extra associated with a {@code Connection}. 442 * 443 * @param callId The unique ID of the call. 444 * @param key The extra key. 445 * @param value The extra value. 446 */ putExtra(String callId, String key, boolean value)447 void putExtra(String callId, String key, boolean value) { 448 Log.v(this, "putExtra: %s %s=%b", callId, key, value); 449 for (IConnectionServiceAdapter adapter : mAdapters) { 450 try { 451 Bundle bundle = new Bundle(); 452 bundle.putBoolean(key, value); 453 adapter.putExtras(callId, bundle); 454 } catch (RemoteException ignored) { 455 } 456 } 457 } 458 459 /** 460 * Adds an extra associated with a {@code Connection}. 461 * 462 * @param callId The unique ID of the call. 463 * @param key The extra key. 464 * @param value The extra value. 465 */ putExtra(String callId, String key, int value)466 void putExtra(String callId, String key, int value) { 467 Log.v(this, "putExtra: %s %s=%d", callId, key, value); 468 for (IConnectionServiceAdapter adapter : mAdapters) { 469 try { 470 Bundle bundle = new Bundle(); 471 bundle.putInt(key, value); 472 adapter.putExtras(callId, bundle); 473 } catch (RemoteException ignored) { 474 } 475 } 476 } 477 478 /** 479 * Adds an extra associated with a {@code Connection}. 480 * 481 * @param callId The unique ID of the call. 482 * @param key The extra key. 483 * @param value The extra value. 484 */ putExtra(String callId, String key, String value)485 void putExtra(String callId, String key, String value) { 486 Log.v(this, "putExtra: %s %s=%s", callId, key, value); 487 for (IConnectionServiceAdapter adapter : mAdapters) { 488 try { 489 Bundle bundle = new Bundle(); 490 bundle.putString(key, value); 491 adapter.putExtras(callId, bundle); 492 } catch (RemoteException ignored) { 493 } 494 } 495 } 496 497 /** 498 * Removes extras associated with a {@code Connection}. 499 * @param callId The unique ID of the call. 500 * @param keys The extra keys to remove. 501 */ removeExtras(String callId, List<String> keys)502 void removeExtras(String callId, List<String> keys) { 503 Log.v(this, "removeExtras: %s %s", callId, keys); 504 for (IConnectionServiceAdapter adapter : mAdapters) { 505 try { 506 adapter.removeExtras(callId, keys); 507 } catch (RemoteException ignored) { 508 } 509 } 510 } 511 512 /** 513 * Informs Telecom of a connection level event. 514 * 515 * @param callId The unique ID of the call. 516 * @param event The event. 517 * @param extras Extras associated with the event. 518 */ onConnectionEvent(String callId, String event, Bundle extras)519 void onConnectionEvent(String callId, String event, Bundle extras) { 520 Log.v(this, "onConnectionEvent: %s", event); 521 for (IConnectionServiceAdapter adapter : mAdapters) { 522 try { 523 adapter.onConnectionEvent(callId, event, extras); 524 } catch (RemoteException ignored) { 525 } 526 } 527 } 528 } 529