1 /* 2 * Copyright (C) 2017 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.telephony.ims.stub; 18 19 import android.annotation.NonNull; 20 import android.annotation.SystemApi; 21 import android.annotation.TestApi; 22 import android.os.Message; 23 import android.os.RemoteException; 24 import android.telephony.ims.ImsCallProfile; 25 import android.telephony.ims.ImsCallSession; 26 import android.telephony.ims.ImsCallSessionListener; 27 import android.telephony.ims.ImsReasonInfo; 28 import android.telephony.ims.ImsStreamMediaProfile; 29 import android.telephony.ims.ImsVideoCallProvider; 30 import android.telephony.ims.aidl.IImsCallSessionListener; 31 32 import com.android.ims.internal.IImsCallSession; 33 import com.android.ims.internal.IImsVideoCallProvider; 34 /** 35 * Base implementation of IImsCallSession, which implements stub versions of the methods available. 36 * 37 * Override the methods that your implementation of ImsCallSession supports. 38 * 39 * @hide 40 */ 41 @SystemApi 42 @TestApi 43 // DO NOT remove or change the existing APIs, only add new ones to this Base implementation or you 44 // will break other implementations of ImsCallSession maintained by other ImsServices. 45 public class ImsCallSessionImplBase implements AutoCloseable { 46 /** 47 * Notify USSD Mode. 48 */ 49 public static final int USSD_MODE_NOTIFY = 0; 50 /** 51 * Request USSD Mode 52 */ 53 public static final int USSD_MODE_REQUEST = 1; 54 55 /** 56 * Defines IMS call session state. 57 */ 58 public static class State { 59 public static final int IDLE = 0; 60 public static final int INITIATED = 1; 61 public static final int NEGOTIATING = 2; 62 public static final int ESTABLISHING = 3; 63 public static final int ESTABLISHED = 4; 64 65 public static final int RENEGOTIATING = 5; 66 public static final int REESTABLISHING = 6; 67 68 public static final int TERMINATING = 7; 69 public static final int TERMINATED = 8; 70 71 public static final int INVALID = (-1); 72 73 /** 74 * Converts the state to string. 75 */ toString(int state)76 public static String toString(int state) { 77 switch (state) { 78 case IDLE: 79 return "IDLE"; 80 case INITIATED: 81 return "INITIATED"; 82 case NEGOTIATING: 83 return "NEGOTIATING"; 84 case ESTABLISHING: 85 return "ESTABLISHING"; 86 case ESTABLISHED: 87 return "ESTABLISHED"; 88 case RENEGOTIATING: 89 return "RENEGOTIATING"; 90 case REESTABLISHING: 91 return "REESTABLISHING"; 92 case TERMINATING: 93 return "TERMINATING"; 94 case TERMINATED: 95 return "TERMINATED"; 96 default: 97 return "UNKNOWN"; 98 } 99 } 100 101 /** 102 * @hide 103 */ State()104 private State() { 105 } 106 } 107 108 // Non-final for injection by tests 109 private IImsCallSession mServiceImpl = new IImsCallSession.Stub() { 110 @Override 111 public void close() { 112 ImsCallSessionImplBase.this.close(); 113 } 114 115 @Override 116 public String getCallId() { 117 return ImsCallSessionImplBase.this.getCallId(); 118 } 119 120 @Override 121 public ImsCallProfile getCallProfile() { 122 return ImsCallSessionImplBase.this.getCallProfile(); 123 } 124 125 @Override 126 public ImsCallProfile getLocalCallProfile() { 127 return ImsCallSessionImplBase.this.getLocalCallProfile(); 128 } 129 130 @Override 131 public ImsCallProfile getRemoteCallProfile() { 132 return ImsCallSessionImplBase.this.getRemoteCallProfile(); 133 } 134 135 @Override 136 public String getProperty(String name) { 137 return ImsCallSessionImplBase.this.getProperty(name); 138 } 139 140 @Override 141 public int getState() { 142 return ImsCallSessionImplBase.this.getState(); 143 } 144 145 @Override 146 public boolean isInCall() { 147 return ImsCallSessionImplBase.this.isInCall(); 148 } 149 150 @Override 151 public void setListener(IImsCallSessionListener listener) { 152 ImsCallSessionImplBase.this.setListener(new ImsCallSessionListener(listener)); 153 } 154 155 @Override 156 public void setMute(boolean muted) { 157 ImsCallSessionImplBase.this.setMute(muted); 158 } 159 160 @Override 161 public void start(String callee, ImsCallProfile profile) { 162 ImsCallSessionImplBase.this.start(callee, profile); 163 } 164 165 @Override 166 public void startConference(String[] participants, ImsCallProfile profile) throws 167 RemoteException { 168 ImsCallSessionImplBase.this.startConference(participants, profile); 169 } 170 171 @Override 172 public void accept(int callType, ImsStreamMediaProfile profile) { 173 ImsCallSessionImplBase.this.accept(callType, profile); 174 } 175 176 @Override 177 public void deflect(String deflectNumber) { 178 ImsCallSessionImplBase.this.deflect(deflectNumber); 179 } 180 181 @Override 182 public void reject(int reason) { 183 ImsCallSessionImplBase.this.reject(reason); 184 } 185 186 @Override 187 public void transfer(@NonNull String number, boolean isConfirmationRequired) { 188 ImsCallSessionImplBase.this.transfer(number, isConfirmationRequired); 189 } 190 191 @Override 192 public void consultativeTransfer(@NonNull IImsCallSession transferToSession) { 193 ImsCallSessionImplBase otherSession = new ImsCallSessionImplBase(); 194 otherSession.setServiceImpl(transferToSession); 195 ImsCallSessionImplBase.this.transfer(otherSession); 196 } 197 198 @Override 199 public void terminate(int reason) { 200 ImsCallSessionImplBase.this.terminate(reason); 201 } 202 203 @Override 204 public void hold(ImsStreamMediaProfile profile) { 205 ImsCallSessionImplBase.this.hold(profile); 206 } 207 208 @Override 209 public void resume(ImsStreamMediaProfile profile) { 210 ImsCallSessionImplBase.this.resume(profile); 211 } 212 213 @Override 214 public void merge() { 215 ImsCallSessionImplBase.this.merge(); 216 } 217 218 @Override 219 public void update(int callType, ImsStreamMediaProfile profile) { 220 ImsCallSessionImplBase.this.update(callType, profile); 221 } 222 223 @Override 224 public void extendToConference(String[] participants) { 225 ImsCallSessionImplBase.this.extendToConference(participants); 226 } 227 228 @Override 229 public void inviteParticipants(String[] participants) { 230 ImsCallSessionImplBase.this.inviteParticipants(participants); 231 } 232 233 @Override 234 public void removeParticipants(String[] participants) { 235 ImsCallSessionImplBase.this.removeParticipants(participants); 236 } 237 238 @Override 239 public void sendDtmf(char c, Message result) { 240 ImsCallSessionImplBase.this.sendDtmf(c, result); 241 } 242 243 @Override 244 public void startDtmf(char c) { 245 ImsCallSessionImplBase.this.startDtmf(c); 246 } 247 248 @Override 249 public void stopDtmf() { 250 ImsCallSessionImplBase.this.stopDtmf(); 251 } 252 253 @Override 254 public void sendUssd(String ussdMessage) { 255 ImsCallSessionImplBase.this.sendUssd(ussdMessage); 256 } 257 258 @Override 259 public IImsVideoCallProvider getVideoCallProvider() { 260 return ImsCallSessionImplBase.this.getVideoCallProvider(); 261 } 262 263 @Override 264 public boolean isMultiparty() { 265 return ImsCallSessionImplBase.this.isMultiparty(); 266 } 267 268 @Override 269 public void sendRttModifyRequest(ImsCallProfile toProfile) { 270 ImsCallSessionImplBase.this.sendRttModifyRequest(toProfile); 271 } 272 273 @Override 274 public void sendRttModifyResponse(boolean status) { 275 ImsCallSessionImplBase.this.sendRttModifyResponse(status); 276 } 277 278 @Override 279 public void sendRttMessage(String rttMessage) { 280 ImsCallSessionImplBase.this.sendRttMessage(rttMessage); 281 } 282 }; 283 284 /** 285 * @hide 286 */ setListener(IImsCallSessionListener listener)287 public final void setListener(IImsCallSessionListener listener) throws RemoteException { 288 setListener(new ImsCallSessionListener(listener)); 289 } 290 291 /** 292 * Sets the listener to listen to the session events. An {@link ImsCallSession} 293 * can only hold one listener at a time. Subsequent calls to this method 294 * override the previous listener. 295 * 296 * @param listener {@link ImsCallSessionListener} used to notify the framework of updates 297 * to the ImsCallSession 298 */ setListener(ImsCallSessionListener listener)299 public void setListener(ImsCallSessionListener listener) { 300 } 301 302 /** 303 * Closes the object. This {@link ImsCallSessionImplBase} is not usable after being closed. 304 */ 305 @Override close()306 public void close() { 307 308 } 309 310 /** 311 * @return A String containing the unique call ID of this {@link ImsCallSessionImplBase}. 312 */ getCallId()313 public String getCallId() { 314 return null; 315 } 316 317 /** 318 * @return The {@link ImsCallProfile} that this {@link ImsCallSessionImplBase} is associated 319 * with. 320 */ getCallProfile()321 public ImsCallProfile getCallProfile() { 322 return null; 323 } 324 325 /** 326 * @return The local {@link ImsCallProfile} that this {@link ImsCallSessionImplBase} is 327 * associated with. 328 */ getLocalCallProfile()329 public ImsCallProfile getLocalCallProfile() { 330 return null; 331 } 332 333 /** 334 * @return The remote {@link ImsCallProfile} that this {@link ImsCallSessionImplBase} is 335 * associated with. 336 */ getRemoteCallProfile()337 public ImsCallProfile getRemoteCallProfile() { 338 return null; 339 } 340 341 /** 342 * @param name The String extra key. 343 * @return The string extra value associated with the specified property. 344 */ getProperty(String name)345 public String getProperty(String name) { 346 return null; 347 } 348 349 /** 350 * @return The {@link ImsCallSessionImplBase} state, defined in 351 * {@link ImsCallSessionImplBase.State}. 352 */ getState()353 public int getState() { 354 return ImsCallSessionImplBase.State.INVALID; 355 } 356 357 /** 358 * @return true if the {@link ImsCallSessionImplBase} is in a call, false otherwise. 359 */ isInCall()360 public boolean isInCall() { 361 return false; 362 } 363 364 /** 365 * Mutes or unmutes the mic for the active call. 366 * 367 * @param muted true if the call should be muted, false otherwise. 368 */ setMute(boolean muted)369 public void setMute(boolean muted) { 370 } 371 372 /** 373 * Initiates an IMS call with the specified number and call profile. 374 * The session listener set in {@link #setListener(ImsCallSessionListener)} is called back upon 375 * defined session events. 376 * Only valid to call when the session state is in 377 * {@link ImsCallSession.State#IDLE}. 378 * 379 * @param callee dialed string to make the call to 380 * @param profile call profile to make the call with the specified service type, 381 * call type and media information 382 * @see {@link ImsCallSession.Listener#callSessionStarted}, 383 * {@link ImsCallSession.Listener#callSessionStartFailed} 384 */ start(String callee, ImsCallProfile profile)385 public void start(String callee, ImsCallProfile profile) { 386 } 387 388 /** 389 * Initiates an IMS call with the specified participants and call profile. 390 * The session listener set in {@link #setListener(ImsCallSessionListener)} is called back upon 391 * defined session events. 392 * The method is only valid to call when the session state is in 393 * {@link ImsCallSession.State#IDLE}. 394 * 395 * @param participants participant list to initiate an IMS conference call 396 * @param profile call profile to make the call with the specified service type, 397 * call type and media information 398 * @see {@link ImsCallSession.Listener#callSessionStarted}, 399 * {@link ImsCallSession.Listener#callSessionStartFailed} 400 */ startConference(String[] participants, ImsCallProfile profile)401 public void startConference(String[] participants, ImsCallProfile profile) { 402 } 403 404 /** 405 * Accepts an incoming call or session update. 406 * 407 * @param callType call type specified in {@link ImsCallProfile} to be answered 408 * @param profile stream media profile {@link ImsStreamMediaProfile} to be answered 409 * @see {@link ImsCallSession.Listener#callSessionStarted} 410 */ accept(int callType, ImsStreamMediaProfile profile)411 public void accept(int callType, ImsStreamMediaProfile profile) { 412 } 413 414 /** 415 * Deflects an incoming call. 416 * 417 * @param deflectNumber number to deflect the call 418 */ deflect(String deflectNumber)419 public void deflect(String deflectNumber) { 420 } 421 422 /** 423 * Rejects an incoming call or session update. 424 * 425 * @param reason reason code to reject an incoming call, defined in {@link ImsReasonInfo}. 426 * The {@link android.telecom.InCallService} (dialer app) can use the 427 * {@link android.telecom.Call#reject(int)} API to reject a call while specifying 428 * a user-indicated reason for rejecting the call. 429 * Normal call declines ({@link android.telecom.Call#REJECT_REASON_DECLINED}) will 430 * map to {@link ImsReasonInfo#CODE_USER_DECLINE}. 431 * Unwanted calls ({@link android.telecom.Call#REJECT_REASON_UNWANTED}) will map 432 * to {@link ImsReasonInfo#CODE_SIP_USER_MARKED_UNWANTED}. 433 * {@link ImsCallSession.Listener#callSessionStartFailed} 434 */ reject(int reason)435 public void reject(int reason) { 436 } 437 438 /** 439 * Transfer an established call to given number 440 * 441 * @param number number to transfer the call 442 * @param isConfirmationRequired if {@code True}, indicates Assured transfer, 443 * if {@code False} it indicates Blind transfer. 444 * @hide 445 */ transfer(@onNull String number, boolean isConfirmationRequired)446 public void transfer(@NonNull String number, boolean isConfirmationRequired) { 447 } 448 449 /** 450 * Transfer an established call to another call session 451 * 452 * @param otherSession The other ImsCallSession to transfer the ongoing session to. 453 * @hide 454 */ transfer(@onNull ImsCallSessionImplBase otherSession)455 public void transfer(@NonNull ImsCallSessionImplBase otherSession) { 456 } 457 458 /** 459 * Terminates a call. 460 * 461 * @param reason reason code to terminate a call, defined in {@link ImsReasonInfo}. 462 * 463 * @see {@link ImsCallSession.Listener#callSessionTerminated} 464 */ terminate(int reason)465 public void terminate(int reason) { 466 } 467 468 /** 469 * Puts a call on hold. When it succeeds, {@link ImsCallSession.Listener#callSessionHeld} is 470 * called. 471 * 472 * @param profile stream media profile {@link ImsStreamMediaProfile} to hold the call 473 * @see {@link ImsCallSession.Listener#callSessionHeld}, 474 * {@link ImsCallSession.Listener#callSessionHoldFailed} 475 */ hold(ImsStreamMediaProfile profile)476 public void hold(ImsStreamMediaProfile profile) { 477 } 478 479 /** 480 * Continues a call that's on hold. When it succeeds, 481 * {@link ImsCallSession.Listener#callSessionResumed} is called. 482 * 483 * @param profile stream media profile with {@link ImsStreamMediaProfile} to resume the call 484 * @see {@link ImsCallSession.Listener#callSessionResumed}, 485 * {@link ImsCallSession.Listener#callSessionResumeFailed} 486 */ resume(ImsStreamMediaProfile profile)487 public void resume(ImsStreamMediaProfile profile) { 488 } 489 490 /** 491 * Merges the active and held call. When the merge starts, 492 * {@link ImsCallSession.Listener#callSessionMergeStarted} is called. 493 * {@link ImsCallSession.Listener#callSessionMergeComplete} is called if the merge is 494 * successful, and {@link ImsCallSession.Listener#callSessionMergeFailed} is called if the merge 495 * fails. 496 * 497 * @see {@link ImsCallSession.Listener#callSessionMergeStarted}, 498 * {@link ImsCallSession.Listener#callSessionMergeComplete}, 499 * {@link ImsCallSession.Listener#callSessionMergeFailed} 500 */ merge()501 public void merge() { 502 } 503 504 /** 505 * Updates the current call's properties (ex. call mode change: video upgrade / downgrade). 506 * 507 * @param callType call type specified in {@link ImsCallProfile} to be updated 508 * @param profile stream media profile {@link ImsStreamMediaProfile} to be updated 509 * @see {@link ImsCallSession.Listener#callSessionUpdated}, 510 * {@link ImsCallSession.Listener#callSessionUpdateFailed} 511 */ update(int callType, ImsStreamMediaProfile profile)512 public void update(int callType, ImsStreamMediaProfile profile) { 513 } 514 515 /** 516 * Extends this call to the conference call with the specified recipients. 517 * 518 * @param participants participant list to be invited to the conference call after extending the 519 * call 520 * @see {@link ImsCallSession.Listener#callSessionConferenceExtended}, 521 * {@link ImsCallSession.Listener#callSessionConferenceExtendFailed} 522 */ extendToConference(String[] participants)523 public void extendToConference(String[] participants) { 524 } 525 526 /** 527 * Requests the conference server to invite an additional participants to the conference. 528 * 529 * @param participants participant list to be invited to the conference call 530 * @see {@link ImsCallSession.Listener#callSessionInviteParticipantsRequestDelivered}, 531 * {@link ImsCallSession.Listener#callSessionInviteParticipantsRequestFailed} 532 */ inviteParticipants(String[] participants)533 public void inviteParticipants(String[] participants) { 534 } 535 536 /** 537 * Requests the conference server to remove the specified participants from the conference. 538 * 539 * @param participants participant list to be removed from the conference call 540 * @see {@link ImsCallSession.Listener#callSessionRemoveParticipantsRequestDelivered}, 541 * {@link ImsCallSession.Listener#callSessionRemoveParticipantsRequestFailed} 542 */ removeParticipants(String[] participants)543 public void removeParticipants(String[] participants) { 544 } 545 546 /** 547 * Sends a DTMF code. According to <a href="http://tools.ietf.org/html/rfc2833">RFC 2833</a>, 548 * event 0 ~ 9 maps to decimal value 0 ~ 9, '*' to 10, '#' to 11, event 'A' ~ 'D' to 12 ~ 15, 549 * and event flash to 16. Currently, event flash is not supported. 550 * 551 * @param c the DTMF to send. '0' ~ '9', 'A' ~ 'D', '*', '#' are valid inputs. 552 * @param result If non-null, the {@link Message} to send when the operation is complete. This 553 * is done by using the associated {@link android.os.Messenger} in 554 * {@link Message#replyTo}. For example: 555 * {@code 556 * // Send DTMF and other operations... 557 * try { 558 * // Notify framework that the DTMF was sent. 559 * Messenger dtmfMessenger = result.replyTo; 560 * if (dtmfMessenger != null) { 561 * dtmfMessenger.send(result); 562 * } 563 * } catch (RemoteException e) { 564 * // Remote side is dead 565 * } 566 * } 567 */ sendDtmf(char c, Message result)568 public void sendDtmf(char c, Message result) { 569 } 570 571 /** 572 * Start a DTMF code. According to <a href="http://tools.ietf.org/html/rfc2833">RFC 2833</a>, 573 * event 0 ~ 9 maps to decimal value 0 ~ 9, '*' to 10, '#' to 11, event 'A' ~ 'D' to 12 ~ 15, 574 * and event flash to 16. Currently, event flash is not supported. 575 * 576 * @param c the DTMF to send. '0' ~ '9', 'A' ~ 'D', '*', '#' are valid inputs. 577 */ startDtmf(char c)578 public void startDtmf(char c) { 579 } 580 581 /** 582 * Stop a DTMF code. 583 */ stopDtmf()584 public void stopDtmf() { 585 } 586 587 /** 588 * Sends an USSD message. 589 * 590 * @param ussdMessage USSD message to send 591 */ sendUssd(String ussdMessage)592 public void sendUssd(String ussdMessage) { 593 } 594 595 /** 596 * See {@link #getImsVideoCallProvider()}, used directly in older ImsService implementations. 597 * @hide 598 */ getVideoCallProvider()599 public IImsVideoCallProvider getVideoCallProvider() { 600 ImsVideoCallProvider provider = getImsVideoCallProvider(); 601 return provider != null ? provider.getInterface() : null; 602 } 603 604 /** 605 * @return The {@link ImsVideoCallProvider} implementation contained within the IMS service 606 * process. 607 */ getImsVideoCallProvider()608 public ImsVideoCallProvider getImsVideoCallProvider() { 609 return null; 610 } 611 612 /** 613 * Determines if the current session is multiparty. 614 * @return {@code True} if the session is multiparty. 615 */ isMultiparty()616 public boolean isMultiparty() { 617 return false; 618 } 619 620 /** 621 * Device issues RTT modify request 622 * @param toProfile The profile with requested changes made 623 */ sendRttModifyRequest(ImsCallProfile toProfile)624 public void sendRttModifyRequest(ImsCallProfile toProfile) { 625 } 626 627 /** 628 * Device responds to Remote RTT modify request 629 * @param status true if the the request was accepted or false of the request is defined. 630 */ sendRttModifyResponse(boolean status)631 public void sendRttModifyResponse(boolean status) { 632 } 633 634 /** 635 * Device sends RTT message 636 * @param rttMessage RTT message to be sent 637 */ sendRttMessage(String rttMessage)638 public void sendRttMessage(String rttMessage) { 639 } 640 641 /** @hide */ getServiceImpl()642 public IImsCallSession getServiceImpl() { 643 return mServiceImpl; 644 } 645 646 /** @hide */ setServiceImpl(IImsCallSession serviceImpl)647 public void setServiceImpl(IImsCallSession serviceImpl) { 648 mServiceImpl = serviceImpl; 649 } 650 } 651