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