1 /* 2 * Copyright (C) 2022 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.mockmodem; 18 19 import android.hardware.radio.voice.CdmaSignalInfoRecord; 20 import android.hardware.radio.voice.LastCallFailCause; 21 import android.hardware.radio.voice.LastCallFailCauseInfo; 22 import android.hardware.radio.voice.UusInfo; 23 import android.os.Handler; 24 import android.os.HandlerThread; 25 import android.os.Looper; 26 import android.os.Message; 27 import android.support.annotation.GuardedBy; 28 import android.telephony.Annotation; 29 import android.telephony.DisconnectCause; 30 import android.util.Log; 31 32 import java.util.ArrayList; 33 import java.util.Timer; 34 import java.util.TimerTask; 35 36 public class MockVoiceService { 37 private static final int INVALID_CALL_ID = -1; 38 private static final int MIN_CALL_ID = 1; 39 private static final int MAX_CALL_ID = 9; 40 private static final int MSG_REQUEST_DIALING_CALL = 1; 41 private static final int MSG_REQUEST_RINGBACK_TONE = 2; 42 private static final int MSG_REQUEST_ALERTING_CALL = 3; 43 private static final int MSG_REQUEST_ACTIVATING_CALL = 4; 44 private static final int MSG_REQUEST_DISCONNECTING_CALL = 5; 45 private static final int MSG_REQUEST_INCOMING_CALL = 6; 46 private static final int MSG_REQUEST_CALL_END = 7; 47 48 private static final int EMERGENCY_TEMP_FAILURE = 325; 49 private static final int EMERGENCY_PERM_FAILURE = 326; 50 51 private String mTag = "MockVoiceService"; 52 private Handler mConfigHandler; 53 private HandlerThread mCallStateHandlerThread; 54 private MockCallStateHandler mCallStateHandler; 55 56 @GuardedBy("mCallList") 57 private final ArrayList<MockCallInfo> mCallList = new ArrayList<MockCallInfo>(); 58 59 private LastCallFailCauseInfo mLastCallEndInfo; 60 private boolean mMuteMode; 61 62 public class MockCallInfo { 63 // Call state definition 64 public static final int CALL_STATE_INIT = 0; 65 public static final int CALL_STATE_ACTIVE = 1; 66 public static final int CALL_STATE_HOLDING = 2; 67 public static final int CALL_STATE_DIALING = 3; 68 public static final int CALL_STATE_ALERTING = 4; 69 public static final int CALL_STATE_INCOMING = 5; 70 public static final int CALL_STATE_WAITING = 6; 71 public static final int CALL_STATE_DISCONNECTING = 7; 72 public static final int CALL_STATE_END = 8; 73 74 // Call presentation definition 75 public static final int CALL_PRESENTATION_ALLOWED = 0; 76 public static final int CALL_PRESENTATION_RESTRICTED = 1; 77 public static final int CALL_PRESENTATION_UNKNOWN = 2; 78 public static final int CALL_PRESENTATION_PAYPHONE = 3; 79 80 // Audio quality definition 81 public static final int AUDIO_QUALITY_UNSPECIFIED = 0; 82 public static final int AUDIO_QUALITY_AMR = 1; 83 public static final int AUDIO_QUALITY_AMR_WB = 2; 84 public static final int AUDIO_QUALITY_GSM_EFR = 3; 85 public static final int AUDIO_QUALITY_GSM_FR = 4; 86 public static final int AUDIO_QUALITY_GSM_HR = 5; 87 public static final int AUDIO_QUALITY_EVRC = 6; 88 public static final int AUDIO_QUALITY_EVRC_B = 7; 89 public static final int AUDIO_QUALITY_EVRC_WB = 8; 90 public static final int AUDIO_QUALITY_EVRC_NW = 9; 91 92 // Call type definition 93 public static final int CALL_TYPE_VOICE = 0; 94 public static final int CALL_TYPE_VIDEO = 1; 95 public static final int CALL_TYPE_EMERGENCY = 2; 96 public static final int CALL_TYPE_CDMA_VOICE = 3; 97 public static final int CALL_TYPE_CDMA_EMERGENCY = 4; 98 99 // CLIR type definition 100 public static final int CLIR_TYPE_DEFAULT = 0; 101 public static final int CLIR_TYPE_INVOCATION = 1; 102 public static final int CLIR_TYPE_SUPPRESSION = 2; 103 104 // Default type of address 105 private static final int DEFAULT_TOA = 145; 106 107 private int mState; 108 private int mIndex; 109 private int mToa; 110 private byte mAls; 111 private boolean mIsMpty; 112 private boolean mIsMT; 113 private boolean mIsVoice; 114 private boolean mIsVoicePrivacy; 115 private String mNumber; 116 private int mNumberPresentation; 117 private String mName; 118 private int mNamePresentation; 119 private UusInfo[] mUusInfo; 120 private int mAudioQuality; 121 private String mForwardedNumber; 122 private int mCallType; 123 private int mClir; 124 private CdmaSignalInfoRecord mCdmaSignalInfoRecord; 125 private MockCallControlInfo mCallControlInfo; 126 private int mCategories; 127 private String[] mUrns; 128 private int mRouting; 129 130 @GuardedBy("mTimerList") 131 private final ArrayList<Timer> mTimerList = new ArrayList<Timer>(); 132 133 private final class MockCallStateTimerTask extends TimerTask { 134 private Timer mTimer; 135 private int mCallId; 136 private int mEvent; 137 MockCallStateTimerTask(Timer timer, int callId, int event)138 MockCallStateTimerTask(Timer timer, int callId, int event) { 139 mTimer = timer; 140 mCallId = callId; 141 mEvent = event; 142 } 143 144 @Override run()145 public void run() { 146 Log.d( 147 mTag, 148 "Timer task - triggering call state event = " 149 + getCallStateRequestEventStr(mEvent) 150 + " for call id = " 151 + mCallId); 152 mCallStateHandler.obtainMessage(mEvent, mCallId).sendToTarget(); 153 synchronized (mTimerList) { 154 mTimerList.remove(mTimer); 155 } 156 } 157 } 158 MockCallInfo( boolean isMT, String address, int clir, UusInfo[] uusInfo, int callType, MockCallControlInfo callControlInfo)159 public MockCallInfo( 160 boolean isMT, 161 String address, 162 int clir, 163 UusInfo[] uusInfo, 164 int callType, 165 MockCallControlInfo callControlInfo) { 166 mState = CALL_STATE_INIT; 167 mIndex = generateCallId(); 168 mToa = DEFAULT_TOA; 169 mNumber = address; 170 mIsMT = isMT; 171 mClir = clir; 172 mUusInfo = uusInfo; 173 mCallType = callType; 174 mCdmaSignalInfoRecord = null; 175 if (callControlInfo == null) { 176 mCallControlInfo = new MockCallControlInfo(); 177 Log.w(mTag, "No call control info. Using default instead."); 178 } else { 179 mCallControlInfo = callControlInfo; 180 } 181 } 182 MockCallInfo( boolean isMT, String address, int categories, String[] urns, int routing, int callType, MockCallControlInfo callControlInfo)183 public MockCallInfo( 184 boolean isMT, 185 String address, 186 int categories, 187 String[] urns, 188 int routing, 189 int callType, 190 MockCallControlInfo callControlInfo) { 191 mState = CALL_STATE_INIT; 192 mIndex = generateCallId(); 193 mToa = DEFAULT_TOA; 194 mNumber = address; 195 mIsMT = isMT; 196 mCallType = callType; 197 mCategories = categories; 198 mUrns = urns; 199 mRouting = routing; 200 if (callControlInfo == null) { 201 mCallControlInfo = new MockCallControlInfo(); 202 Log.w(mTag, "No call control info. Using default instead."); 203 } else { 204 mCallControlInfo = callControlInfo; 205 } 206 } 207 getCallState()208 public int getCallState() { 209 return mState; 210 } 211 setCallState(int state)212 public void setCallState(int state) { 213 mState = state; 214 } 215 getCallId()216 public int getCallId() { 217 return mIndex; 218 } 219 setCallId(int callId)220 public void setCallId(int callId) { 221 mIndex = callId; 222 } 223 getCallToa()224 public int getCallToa() { 225 return mToa; 226 } 227 setCallToa(int toa)228 public void setCallToa(int toa) { 229 mToa = toa; 230 } 231 getCallAls()232 public byte getCallAls() { 233 return mAls; 234 } 235 setCallAls(byte als)236 public void setCallAls(byte als) { 237 mAls = als; 238 } 239 isMpty()240 public boolean isMpty() { 241 return mIsMpty; 242 } 243 setMpty(boolean isMpty)244 public void setMpty(boolean isMpty) { 245 mIsMpty = isMpty; 246 } 247 isMT()248 public boolean isMT() { 249 return mIsMT; 250 } 251 setMT(boolean isMT)252 public void setMT(boolean isMT) { 253 mIsMT = isMT; 254 } 255 isVoice()256 public boolean isVoice() { 257 return mIsVoice; 258 } 259 setVoice(boolean isVoice)260 public void setVoice(boolean isVoice) { 261 mIsVoice = isVoice; 262 } 263 isVoicePrivacy()264 public boolean isVoicePrivacy() { 265 return mIsVoicePrivacy; 266 } 267 setVoicePrivacy(boolean isVoicePrivacy)268 public void setVoicePrivacy(boolean isVoicePrivacy) { 269 mIsVoicePrivacy = isVoicePrivacy; 270 } 271 getNumber()272 public String getNumber() { 273 return mNumber; 274 } 275 setNumber(String number)276 public void setNumber(String number) { 277 mNumber = number; 278 } 279 getNumberPresentation()280 public int getNumberPresentation() { 281 return mNumberPresentation; 282 } 283 setNumberPresentation(int numberPresentation)284 public void setNumberPresentation(int numberPresentation) { 285 mNumberPresentation = numberPresentation; 286 } 287 getName()288 public String getName() { 289 return mName; 290 } 291 setName(String name)292 public void setName(String name) { 293 mName = name; 294 } 295 getNamePresentation()296 public int getNamePresentation() { 297 return mNamePresentation; 298 } 299 setNamePresentation(int namePresentation)300 public void setNamePresentation(int namePresentation) { 301 mNamePresentation = namePresentation; 302 } 303 getUusInfo()304 public UusInfo[] getUusInfo() { 305 return mUusInfo; 306 } 307 setUusInfo(UusInfo[] uusInfo)308 public void setUusInfo(UusInfo[] uusInfo) { 309 mUusInfo = uusInfo; 310 } 311 getAudioQuality()312 public int getAudioQuality() { 313 return mAudioQuality; 314 } 315 setAudioQuality(int audioQuality)316 public void setAudioQuality(int audioQuality) { 317 mAudioQuality = audioQuality; 318 } 319 getForwardedNumber()320 public String getForwardedNumber() { 321 return mForwardedNumber; 322 } 323 setForwardedNumber(String forwardedNumber)324 public void setForwardedNumber(String forwardedNumber) { 325 mForwardedNumber = forwardedNumber; 326 } 327 getClir()328 public int getClir() { 329 return mClir; 330 } 331 setClir(int clir)332 public void setClir(int clir) { 333 mClir = clir; 334 } 335 getCallType()336 public int getCallType() { 337 return mCallType; 338 } 339 setCallType(int callType)340 public void setCallType(int callType) { 341 mCallType = callType; 342 } 343 dump()344 public void dump() { 345 Log.d( 346 mTag, 347 "mState = " 348 + mState 349 + ", mIndex = " 350 + mIndex 351 + ", mToa = " 352 + mToa 353 + ", mAls = " 354 + mAls 355 + ", mIsMpty = " 356 + mIsMpty 357 + ", mIsVoice = " 358 + mIsVoice 359 + ", mIsvoicePrivacy = " 360 + mIsVoicePrivacy 361 + ", mNumber = " 362 + mNumber 363 + ", mNumberPresentation = " 364 + mNumberPresentation 365 + ", mName = " 366 + mName 367 + ", mNamePresentation = " 368 + mNamePresentation 369 + ", mAudioQuality = " 370 + mAudioQuality 371 + ", mForwardedNumber = " 372 + mForwardedNumber 373 + ", mCallType = " 374 + mCallType 375 + ", mClir = " 376 + mClir); 377 } 378 getCdmaSignalInfoRecord()379 public CdmaSignalInfoRecord getCdmaSignalInfoRecord() { 380 return mCdmaSignalInfoRecord; 381 } 382 setCdmaSignalInfoRecord(CdmaSignalInfoRecord cdmaSignalInfoRecord)383 public void setCdmaSignalInfoRecord(CdmaSignalInfoRecord cdmaSignalInfoRecord) { 384 mCdmaSignalInfoRecord = cdmaSignalInfoRecord; 385 } 386 getCallControlInfo()387 public MockCallControlInfo getCallControlInfo() { 388 return mCallControlInfo; 389 } 390 addCallStateTimerTask(int callId, int event, long duration)391 public void addCallStateTimerTask(int callId, int event, long duration) { 392 Timer timer = new Timer(false); 393 MockCallStateTimerTask timerTask = new MockCallStateTimerTask(timer, callId, event); 394 if (timer != null && timerTask != null) { 395 timer.schedule(timerTask, duration); 396 synchronized (mTimerList) { 397 if (mTimerList != null) { 398 mTimerList.add(timer); 399 } 400 } 401 } else { 402 Log.e( 403 mTag, 404 "Failed to start timer for event = " + getCallStateRequestEventStr(event)); 405 } 406 } 407 clearAllTimers()408 public void clearAllTimers() { 409 synchronized (mTimerList) { 410 if (mTimerList != null && mTimerList.size() > 0) { 411 for (int i = 0; i < mTimerList.size(); i++) { 412 mTimerList.get(i).cancel(); 413 } 414 mTimerList.clear(); 415 } 416 } 417 } 418 destroy()419 public void destroy() { 420 clearAllTimers(); 421 } 422 } 423 MockVoiceService(Handler handler)424 public MockVoiceService(Handler handler) { 425 mConfigHandler = handler; 426 mLastCallEndInfo = new LastCallFailCauseInfo(); 427 initMockVoiceService(); 428 429 // Start call state handler 430 mCallStateHandlerThread = new HandlerThread(mTag); 431 mCallStateHandlerThread.start(); 432 mCallStateHandler = new MockCallStateHandler(mCallStateHandlerThread.getLooper()); 433 } 434 destroy()435 public void destroy() { 436 Log.e(mTag, "destroy"); 437 clearAllCalls(); 438 if (mCallStateHandlerThread != null) { 439 mCallStateHandlerThread.quitSafely(); 440 mCallStateHandlerThread = null; 441 } 442 } 443 initMockVoiceService()444 private void initMockVoiceService() { 445 clearAllCalls(); 446 mMuteMode = false; 447 } 448 clearAllCalls()449 private void clearAllCalls() { 450 synchronized (mCallList) { 451 if (mCallList != null && mCallList.size() > 0) { 452 for (int i = 0; i < mCallList.size(); i++) { 453 mCallList.get(i).destroy(); 454 } 455 mCallList.clear(); 456 } 457 } 458 } 459 generateCallId()460 private int generateCallId() { 461 int callId = INVALID_CALL_ID; 462 int idx = 0; 463 464 synchronized (mCallList) { 465 for (callId = MIN_CALL_ID; callId <= MAX_CALL_ID; callId++) { 466 for (idx = 0; idx < mCallList.size(); idx++) { 467 if (mCallList.get(idx).getCallId() == callId) { 468 break; 469 } 470 } 471 if (idx == mCallList.size()) { 472 break; 473 } 474 } 475 } 476 477 if (callId > MAX_CALL_ID) { 478 callId = INVALID_CALL_ID; 479 Log.e(mTag, "Exceed maximum number of call (" + MAX_CALL_ID + ")."); 480 } 481 482 return callId; 483 } 484 getCallInfo(int callId)485 private MockCallInfo getCallInfo(int callId) { 486 MockCallInfo callInfo = null; 487 if (callId >= MIN_CALL_ID && callId <= MAX_CALL_ID) { 488 if (hasVoiceCalls()) { 489 synchronized (mCallList) { 490 for (int idx = 0; idx < mCallList.size(); idx++) { 491 callInfo = mCallList.get(idx); 492 if (callInfo.getCallId() == callId) { 493 break; 494 } else { 495 callInfo = null; 496 } 497 } 498 } 499 } else { 500 Log.w(mTag, "No any call in list."); 501 } 502 } else { 503 Log.e(mTag, "Invalid call id."); 504 } 505 506 if (callInfo == null) { 507 Log.e(mTag, "Not found any call info with call id " + callId + "."); 508 } 509 510 return callInfo; 511 } 512 removeCallInfo(int callId)513 private void removeCallInfo(int callId) { 514 MockCallInfo callInfo = null; 515 516 if (callId >= MIN_CALL_ID && callId <= MAX_CALL_ID) { 517 if (hasVoiceCalls()) { 518 synchronized (mCallList) { 519 for (int idx = 0; idx < mCallList.size(); idx++) { 520 callInfo = mCallList.get(idx); 521 if (callInfo.getCallId() == callId) { 522 mCallList.remove(idx); 523 break; 524 } else { 525 callInfo = null; 526 } 527 } 528 } 529 } else { 530 Log.w(mTag, "No any call in list."); 531 } 532 } else { 533 Log.e(mTag, "Invalid call id."); 534 } 535 536 if (callInfo == null) { 537 Log.e(mTag, "Not found any call info with call id " + callId + "."); 538 } 539 540 return; 541 } 542 getIncomingCallInfo()543 private MockCallInfo getIncomingCallInfo() { 544 MockCallInfo callInfo = null; 545 546 if (hasVoiceCalls()) { 547 synchronized (mCallList) { 548 for (int idx = 0; idx < mCallList.size(); idx++) { 549 callInfo = mCallList.get(idx); 550 if (callInfo.isMT() 551 && callInfo.getCallState() == MockCallInfo.CALL_STATE_INCOMING) { 552 break; 553 } else { 554 callInfo = null; 555 } 556 } 557 } 558 } else { 559 Log.w(mTag, "No any call in list."); 560 } 561 562 if (callInfo == null) { 563 Log.e(mTag, "Not found any incoming call info."); 564 } 565 566 return callInfo; 567 } 568 getCallStateRequestEventStr(int event)569 private String getCallStateRequestEventStr(int event) { 570 switch (event) { 571 case MSG_REQUEST_DIALING_CALL: 572 return "MSG_REQUEST_DIALING_CALL"; 573 case MSG_REQUEST_RINGBACK_TONE: 574 return "MSG_REQUEST_RINGBACK_TONE"; 575 case MSG_REQUEST_ALERTING_CALL: 576 return "MSG_REQUEST_ALERTING_CALL"; 577 case MSG_REQUEST_ACTIVATING_CALL: 578 return "MSG_REQUEST_ACTIVATING_CALL"; 579 case MSG_REQUEST_DISCONNECTING_CALL: 580 return "MSG_REQUEST_DISCONNECTING_CALL"; 581 case MSG_REQUEST_INCOMING_CALL: 582 return "MSG_REQUEST_INCOMING_CALL"; 583 case MSG_REQUEST_CALL_END: 584 return "MSG_REQUEST_CALL_END"; 585 } 586 return "Unknown"; 587 } 588 scheduleNextEventTimer(MockCallInfo callInfo, int nextEvent, long duration)589 private void scheduleNextEventTimer(MockCallInfo callInfo, int nextEvent, long duration) { 590 Log.d( 591 mTag, 592 "Schedule " 593 + getCallStateRequestEventStr(nextEvent) 594 + " for call id " 595 + callInfo.getCallId() 596 + " in " 597 + duration 598 + " ms."); 599 if (nextEvent >= 0) { 600 callInfo.addCallStateTimerTask(callInfo.getCallId(), nextEvent, duration); 601 } 602 } 603 handleDialingCall(int callId)604 private boolean handleDialingCall(int callId) { 605 Log.d(mTag, "handleDialingCall for call id: " + callId); 606 boolean isCallStateChanged = false; 607 608 synchronized (mCallList) { 609 MockCallInfo callInfo = getCallInfo(callId); 610 611 if (callInfo != null) { 612 long dialing_duration_in_ms = 613 callInfo.getCallControlInfo().getDialingDurationInMs(); 614 long alerting_duration_in_ms = 615 callInfo.getCallControlInfo().getAlertingDurationInMs(); 616 long ringback_tone_in_ms = callInfo.getCallControlInfo().getRingbackToneTimeInMs(); 617 int call_state_fail_bitmask = 618 callInfo.getCallControlInfo().getCallStateFailBitMask(); 619 int next_event = -1; 620 621 if (callInfo.getCallState() != MockCallInfo.CALL_STATE_DIALING) { 622 callInfo.setCallState(MockCallInfo.CALL_STATE_DIALING); 623 isCallStateChanged = true; 624 Log.d(mTag, "call id = " + callId + " call state = CALL_STATE_DIALING"); 625 } 626 627 if (isCallStateChanged) { 628 if ((call_state_fail_bitmask & MockCallControlInfo.CALL_DIALING_FAIL_BITMASK) 629 != 0) { 630 if (dialing_duration_in_ms < 0) { 631 Log.d(mTag, "Dialing duration < 0, using default duration!"); 632 dialing_duration_in_ms = 633 MockCallControlInfo.DEFAULT_DIALING_FAIL_DURATION_IN_MS; 634 } 635 next_event = MSG_REQUEST_DISCONNECTING_CALL; 636 Log.d( 637 mTag, 638 "Start call disconnecting task after " 639 + dialing_duration_in_ms 640 + " ms."); 641 } else { 642 // Ringback tone start event 643 callInfo.getCallControlInfo().setRingbackToneState(true); 644 next_event = MSG_REQUEST_RINGBACK_TONE; 645 if (ringback_tone_in_ms < 0 646 || ringback_tone_in_ms 647 > (dialing_duration_in_ms + alerting_duration_in_ms)) { 648 ringback_tone_in_ms = dialing_duration_in_ms; 649 Log.e( 650 mTag, 651 "ringback_tone_in_ms < 0 or > (dialing + alerting) duration (" 652 + (dialing_duration_in_ms + alerting_duration_in_ms) 653 + ") ms. Reset to dialing duration (" 654 + dialing_duration_in_ms 655 + ") ms"); 656 } 657 658 Log.d( 659 mTag, 660 "Start ringback tone task after " + ringback_tone_in_ms + " ms."); 661 662 scheduleNextEventTimer(callInfo, next_event, ringback_tone_in_ms); 663 664 // Next call state change event 665 if (dialing_duration_in_ms >= 0) { 666 next_event = MSG_REQUEST_ALERTING_CALL; 667 Log.d( 668 mTag, 669 "Start alerting task after " + dialing_duration_in_ms + " ms."); 670 } else { 671 next_event = -1; 672 Log.d(mTag, "Call dialing forever...."); 673 } 674 } 675 676 scheduleNextEventTimer(callInfo, next_event, dialing_duration_in_ms); 677 } 678 } else { 679 Log.e(mTag, "No found call id = " + callId); 680 } 681 } 682 683 return isCallStateChanged; 684 } 685 handleRingbackTone(int callId)686 private boolean handleRingbackTone(int callId) { 687 Log.d(mTag, "handleRingbackTone for call id: " + callId); 688 689 synchronized (mCallList) { 690 MockCallInfo callInfo = getCallInfo(callId); 691 692 if (callInfo != null) { 693 Message ringback_tone_msg = 694 mConfigHandler.obtainMessage( 695 MockModemConfigBase.EVENT_RINGBACK_TONE, 696 callInfo.getCallControlInfo().getRingbackToneState()); 697 mConfigHandler.sendMessage(ringback_tone_msg); 698 } else { 699 Log.e(mTag, "No found call id = " + callId); 700 } 701 } 702 703 return false; 704 } 705 handleAlertingCall(int callId)706 private boolean handleAlertingCall(int callId) { 707 Log.d(mTag, "handleAlertingCall for call id: " + callId); 708 709 boolean isCallStateChanged = false; 710 711 synchronized (mCallList) { 712 MockCallInfo callInfo = getCallInfo(callId); 713 714 if (callInfo != null) { 715 long alerting_duration_in_ms = 716 callInfo.getCallControlInfo().getAlertingDurationInMs(); 717 int call_state_fail_bitmask = 718 callInfo.getCallControlInfo().getCallStateFailBitMask(); 719 int next_event = -1; 720 721 if (callInfo.getCallState() != MockCallInfo.CALL_STATE_ALERTING) { 722 callInfo.setCallState(MockCallInfo.CALL_STATE_ALERTING); 723 isCallStateChanged = true; 724 Log.d(mTag, "call id = " + callId + " call state = CALL_STATE_ALERTING"); 725 } 726 727 if (isCallStateChanged) { 728 if ((call_state_fail_bitmask & MockCallControlInfo.CALL_ALERTING_FAIL_BITMASK) 729 != 0) { 730 if (alerting_duration_in_ms < 0) { 731 Log.d(mTag, "Alerting duration < 0, using default duration!"); 732 alerting_duration_in_ms = 733 MockCallControlInfo.DEFAULT_ALERTING_FAIL_DURATION_IN_MS; 734 } 735 next_event = MSG_REQUEST_DISCONNECTING_CALL; 736 Log.d( 737 mTag, 738 "Start call disconnecting task after " 739 + alerting_duration_in_ms 740 + " ms."); 741 } else { 742 if (alerting_duration_in_ms >= 0) { 743 next_event = MSG_REQUEST_ACTIVATING_CALL; 744 Log.d( 745 mTag, 746 "Start activating task after " 747 + alerting_duration_in_ms 748 + " ms."); 749 } else { 750 next_event = -1; 751 Log.d(mTag, "Call alerting forever...."); 752 } 753 } 754 755 scheduleNextEventTimer(callInfo, next_event, alerting_duration_in_ms); 756 } 757 } else { 758 Log.e(mTag, "No found call id = " + callId); 759 } 760 } 761 762 return isCallStateChanged; 763 } 764 handleActivatingCall(int callId)765 private boolean handleActivatingCall(int callId) { 766 Log.d(mTag, "handleActivatingCall for call id: " + callId); 767 768 boolean isCallStateChanged = false; 769 770 synchronized (mCallList) { 771 MockCallInfo callInfo = getCallInfo(callId); 772 773 if (callInfo != null) { 774 long active_duration_in_ms = callInfo.getCallControlInfo().getActiveDurationInMs(); 775 int next_event = -1; 776 777 if (callInfo.getCallState() != MockCallInfo.CALL_STATE_ACTIVE) { 778 // Ringback tone stop event 779 callInfo.getCallControlInfo().setRingbackToneState(false); 780 next_event = MSG_REQUEST_RINGBACK_TONE; 781 Log.d(mTag, "Start ringback tone task immediately."); 782 scheduleNextEventTimer(callInfo, next_event, 0); 783 callInfo.setCallState(MockCallInfo.CALL_STATE_ACTIVE); 784 isCallStateChanged = true; 785 Log.d(mTag, "call id = " + callId + " call state = CALL_STATE_ACTIVE"); 786 } 787 788 if (isCallStateChanged) { 789 // Next call state change event 790 if (active_duration_in_ms >= 0) { 791 next_event = MSG_REQUEST_DISCONNECTING_CALL; 792 Log.d( 793 mTag, 794 "Start call disconnecting task after " 795 + active_duration_in_ms 796 + " ms."); 797 scheduleNextEventTimer(callInfo, next_event, active_duration_in_ms); 798 } else { 799 Log.d(mTag, "Call active forever...."); 800 } 801 } 802 } else { 803 Log.e(mTag, "No found call id = " + callId); 804 } 805 } 806 807 return isCallStateChanged; 808 } 809 handleDisconnectingCall(int callId)810 private boolean handleDisconnectingCall(int callId) { 811 Log.d(mTag, "handleDisconnectingCall for call id: " + callId); 812 813 boolean isCallStateChanged = false; 814 815 synchronized (mCallList) { 816 MockCallInfo callInfo = getCallInfo(callId); 817 818 if (callInfo != null) { 819 long disconnecting_duration_in_ms = 820 callInfo.getCallControlInfo().getDisconnectingDurationInMs(); 821 int next_event = -1; 822 823 if (callInfo.getCallState() != MockCallInfo.CALL_STATE_DISCONNECTING) { 824 callInfo.setCallState(MockCallInfo.CALL_STATE_DISCONNECTING); 825 callInfo.clearAllTimers(); 826 isCallStateChanged = true; 827 Log.d(mTag, "call id = " + callId + " call state = CALL_STATE_DISCONNECTING"); 828 } 829 830 if (isCallStateChanged) { 831 if (disconnecting_duration_in_ms >= 0) { 832 next_event = MSG_REQUEST_CALL_END; 833 Log.d( 834 mTag, 835 "Start call end task after " 836 + disconnecting_duration_in_ms 837 + " ms."); 838 scheduleNextEventTimer(callInfo, next_event, disconnecting_duration_in_ms); 839 } else { 840 Log.d(mTag, "Call disconnecting forever...."); 841 } 842 // No need updating call disconnecting to upper layer 843 isCallStateChanged = false; 844 } 845 } else { 846 Log.e(mTag, "No found call id = " + callId); 847 } 848 } 849 850 return isCallStateChanged; 851 } 852 handleIncomingCall(int callId)853 private boolean handleIncomingCall(int callId) { 854 Log.d(mTag, "handleIncomingCall for call id: " + callId); 855 856 boolean isCallStateChanged = false; 857 858 synchronized (mCallList) { 859 MockCallInfo callInfo = getCallInfo(callId); 860 861 if (callInfo != null) { 862 long incoming_duration_in_ms = 863 callInfo.getCallControlInfo().getIncomingDurationInMs(); 864 int call_state_fail_bitmask = 865 callInfo.getCallControlInfo().getCallStateFailBitMask(); 866 int next_event = -1; 867 868 if (callInfo.getCallState() != MockCallInfo.CALL_STATE_INCOMING) { 869 callInfo.setCallState(MockCallInfo.CALL_STATE_INCOMING); 870 isCallStateChanged = true; 871 Log.d(mTag, "call id = " + callId + " call state = CALL_STATE_INCOMING"); 872 } 873 874 if (isCallStateChanged) { 875 if ((call_state_fail_bitmask & MockCallControlInfo.CALL_INCOMING_FAIL_BITMASK) 876 != 0) { 877 if (incoming_duration_in_ms < 0) { 878 Log.d(mTag, "Incoming duration < 0, using default duration!"); 879 incoming_duration_in_ms = 880 MockCallControlInfo.DEFAULT_INCOMING_FAIL_DURATION_IN_MS; 881 } 882 next_event = MSG_REQUEST_DISCONNECTING_CALL; 883 Log.d( 884 mTag, 885 "Start call disconnecting task after " 886 + incoming_duration_in_ms 887 + " ms."); 888 } else { 889 if (incoming_duration_in_ms >= 0) { 890 next_event = MSG_REQUEST_ACTIVATING_CALL; 891 Log.d( 892 mTag, 893 "Start activating task after " 894 + incoming_duration_in_ms 895 + " ms."); 896 } else { 897 next_event = -1; 898 Log.d(mTag, "Call incoming forever...."); 899 } 900 } 901 902 scheduleNextEventTimer(callInfo, next_event, incoming_duration_in_ms); 903 } 904 } else { 905 Log.e(mTag, "No found call id = " + callId); 906 } 907 908 if (isCallStateChanged) { 909 Message call_incoming_msg = 910 mConfigHandler.obtainMessage( 911 MockModemConfigBase.EVENT_CALL_INCOMING, callInfo); 912 mConfigHandler.sendMessage(call_incoming_msg); 913 } 914 } 915 916 return isCallStateChanged; 917 } 918 handleCallEnd(int callId)919 private boolean handleCallEnd(int callId) { 920 Log.d(mTag, "handleCallEnd for call id: " + callId); 921 922 boolean isCallStateChanged = false; 923 924 synchronized (mCallList) { 925 MockCallInfo callInfo = getCallInfo(callId); 926 927 if (callInfo != null) { 928 if (callInfo.getCallState() != MockCallInfo.CALL_STATE_END) { 929 callInfo.setCallState(MockCallInfo.CALL_STATE_END); 930 mLastCallEndInfo.causeCode = 931 callInfo.getCallControlInfo().getCallEndInfo().causeCode; 932 mLastCallEndInfo.vendorCause = 933 callInfo.getCallControlInfo().getCallEndInfo().vendorCause; 934 isCallStateChanged = true; 935 removeCallInfo(callId); 936 Log.d( 937 mTag, 938 "call id = " 939 + callId 940 + " call state = CALL_STATE_END with causeCode = " 941 + mLastCallEndInfo.causeCode 942 + ", vendorCause = " 943 + mLastCallEndInfo.vendorCause); 944 } 945 } else { 946 Log.e(mTag, "No found call id = " + callId); 947 } 948 } 949 950 return isCallStateChanged; 951 } 952 953 private final class MockCallStateHandler extends Handler { MockCallStateHandler(Looper looper)954 MockCallStateHandler(Looper looper) { 955 super(looper); 956 } 957 958 @Override handleMessage(Message msg)959 public void handleMessage(Message msg) { 960 Log.d( 961 mTag, 962 "Call state change handling begin for " 963 + getCallStateRequestEventStr(msg.what)); 964 boolean isCallStateChanged = false; 965 966 try { 967 switch (msg.what) { 968 case MSG_REQUEST_DIALING_CALL: 969 isCallStateChanged = handleDialingCall((int) msg.obj); 970 break; 971 case MSG_REQUEST_RINGBACK_TONE: 972 isCallStateChanged = handleRingbackTone((int) msg.obj); 973 break; 974 case MSG_REQUEST_ALERTING_CALL: 975 isCallStateChanged = handleAlertingCall((int) msg.obj); 976 break; 977 case MSG_REQUEST_ACTIVATING_CALL: 978 isCallStateChanged = handleActivatingCall((int) msg.obj); 979 break; 980 case MSG_REQUEST_DISCONNECTING_CALL: 981 isCallStateChanged = handleDisconnectingCall((int) msg.obj); 982 break; 983 case MSG_REQUEST_INCOMING_CALL: 984 isCallStateChanged = handleIncomingCall((int) msg.obj); 985 break; 986 case MSG_REQUEST_CALL_END: 987 isCallStateChanged = handleCallEnd((int) msg.obj); 988 break; 989 default: 990 Log.e(mTag, "Unknown message id."); 991 break; 992 } 993 } finally { 994 Log.d(mTag, "Call state change handling complete"); 995 if (isCallStateChanged) { 996 synchronized (mCallList) { 997 Message call_state_changed_msg = 998 mConfigHandler.obtainMessage( 999 MockModemConfigBase.EVENT_CALL_STATE_CHANGE, mCallList); 1000 mConfigHandler.sendMessage(call_state_changed_msg); 1001 } 1002 } 1003 } 1004 } 1005 } 1006 getNumberOfCalls()1007 public int getNumberOfCalls() { 1008 int numOfCalls = 0; 1009 synchronized (mCallList) { 1010 numOfCalls = mCallList.size(); 1011 } 1012 return numOfCalls; 1013 } 1014 hasVoiceCalls()1015 public boolean hasVoiceCalls() { 1016 return (getNumberOfCalls() > 0 ? true : false); 1017 } 1018 hasDisconnectingCall()1019 public boolean hasDisconnectingCall() { 1020 boolean result = false; 1021 synchronized (mCallList) { 1022 for (int i = 0; i < mCallList.size(); i++) { 1023 if (mCallList.get(i).getCallState() == MockCallInfo.CALL_STATE_DISCONNECTING) { 1024 result = true; 1025 break; 1026 } 1027 } 1028 } 1029 return result; 1030 } 1031 getCurrentCalls()1032 public boolean getCurrentCalls() { 1033 if (!hasDisconnectingCall()) { 1034 synchronized (mCallList) { 1035 Message current_calls_response_msg = 1036 mConfigHandler.obtainMessage( 1037 MockModemConfigBase.EVENT_CURRENT_CALLS_RESPONSE, mCallList); 1038 mConfigHandler.sendMessage(current_calls_response_msg); 1039 } 1040 } else { 1041 Log.d(mTag, "Has disconnecting calls, skip to trigger EVENT_CURRENT_CALLS_RESPONSE."); 1042 } 1043 return true; 1044 } 1045 dialVoiceCall( String address, int clir, UusInfo[] uusInfo, int callType, MockCallControlInfo callControlInfo)1046 public boolean dialVoiceCall( 1047 String address, 1048 int clir, 1049 UusInfo[] uusInfo, 1050 int callType, 1051 MockCallControlInfo callControlInfo) { 1052 boolean result = false; 1053 MockCallInfo newCall = 1054 new MockCallInfo(false, address, clir, uusInfo, callType, callControlInfo); 1055 1056 if (newCall != null) { 1057 synchronized (mCallList) { 1058 mCallList.add(newCall); 1059 newCall.dump(); 1060 newCall.getCallControlInfo().dump(); 1061 } 1062 mCallStateHandler 1063 .obtainMessage(MSG_REQUEST_DIALING_CALL, newCall.getCallId()) 1064 .sendToTarget(); 1065 result = true; 1066 } else { 1067 Log.e(mTag, "Call info creation failed!"); 1068 } 1069 return result; 1070 } 1071 dialEccVoiceCall( String address, int categories, String[] urns, int routing, int callType, MockCallControlInfo callControlInfo)1072 public boolean dialEccVoiceCall( 1073 String address, 1074 int categories, 1075 String[] urns, 1076 int routing, 1077 int callType, 1078 MockCallControlInfo callControlInfo) { 1079 boolean result = false; 1080 MockCallInfo newCall = 1081 new MockCallInfo(false, address, 1082 categories, urns, routing, callType, callControlInfo); 1083 1084 if (newCall != null) { 1085 synchronized (mCallList) { 1086 mCallList.add(newCall); 1087 newCall.dump(); 1088 newCall.getCallControlInfo().dump(); 1089 } 1090 mCallStateHandler 1091 .obtainMessage(MSG_REQUEST_DIALING_CALL, newCall.getCallId()) 1092 .sendToTarget(); 1093 result = true; 1094 } else { 1095 Log.e(mTag, "Call info creation failed!"); 1096 } 1097 return result; 1098 } 1099 hangupVoiceCall(int index)1100 public boolean hangupVoiceCall(int index) { 1101 boolean result = false; 1102 MockCallInfo callInfo = null; 1103 1104 synchronized (mCallList) { 1105 callInfo = getCallInfo(index); 1106 1107 if (callInfo != null) { 1108 mCallStateHandler 1109 .obtainMessage(MSG_REQUEST_DISCONNECTING_CALL, index) 1110 .sendToTarget(); 1111 result = true; 1112 } else { 1113 Log.e(mTag, "Cannot find any call with id = " + index); 1114 } 1115 } 1116 1117 return result; 1118 } 1119 rejectVoiceCall()1120 public boolean rejectVoiceCall() { 1121 boolean result = false; 1122 MockCallInfo callInfo = null; 1123 1124 synchronized (mCallList) { 1125 callInfo = getIncomingCallInfo(); 1126 1127 if (callInfo != null) { 1128 mCallStateHandler 1129 .obtainMessage(MSG_REQUEST_DISCONNECTING_CALL, callInfo.getCallId()) 1130 .sendToTarget(); 1131 result = true; 1132 } else { 1133 Log.e(mTag, "Cannot find any incoming call."); 1134 } 1135 } 1136 1137 return result; 1138 } 1139 acceptVoiceCall()1140 public boolean acceptVoiceCall() { 1141 boolean result = false; 1142 MockCallInfo callInfo = null; 1143 1144 synchronized (mCallList) { 1145 callInfo = getIncomingCallInfo(); 1146 1147 if (callInfo != null) { 1148 mCallStateHandler 1149 .obtainMessage(MSG_REQUEST_ACTIVATING_CALL, callInfo.getCallId()) 1150 .sendToTarget(); 1151 result = true; 1152 } else { 1153 Log.e(mTag, "Cannot find any incoming call."); 1154 } 1155 } 1156 1157 return result; 1158 } 1159 triggerIncomingVoiceCall( String address, UusInfo[] uusInfo, int callType, CdmaSignalInfoRecord cdmaSignalInfoRecord, MockCallControlInfo callControlInfo)1160 public boolean triggerIncomingVoiceCall( 1161 String address, 1162 UusInfo[] uusInfo, 1163 int callType, 1164 CdmaSignalInfoRecord cdmaSignalInfoRecord, 1165 MockCallControlInfo callControlInfo) { 1166 boolean result = false; 1167 MockCallInfo newCall = 1168 new MockCallInfo( 1169 true, 1170 address, 1171 MockCallInfo.CLIR_TYPE_DEFAULT, 1172 uusInfo, 1173 callType, 1174 callControlInfo); 1175 1176 if (newCall != null) { 1177 if (cdmaSignalInfoRecord != null) { 1178 newCall.setCdmaSignalInfoRecord(cdmaSignalInfoRecord); 1179 } 1180 1181 synchronized (mCallList) { 1182 mCallList.add(newCall); 1183 newCall.dump(); 1184 } 1185 mCallStateHandler 1186 .obtainMessage(MSG_REQUEST_INCOMING_CALL, newCall.getCallId()) 1187 .sendToTarget(); 1188 result = true; 1189 } else { 1190 Log.e(mTag, "Call info creation failed!"); 1191 } 1192 1193 return result; 1194 } 1195 getMuteMode()1196 public boolean getMuteMode() { 1197 return mMuteMode; 1198 } 1199 setMuteMode(boolean isMute)1200 public void setMuteMode(boolean isMute) { 1201 mMuteMode = isMute; 1202 } 1203 getLastCallEndInfo()1204 public LastCallFailCauseInfo getLastCallEndInfo() { 1205 return mLastCallEndInfo; 1206 } 1207 setLastCallFailCause(@nnotation.DisconnectCauses int cause)1208 public void setLastCallFailCause(@Annotation.DisconnectCauses int cause) { 1209 mLastCallEndInfo.causeCode = convertToLastCallFailCause(cause); 1210 } 1211 clearAllCalls(@nnotation.DisconnectCauses int cause)1212 public void clearAllCalls(@Annotation.DisconnectCauses int cause) { 1213 setLastCallFailCause(cause); 1214 synchronized (mCallList) { 1215 if (mCallList != null && mCallList.size() > 0) { 1216 clearAllCalls(); 1217 Message call_state_changed_msg = 1218 mConfigHandler.obtainMessage( 1219 MockModemConfigBase.EVENT_CALL_STATE_CHANGE, mCallList); 1220 mConfigHandler.sendMessage(call_state_changed_msg); 1221 } 1222 } 1223 } 1224 1225 /** 1226 * Converts {@link DisconnectCause} to {@link LastCallFailCause}. 1227 * 1228 * @param cause The disconnect cause code. 1229 * @return The converted call fail cause. 1230 */ convertToLastCallFailCause( @nnotation.DisconnectCauses int cause)1231 private @LastCallFailCause int convertToLastCallFailCause( 1232 @Annotation.DisconnectCauses int cause) { 1233 switch (cause) { 1234 case DisconnectCause.BUSY: 1235 return LastCallFailCause.BUSY; 1236 case DisconnectCause.CONGESTION: 1237 return LastCallFailCause.TEMPORARY_FAILURE; 1238 case DisconnectCause.NORMAL: 1239 return LastCallFailCause.NORMAL; 1240 case DisconnectCause.POWER_OFF: 1241 return LastCallFailCause.RADIO_OFF; 1242 case DisconnectCause.EMERGENCY_TEMP_FAILURE: 1243 return EMERGENCY_TEMP_FAILURE; 1244 case DisconnectCause.EMERGENCY_PERM_FAILURE: 1245 return EMERGENCY_PERM_FAILURE; 1246 default: 1247 return LastCallFailCause.ERROR_UNSPECIFIED; 1248 } 1249 } 1250 } 1251