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