1 /** 2 * Copyright (C) 2010 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 /** 18 * The Radio object contains a set of methods and objects to handle ril request 19 * which is passed from simulatedRadioWorker queue. The global object initialize 20 * an instance of Radio object by calling "new Radio". For each ril request, 21 * rilDispatchTable gets searched and the corresponding method is called. 22 * Extra requests are also defined to process unsolicited rerequests. 23 * 24 * The rilDispatchTable is an array indexed by RIL_REQUEST_* or REQUEST_UNSOL_*, 25 * in which each request corresponds to a functions defined in the Radio object. 26 * We need to pay attention when using "this" within those functions. When they are 27 * called in "this.process" using 28 * result = this.radioDispatchTable[req.reqNum])(req); 29 * this scope of "this" within those functions are the radioDispatchTable, not the 30 * object that "this.process" belongs to. Using "this." to access other 31 * functions in the object may cause trouble. 32 * To avoid that, the object is passed in when those functions are called as 33 * shown in the following: 34 * result = (this.radioDispatchTable[req.reqNum]).call(this, req); 35 */ 36 37 /** 38 * Set radio state 39 */ 40 function setRadioState(newState) { 41 newRadioState = newState; 42 if (typeof newState == 'string') { 43 newRadioState = globals[newState]; 44 if (typeof newRadioState == 'undefined') { 45 throw('setRadioState: Unknow string: ' + newState); 46 } 47 } 48 if ((newRadioState < RADIOSTATE_OFF) || (newRadioState > RADIOSTATE_NV_READY)) { 49 throw('setRadioState: newRadioState: ' + newRadioState + ' is invalid'); 50 } 51 gRadioState = newRadioState; 52 sendRilUnsolicitedResponse(RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED); 53 } 54 55 /** 56 * Create a call. 57 * 58 * @return a RilCall 59 */ 60 function RilCall(state, phoneNumber, callerName) { 61 this.state = state; 62 this.index = 0; 63 this.toa = 0; 64 this.isMpty = false; 65 this.isMt = false; 66 this.als = 0; 67 this.isVoice = true; 68 this.isVoicePrivacy = false; 69 this.number = phoneNumber; 70 this.numberPresentation = 0; 71 this.name = callerName; 72 } 73 74 /** 75 * Simulated Radio 76 */ 77 function Radio() { 78 var registrationState = '1'; 79 var lac = '0'; 80 var cid = '0'; 81 var radioTechnology = '3'; 82 var baseStationId = NULL_RESPONSE_STRING; 83 var baseStationLatitude = NULL_RESPONSE_STRING; 84 var baseStationLongitude = NULL_RESPONSE_STRING; 85 var concurrentServices = NULL_RESPONSE_STRING; 86 var systemId = NULL_RESPONSE_STRING; 87 var networkId = NULL_RESPONSE_STRING; 88 var roamingIndicator = NULL_RESPONSE_STRING; 89 var prlActive = NULL_RESPONSE_STRING; 90 var defaultRoamingIndicator = NULL_RESPONSE_STRING; 91 var registrationDeniedReason = NULL_RESPONSE_STRING; 92 var primaryScrambingCode = NULL_RESPONSE_STRING; 93 94 var NETWORK_SELECTION_MODE_AUTOMATIC = 0; 95 var NETWORK_SELECTION_MODE_MANUAL = 1; 96 var networkSelectionMode = NETWORK_SELECTION_MODE_AUTOMATIC; 97 98 var muteState = 0; // disable mute 99 100 // Number of active calls in calls 101 var numberActiveCalls = 0; 102 103 // Maximum number of active calls 104 var maxNumberActiveCalls = 7; 105 var maxConnectionsPerCall = 5; // only 5 connections allowed per call 106 107 // Flag to denote whether an incoming/waiting call is answered 108 var incomingCallIsProcessed = false; 109 110 // Call transition flag 111 var callTransitionFlag = false; // default to auto-transition 112 113 var lastCallFailCause = 0; 114 115 // Array of "active" calls 116 var calls = Array(maxNumberActiveCalls + 1); 117 118 // The result returned by the request handlers 119 var result = new Object(); 120 121 function GWSignalStrength() { 122 this.signalStrength = 10; // 10 * 2 + (-113) = -93dBm, make it three bars 123 this.bitErrorRate = 0; 124 } 125 126 function CDMASignalStrength() { 127 this.dbm = -1; 128 this.ecio = -1; 129 } 130 131 function EVDOSignalStrength() { 132 this.dbm = -1; 133 this.ecio = -1; 134 this.signalNoiseRatio = 0; 135 } 136 137 function LTESignalStrength() { 138 this.signalStrength = -1; 139 this.rsrp = 0; 140 this.rsrq = 0; 141 this.rssnr = 0; 142 this.cqi = 0; 143 } 144 145 var gwSignalStrength = new GWSignalStrength; 146 var cdmaSignalStrength = new CDMASignalStrength(); 147 var evdoSignalStrength = new EVDOSignalStrength(); 148 var lteSignalStrength = new LTESignalStrength(); 149 150 /** 151 * The the array of calls, this is a sparse 152 * array and some elements maybe 'undefined'. 153 * 154 * @return Array of RilCall's 155 */ 156 this.getCalls = function() { 157 return calls; 158 } 159 160 /** 161 * @return the RilCall at calls[index] or null if undefined. 162 */ 163 this.getCall = function(index) { 164 var c = null; 165 try { 166 c = calls[index]; 167 if (typeof c == 'undefined') { 168 c = null; 169 } 170 } catch (err) { 171 c = null; 172 } 173 return c; 174 } 175 176 /** 177 * @return the first call that is in the given state 178 */ 179 this.getCallIdByState = function(callState) { 180 if ((callState < CALLSTATE_ACTIVE) || (callState > CALLSTATE_WAITING)) { 181 return null; 182 } 183 for (var i = 0; i < calls.length; i++) { 184 if (typeof calls[i] != 'undefined') { 185 if (calls[i].state == callState) { 186 return i; 187 } 188 } 189 } 190 return null; 191 } 192 193 /** Add an active call 194 * 195 * @return a RilCall or null if too many active calls. 196 */ 197 this.addCall = function(state, phoneNumber, callerName) { 198 print('Radio: addCall'); 199 var c = null; 200 if (numberActiveCalls < maxNumberActiveCalls) { 201 numberActiveCalls += 1; 202 c = new RilCall(state, phoneNumber, callerName); 203 // call index should fall in the closure of [1, 7] 204 // Search for an "undefined" element in the array and insert the call 205 for (var i = 1; i < (maxNumberActiveCalls + 1); i++) { 206 print('Radio: addCall, i=' + i); 207 if (typeof calls[i] == 'undefined') { 208 print('Radio: addCall, calls[' + i + '] is undefined'); 209 c.index = i; 210 calls[i] = c; 211 break; 212 } 213 } 214 this.printCalls(calls); 215 } 216 return c; 217 } 218 219 /** 220 * Remove the call, does nothing if the call is undefined. 221 * 222 * @param index into calls to remove. 223 * @return the call removed or null if did not exist 224 */ 225 this.removeCall = function(index) { 226 var c = null; 227 if ((numberActiveCalls > 0) 228 && (index < calls.length) 229 && (typeof calls[index] != 'undefined')) { 230 c = calls[index]; 231 delete calls[index]; 232 numberActiveCalls -= 1; 233 if (numberActiveCalls == 0) { 234 calls = new Array(); 235 } 236 } else { 237 c = null; 238 } 239 return c; 240 } 241 242 /** 243 * Print the call 244 * 245 * @param c is the RilCall to print 246 */ 247 this.printCall = function(c) { 248 if ((c != null) && (typeof c != 'undefined')) { 249 print('c[' + c.index + ']: index=' + c.index + ' state=' + c.state + 250 ' number=' + c.number + ' name=' + c.name); 251 } 252 } 253 254 /** 255 * Print all the calls. 256 * 257 * @param callArray is an Array of RilCall's 258 */ 259 this.printCalls = function(callArray) { 260 if (typeof callArray == 'undefined') { 261 callArray = calls; 262 } 263 print('callArray.length=' + callArray.length); 264 for (var i = 0; i < callArray.length; i++) { 265 if ((callArray[i] == null) || (typeof callArray[i] == 'undefined')) { 266 print('c[' + i + ']: undefined'); 267 } else { 268 this.printCall(callArray[i]); 269 } 270 } 271 } 272 273 /** 274 * Count number of calls in the given state 275 * 276 * @param callState is the give state 277 */ 278 this.countCallsInState = function(callState) { 279 var count = 0; 280 if ((callState < CALLSTATE_ACTIVE) || (callState > CALLSTATE_WAITING)) { 281 // not a valid call state 282 return null; 283 } 284 for (var i = 0; i < calls.length; i++) { 285 if (typeof calls[i] != 'undefined') { 286 if (calls[i].state == callState) { 287 count++; 288 } 289 } 290 } 291 return count; 292 } 293 294 /** 295 * Print signal strength 296 */ 297 this.printSignalStrength = function() { 298 print('rssi: ' + gwSignalStrength.signalStrength); 299 print('bitErrorRate: ' + gwSignalStrength.bitErrorRate); 300 print('cdmaDbm: ' + cdmaSignalStrength.dbm); 301 print('cdmaEcio: ' + cdmaSignalStrength.ecio); 302 print('evdoRssi: ' + evdoSignalStrength.dbm); 303 print('evdoEcio: ' + evdoSignalStrength.ecio); 304 print('evdoSnr: ' + evdoSignalStrength.signalNoiseRatio); 305 print('lteRssi: ' + lteSignalStrength.signalStrength); 306 print('lteRsrp: ' + lteSignalStrength.rsrp); 307 print('lteRsrq: ' + lteSignalStrength.rsrq); 308 print('lteRssnr: ' + lteSignalStrength.rssnr); 309 print('lteCqi: ' + lteSignalStrength.cqi); 310 } 311 312 /** 313 * set signal strength 314 * 315 * @param rssi and bitErrorRate are signal strength parameters for GSM 316 * cdmaDbm, cdmaEcio, evdoRssi, evdoEcio, evdoSnr are parameters for CDMA & EVDO 317 */ 318 this.setSignalStrength = function(rssi, bitErrorRate, cdmaDbm, cdmaEcio, evdoRssi, 319 evdoEcio, evdoSnr, lteSigStrength, lteRsrp, 320 lteRsrq, lteRssnr, lteCqi) { 321 print('setSignalStrength E'); 322 323 if (rssi != 99) { 324 if ((rssi < 0) || (rssi > 31)) { 325 throw ('not a valid signal strength'); 326 } 327 } 328 // update signal strength 329 gwSignalStrength.signalStrength = rssi; 330 gwSignalStrength.bitErrorRate = bitErrorRate; 331 cdmaSignalStrength.dbm = cdmaDbm; 332 cdmaSignalStrength.ecio = cdmaEcio; 333 evdoSignalStrength.dbm = evdoRssi; 334 evdoSignalStrength.ecio = evdoEcio; 335 evdoSignalStrength.signalNoiseRatio = evdoSnr; 336 lteSignalStrength.signalStrength = lteSigStrength; 337 lteSignalStrength.rsrp = lteRsrp; 338 lteSignalStrength.rsrq = lteRsrq; 339 lteSignalStrength.rssnr = lteRssnr; 340 lteSignalStrength.cqi = lteCqi; 341 342 // pack the signal strength into RspSignalStrength and send a unsolicited response 343 var rsp = new Object(); 344 345 rsp.gwSignalstrength = gwSignalStrength; 346 rsp.cdmSignalstrength = cdmaSignalStrength; 347 rsp.evdoSignalstrength = evdoSignalStrength; 348 rsp.lteSignalstrength = lteSignalStrength; 349 350 var response = rilSchema[packageNameAndSeperator + 351 'RspSignalStrength'].serialize(rsp); 352 353 sendRilUnsolicitedResponse(RIL_UNSOL_SIGNAL_STRENGTH, response); 354 355 // send the unsolicited signal strength every 1 minute. 356 simulatedRadioWorker.addDelayed( 357 {'reqNum' : CMD_UNSOL_SIGNAL_STRENGTH}, 60000); 358 print('setSignalStrength X'); 359 } 360 361 /** 362 * Handle RIL_REQUEST_GET_CURRENT_CALL 363 * 364 * @param req is the Request 365 */ 366 this.rilRequestGetCurrentCalls = function(req) { // 9 367 print('Radio: rilRequestGetCurrentCalls E'); 368 var rsp = new Object(); 369 370 // pack calls into rsp.calls 371 rsp.calls = new Array(); 372 var i; 373 var j; 374 for (i = 0, j = 0; i < calls.length; i++) { 375 if (typeof calls[i] != 'undefined') { 376 rsp.calls[j++] = calls[i]; 377 } 378 } 379 result.responseProtobuf = rilSchema[packageNameAndSeperator + 380 'RspGetCurrentCalls'].serialize(rsp); 381 return result; 382 } 383 384 /** 385 * Handle RIL_REQUEST_DIAL 386 * 387 * @param req is the Request 388 */ 389 this.rilRequestDial = function(req) { // 10 390 print('Radio: rilRequestDial E'); 391 var newCall = new Object(); 392 newCall = this.addCall(CALLSTATE_DIALING, req.data.address, ''); 393 if (newCall == null) { 394 result.rilErrCode = RIL_E_GENERIC_FAILURE; 395 return result; 396 } 397 this.printCalls(calls); 398 399 print('after add the call'); 400 // Set call state to dialing 401 simulatedRadioWorker.add( 402 {'reqNum' : CMD_CALL_STATE_CHANGE, 403 'callType' : OUTGOING, 404 'callIndex' : newCall.index, 405 'nextState' : CALLSTATE_DIALING}); 406 if (!callTransitionFlag) { 407 // for auto transition 408 // Update call state to alerting after 1 second 409 simulatedRadioWorker.addDelayed( 410 {'reqNum' : CMD_CALL_STATE_CHANGE, 411 'callType' : OUTGOING, 412 'callIndex' : newCall.index, 413 'nextState' : CALLSTATE_ALERTING}, 1000); 414 // Update call state to active after 2 seconds 415 simulatedRadioWorker.addDelayed( 416 {'reqNum' : CMD_CALL_STATE_CHANGE, 417 'callType' : OUTGOING, 418 'callIndex': newCall.index, 419 'nextState' : CALLSTATE_ACTIVE}, 2000); 420 } 421 return result; 422 } 423 424 /** 425 * Handle RIL_REQUEST_HANG_UP 426 * 427 * @param req is the Request 428 */ 429 this.rilRequestHangUp = function(req) { // 12 430 print('Radio: rilRequestHangUp data.connection_index=' + req.data.connectionIndex); 431 if (this.removeCall(req.data.connectionIndex) == null) { 432 result.rilErrCode = RIL_E_GENERIC_FAILURE; 433 print('no connection to hangup'); 434 } 435 return result; 436 } 437 438 /** 439 * Handle RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND 440 * Hang up waiting or held 441 * 442 * @param req is the Request 443 */ 444 this.rilRequestHangupWaitingOrBackground = function(req) { // 13 445 print('Radio: rilRequestHangupWaitingOrBackground'); 446 if (numberActiveCalls <= 0) { 447 result.rilErrCode = RIL_E_GENERIC_FAILURE; 448 } else { 449 for (var i = 0; i < calls.length; i++) { 450 if (typeof calls[i] != 'undefined') { 451 switch (calls[i].state) { 452 case CALLSTATE_HOLDING: 453 case CALLSTATE_WAITING: 454 case CALLSTATE_INCOMING: 455 this.removeCall(i); 456 incomingCallIsProcessed = true; 457 break; 458 default: 459 result.rilErrCode = RIL_E_GENERIC_FAILURE; 460 break; 461 } 462 this.printCalls(calls); 463 if(result.rilErrCode == RIL_E_GENERIC_FAILURE) { 464 return result; 465 } 466 } // end of processing call[i] 467 } // end of for 468 } 469 // Send out RIL_UNSOL_CALL_STATE_CHANGED after the request is returned 470 simulatedRadioWorker.add( 471 {'reqNum' : CMD_UNSOL_CALL_STATE_CHANGED}); 472 return result; 473 } 474 475 /** 476 * Handle RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND 477 * release all active calls (if any exist) and resume held or waiting calls. 478 * @param req is the Request 479 */ 480 this.rilRequestHangUpForegroundResumeBackground = function(req) { //14 481 print('Radio: rilRequestHangUpForegroundResumeBackground'); 482 if (numberActiveCalls <= 0) { 483 result.rilErrCode = RIL_E_GENERIC_FAILURE; 484 } else { 485 for (var i = 0; i < calls.length; i++) { 486 if (typeof calls[i] != 'undefined') { 487 switch (calls[i].state) { 488 case CALLSTATE_ACTIVE: 489 this.removeCall(i); 490 break; 491 case CALLSTATE_HOLDING: 492 case CALLSTATE_WAITING: 493 calls[i].state = CALLSTATE_ACTIVE; 494 break; 495 default: 496 result.rilErrCode = RIL_E_GENERIC_FAILURE; 497 break; 498 } 499 this.printCalls(calls); 500 if(result.rilErrCode == RIL_E_GENERIC_FAILURE) { 501 return result; 502 } 503 } // end of processing call[i] 504 } 505 } 506 // Send out RIL_UNSOL_CALL_STATE_CHANGED after the request is returned 507 simulatedRadioWorker.add( 508 {'reqNum' : CMD_UNSOL_CALL_STATE_CHANGED}); 509 return result; 510 } 511 512 /** 513 * Handle RIL_REQUEST_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE 514 * 515 * BEFORE AFTER 516 * Call 1 Call 2 Call 1 Call 2 517 * ACTIVE HOLDING HOLDING ACTIVE 518 * ACTIVE WAITING HOLDING ACTIVE 519 * HOLDING WAITING HOLDING ACTIVE 520 * ACTIVE IDLE HOLDING IDLE 521 * IDLE IDLE IDLE IDLE 522 * 523 * @param req is the Request 524 */ 525 this.rilRequestSwitchWaitingOrHoldingAndActive = function(req) { // 15 526 print('Radio: rilRequestSwitchWaitingOrHoldingAndActive'); 527 print('Radio: lastReq = ' + lastReq); 528 print('Radio: req.reqNum = ' + req.reqNum); 529 if (lastReq == req.reqNum) { 530 print('Radio: called twice'); 531 return result; 532 } 533 534 if (numberActiveCalls <= 0) { 535 result.rilErrCode = RIL_E_GENERIC_FAILURE; 536 } else { 537 for (var i = 0; i < calls.length; i++) { 538 if (typeof calls[i] != 'undefined') { 539 switch (calls[i].state) { 540 case CALLSTATE_ACTIVE: 541 calls[i].state = CALLSTATE_HOLDING; 542 break; 543 case CALLSTATE_HOLDING: 544 case CALLSTATE_WAITING: 545 calls[i].state = CALLSTATE_ACTIVE; 546 break; 547 default: 548 result.rilErrCode = RIL_E_GENERIC_FAILURE; 549 break; 550 } 551 this.printCalls(calls); 552 if(result.rilErrCode == RIL_E_GENERIC_FAILURE) { 553 return result; 554 } 555 } // end of processing call[i] 556 } // end of for 557 } 558 // Send out RIL_UNSOL_CALL_STATE_CHANGED after the request is returned 559 simulatedRadioWorker.add( 560 {'reqNum' : CMD_UNSOL_CALL_STATE_CHANGED}); 561 return result; 562 } 563 564 /** 565 * Handle RIL_REQUEST_CONFERENCE 566 * Conference holding and active 567 * 568 * @param req is the Request 569 */ 570 this.rilRequestConference = function(req) { // 16 571 print('Radio: rilRequestConference E'); 572 if ((numberActiveCalls <= 0) || (numberActiveCalls > maxConnectionsPerCall)) { 573 // The maximum number of connections within a call is 5 574 result.rilErrCode = RIL_E_GENERIC_FAILURE; 575 return result; 576 } else { 577 var numCallsInBadState = 0; 578 for (var i = 0; i < calls.length; i++) { 579 if (typeof calls[i] != 'undefined') { 580 if ((calls[i].state != CALLSTATE_ACTIVE) && 581 (calls[i].state != CALLSTATE_HOLDING)) { 582 numCallsInBadState++; 583 } 584 } 585 } 586 587 // if there are calls not in ACITVE or HOLDING state, return error 588 if (numCallsInBadState > 0) { 589 result.rilErrCode = RIL_E_GENERIC_FAILURE; 590 return result; 591 } else { // conference ACTIVE and HOLDING calls 592 for (var i = 0; i < calls.length; i++) { 593 if (typeof calls[i] != 'undefined') { 594 switch (calls[i].state) { 595 case CALLSTATE_ACTIVE: 596 break; 597 case CALLSTATE_HOLDING: 598 calls[i].state = CALLSTATE_ACTIVE; 599 break; 600 default: 601 result.rilErrCode = RIL_E_GENERIC_FAILURE; 602 break; 603 } 604 } 605 this.printCalls(calls); 606 if(result.rilErrCode == RIL_E_GENERIC_FAILURE) { 607 return result; 608 } 609 } 610 } 611 } 612 613 // Only if conferencing is successful, 614 // Send out RIL_UNSOL_CALL_STATE_CHANGED after the request is returned 615 simulatedRadioWorker.add( 616 {'reqNum' : CMD_UNSOL_CALL_STATE_CHANGED}); 617 return result; 618 } 619 620 /** 621 * Handle RIL_REQUEST_LAST_CALL_FAIL_CAUSE 622 * 623 * @param req is the request 624 */ 625 this.rilRequestLastCallFailCause = function(req) { 626 print('Radio: rilRequestLastCallFailCause E'); 627 628 var rsp = new Object(); 629 rsp.integers = new Array(); 630 rsp.integers[0] = lastCallFailCause; 631 632 result.responseProtobuf = rilSchema[packageNameAndSeperator + 633 'RspIntegers'].serialize(rsp); 634 return result; 635 } 636 637 /** 638 * Handle RIL_REQUEST_SIGNAL_STRENGTH 639 * 640 * @param req is the Request 641 */ 642 this.rilRequestSignalStrength = function(req) { // 19 643 print('Radio: rilRequestSignalStrength E'); 644 var rsp = new Object(); 645 646 // pack the signal strength into RspSignalStrength 647 rsp.gwSignalstrength = gwSignalStrength; 648 rsp.cdmaSignalstrength = cdmaSignalStrength; 649 rsp.evdoSignalstrength = evdoSignalStrength; 650 651 result.responseProtobuf = rilSchema[packageNameAndSeperator + 652 'RspSignalStrength'].serialize(rsp); 653 return result; 654 } 655 656 /** 657 * Handle RIL_REQUEST_VOICE_REGISTRATION_STATE 658 * 659 * @param req is the Request 660 */ 661 this.rilRequestVoiceRegistrationState = function(req) { // 20 662 print('Radio: rilRequestVoiceRegistrationState'); 663 664 var rsp = new Object(); 665 rsp.strings = Array(); 666 rsp.strings[0] = registrationState; 667 rsp.strings[1] = lac; 668 rsp.strings[2] = cid; 669 rsp.strings[3] = radioTechnology; 670 rsp.strings[4] = baseStationId; 671 rsp.strings[5] = baseStationLatitude; 672 rsp.strings[6] = baseStationLongitude; 673 rsp.strings[7] = concurrentServices; 674 rsp.strings[8] = systemId; 675 rsp.strings[9] = networkId; 676 rsp.strings[10] = roamingIndicator; 677 rsp.strings[11] = prlActive; 678 rsp.strings[12] = defaultRoamingIndicator; 679 rsp.strings[13] = registrationDeniedReason; 680 rsp.strings[14] = primaryScrambingCode; 681 682 result.responseProtobuf = rilSchema[packageNameAndSeperator + 683 'RspStrings'].serialize(rsp); 684 return result; 685 } 686 687 /** 688 * Handle RIL_REQUEST_DATA_REGISTRATION_STATE 689 * 690 * @param req is the Request 691 */ 692 this.rilRequestDataRegistrationState = function(req) { // 21 693 print('Radio: rilRequestDataRegistrationState'); 694 695 var rsp = new Object(); 696 rsp.strings = Array(); 697 rsp.strings[0] = registrationState; 698 rsp.strings[1] = lac; 699 rsp.strings[2] = cid; 700 rsp.strings[3] = radioTechnology; 701 702 result.responseProtobuf = rilSchema[packageNameAndSeperator + 703 'RspStrings'].serialize(rsp); 704 return result; 705 } 706 707 /** 708 * Handle RIL_REQUEST_ANSWER 709 * 710 * @param req is the Request 711 */ 712 this.rilRequestAnswer = function(req) { // 40 713 print('Radio: rilRequestAnswer'); 714 715 if (numberActiveCalls != 1) { 716 result.rilErrCode = RIL_E_GENERIC_FAILURE; 717 return result; 718 } else { 719 for (var i = 0; i < calls.length; i++) { 720 if (typeof calls[i] != 'undefined') { 721 if (calls[i].state == CALLSTATE_INCOMING) { 722 calls[i].state = CALLSTATE_ACTIVE; 723 break; 724 } else { 725 result.rilErrCode = RIL_E_GENERIC_FAILURE; 726 this.removeCall(i); 727 return result; 728 } 729 } // end of processing call[i] 730 } // end of for 731 } 732 incomingCallIsProcessed = true; 733 return result; 734 } 735 736 /** 737 * Handle RIL_REQUEST_QUERY_NETWORK_SELECTION_MODE 738 * 739 * @param req is the Request 740 */ 741 this.rilRequestQueryNeworkSelectionMode = function(req) { // 45 742 print('Radio: rilRequestQueryNeworkSelectionMode'); 743 744 var rsp = new Object(); 745 rsp.integers = Array(); 746 rsp.integers[0] = networkSelectionMode; 747 748 result.responseProtobuf = rilSchema[packageNameAndSeperator + 749 'RspIntegers'].serialize(rsp); 750 return result; 751 } 752 753 /** 754 * Handle RIL_REQUEST_SET_NETWORK_SELECTION_AUTOMATIC 755 * 756 * @param req is the Request 757 */ 758 this.rilRequestSetNeworkSelectionAutomatic = function(req) { // 46 759 print('Radio: rilRequestSetNeworkSelectionAutomatic'); 760 761 networkSelectionMode = NETWORK_SELECTION_MODE_AUTOMATIC; 762 763 return result; 764 } 765 766 /** 767 * Handle RIL_REQUEST_BASE_BAND_VERSION 768 * 769 * @param req is the Request 770 */ 771 this.rilRequestBaseBandVersion = function(req) { // 51 772 print('Radio: rilRequestBaseBandVersion'); 773 var rsp = new Object(); 774 rsp.strings = Array(); 775 rsp.strings[0] = gBaseBandVersion; 776 777 result.responseProtobuf = rilSchema[packageNameAndSeperator + 778 'RspStrings'].serialize(rsp); 779 return result; 780 } 781 782 /** 783 * Handle RIL_REQUEST_SEPRATE_CONNECTION 784 * Separate a party from a multiparty call placing the multiparty call 785 * (less the specified party) on hold and leaving the specified party 786 * as the only other member of the current (active) call 787 * 788 * See TS 22.084 1.3.8.2 (iii) 789 * 790 * @param req is the Request 791 */ 792 this.rilReqestSeparateConnection = function(req) { // 52 793 print('Radio: rilReqestSeparateConnection'); 794 var index = req.data.index; 795 796 if (numberActiveCalls <= 0) { 797 result.rilErrCode = RIL_E_GENERIC_FAILURE; 798 return result; 799 } else { 800 // get the connection to separate 801 var separateConn = this.getCall(req.data.index); 802 if (separateConn == null) { 803 result.rilErrCode = RIL_E_GENERIC_FAILURE; 804 return result; 805 } else { 806 if (separateConn.state != CALLSTATE_ACTIVE) { 807 result.rilErrCode = RIL_E_GENERIC_FAILURE; 808 return result; 809 } 810 // Put all other connections in hold. 811 for (var i = 0; i < calls.length; i++) { 812 if (index != i) { 813 // put all the active call to hold 814 if (typeof calls[i] != 'undefined') { 815 switch (calls[i].state) { 816 case CALLSTATE_ACTIVE: 817 calls[i].state = CALLSTATE_HOLDING; 818 break; 819 default: 820 result.rilErrCode = RIL_E_GENERIC_FAILURE; 821 break; 822 } 823 this.printCalls(calls); 824 if(result.rilErrCode == RIL_E_GENERIC_FAILURE) { 825 return result; 826 } 827 } // end of processing call[i] 828 } 829 } // end of for 830 } 831 } 832 833 // Send out RIL_UNSOL_CALL_STATE_CHANGED after the request is returned 834 simulatedRadioWorker.add( 835 {'reqNum' : CMD_UNSOL_CALL_STATE_CHANGED}); 836 return result; 837 } 838 839 /** 840 * Handle RIL_REQUEST_SET_MUTE 841 */ 842 this.rilRequestSetMute = function(req) { // 53 843 print('Radio: rilRequestSetMute: req.data.state=' + req.data.state); 844 muteState = req.data.state; 845 if (gRadioState == RADIOSTATE_UNAVAILABLE) { 846 result.rilErrCode = RIL_E_RADIO_NOT_AVAILABLE; 847 } 848 return result; 849 } 850 851 /** 852 * Handle RIL_REQUEST_SCREEN_STATE 853 * 854 * @param req is the Request 855 */ 856 this.rilRequestScreenState = function(req) { // 61 857 print('Radio: rilRequestScreenState: req.data.state=' + req.data.state); 858 screenState = req.data.state; 859 return result; 860 } 861 862 /** 863 * Delay test 864 */ 865 this.cmdDelayTest = function(req) { // 2000 866 print('cmdDelayTest: req.hello=' + req.hello); 867 result.sendResponse = false; 868 return result; 869 } 870 871 /** 872 * Delay for RIL_UNSOL_SIGNAL_STRENGTH 873 * TODO: Simulate signal strength changes: 874 * Method 1: provide an array for signal strength, and send the unsolicited 875 * reponse periodically (the period can also be simulated) 876 * Method 2: Simulate signal strength randomly (within a certain range) and 877 * send the response periodically. 878 */ 879 this.cmdUnsolSignalStrength = function(req) { // 2001 880 print('cmdUnsolSignalStrength: req.reqNum=' + req.reqNum); 881 var rsp = new Object(); 882 883 // pack the signal strength into RspSignalStrength 884 rsp.gwSignalstrength = gwSignalStrength; 885 rsp.cdmaSignalstrength = cdmaSignalStrength; 886 rsp.evdoSignalstrength = evdoSignalStrength; 887 888 response = rilSchema[packageNameAndSeperator + 889 'RspSignalStrength'].serialize(rsp); 890 891 // upldate signal strength 892 sendRilUnsolicitedResponse(RIL_UNSOL_SIGNAL_STRENGTH, response); 893 894 // Send the unsolicited signal strength every 1 minute. 895 simulatedRadioWorker.addDelayed( 896 {'reqNum' : CMD_UNSOL_SIGNAL_STRENGTH}, 60000); 897 898 // this is not a request, no response is needed 899 result.sendResponse = false; 900 return result; 901 } 902 903 /** 904 * Send RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED 905 */ 906 this.cmdUnsolCallStateChanged = function(req) { // 2002 907 print('cmdUnsolCallStateChanged: req.reqNum=' + req.reqNum); 908 sendRilUnsolicitedResponse(RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED); 909 result.sendResponse = false; 910 return result; 911 } 912 913 /** 914 * Simulate call state change 915 */ 916 this.cmdCallStateChange = function(req) { // 2003 917 print('cmdCallStateChange: req.reqNum=' + req.reqNum); 918 print('cmdCallStateChange: req.callType=' + req.callType); 919 print('cmdCallStateChange: req.callIndex=' + req.callIndex); 920 print('cmdCallStateChange: req.nextState=' + req.nextState); 921 922 // if it is an outgoing call, update the call state of the call 923 // Send out call state changed flag 924 var curCall = this.getCall(req.callIndex); 925 this.printCall(curCall); 926 927 if (curCall != null) { 928 curCall.state = req.nextState; 929 } else { 930 this.removeCall(req.callIndex); 931 } 932 933 // TODO: if it is an incoming call, update the call state of the call 934 // Send out call state change flag 935 // Send out RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED 936 simulatedRadioWorker.add( 937 {'reqNum' : CMD_UNSOL_CALL_STATE_CHANGED}); 938 result.sendResponse = false; 939 return result; 940 } 941 942 /** 943 * send UNSOL_CALL_STATE_CHANGED and UNSOL_CALL_RING 944 */ 945 this.cmdUnsolCallRing = function(req) { // 2004 946 print('cmdUnsolCallRing: req.reqNum=' + req.reqNum); 947 if(!incomingCallIsProcessed) { 948 sendRilUnsolicitedResponse(RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED); 949 sendRilUnsolicitedResponse(RIL_UNSOL_CALL_RING); 950 951 // Send the next alert in 3 seconds. [refer to ril.h definition] 952 simulatedRadioWorker.addDelayed( 953 {'reqNum' : CMD_UNSOL_CALL_RING}, 3000); 954 } 955 result.sendResponse = false; 956 return result; 957 } 958 959 /** 960 * Create an incoming call for the giving number 961 * return CTRL_STATUS_ERR if there is already a call in any of the states of 962 * dialing, alerting, incoming, waiting [TS 22 030 6.5] , else 963 * return CTRL_STATUS_OK and update the call state 964 */ 965 this.ctrlServerCmdStartInComingCall = function(req) { // 1001 966 print('ctrlServerCmdStartInComingCall: req.reqNum:' + req.reqNum); 967 print('ctrlServerCmdStartInComingCall: req.data.phonenumber:' + req.data.phoneNumber); 968 969 var phoneNumber = req.data.phoneNumber; 970 var state; 971 972 if (numberActiveCalls <= 0) { 973 // If there is no connection in use, the call state is INCOMING 974 state = CALLSTATE_INCOMING; 975 } else { 976 // If there is call in any of the states of dialing, alerting, incoming 977 // waiting, this MT call can not be set 978 for (var i = 0; i < calls.length; i++) { 979 if (typeof calls[i] != 'undefined') { 980 if ( (calls[i].state == CALLSTATE_DIALING) || 981 (calls[i].state == CALLSTATE_ALERTING) || 982 (calls[i].state == CALLSTATE_INCOMING) || 983 (calls[i].state == CALLSTATE_WAITING)) 984 { 985 result.rilErrCode = CTRL_STATUS_ERR; 986 return result; 987 } 988 } 989 } 990 // If the incoming call is a second call, the state is WAITING 991 state = CALLSTATE_WAITING; 992 } 993 994 // Add call to the call array 995 this.addCall(state, phoneNumber, ''); 996 997 // set the incomingCallIsProcessed flag to be false 998 incomingCallIsProcessed = false; 999 1000 simulatedRadioWorker.add( 1001 {'reqNum' : CMD_UNSOL_CALL_RING}); 1002 1003 result.rilErrCode = CTRL_STATUS_OK; 1004 return result; 1005 } 1006 1007 /** 1008 * Handle control command CTRL_CMD_HANGUP_CONN_REMOTE 1009 * hangup the connection for the given failure cause 1010 * 1011 *@param req is the control request 1012 */ 1013 this.ctrlServerCmdHangupConnRemote = function(req) { // 1002 1014 print('ctrlServerCmdHangupConnRemote: req.data.connectionId=' + req.data.connectionId + 1015 ' req.data.callFailCause' + req.data.callFailCause); 1016 1017 var connection = req.data.connectionId; 1018 var failureCause = req.data.callFailCause; 1019 1020 this.printCalls(calls); 1021 var hangupCall = this.removeCall(connection); 1022 if (hangupCall == null) { 1023 print('ctrlServerCmdHangupConnRemote: connection id is required.'); 1024 result.rilErrCode = CTRL_STATUS_ERR; 1025 return result; 1026 } else { 1027 // for incoming call, stop sending call ring 1028 if ((hangupCall.state == CALLSTATE_INCOMING) || 1029 (hangupCall.state == CALLSTATE_WAITING)) { 1030 incomingCallIsProcessed = true; 1031 } 1032 } 1033 this.printCalls(calls); 1034 lastCallFailCause = failureCause; 1035 1036 // send out call state changed response 1037 simulatedRadioWorker.add( 1038 {'reqNum' : CMD_UNSOL_CALL_STATE_CHANGED}); 1039 1040 result.rilErrCode = CTRL_STATUS_OK; 1041 return result; 1042 } 1043 1044 /** 1045 * Set call transition flag 1046 */ 1047 this.ctrlServerCmdSetCallTransitionFlag = function(req) { // 1003 1048 print('ctrlServerCmdSetCallTransitionFlag: flag=' + req.data.flag); 1049 1050 callTransitionFlag = req.data.flag; 1051 result.rilErrCode = CTRL_STATUS_OK; 1052 return result; 1053 } 1054 1055 /** 1056 * Set the dialing call to alert 1057 */ 1058 this.ctrlServerCmdSetCallAlert = function(req) { // 1004 1059 print('ctrlServerCmdSetCallAlert: E'); 1060 1061 if (callTransitionFlag == false) { 1062 print('ctrlServerCmdSetCallAlert: need to set the flag first'); 1063 result.rilErrCode = CTRL_STATUS_ERR; 1064 return result; 1065 } 1066 if (numberActiveCalls <= 0) { 1067 print('ctrlServerCmdSetCallAlert: no active calls'); 1068 result.rilErrCode = CTRL_STATUS_ERR; 1069 return result; 1070 } 1071 var dialingCalls = this.countCallsInState(CALLSTATE_DIALING); 1072 var index = this.getCallIdByState(CALLSTATE_DIALING); 1073 if ((dialingCalls == 1) && (index != null)) { 1074 calls[index].state = CALLSTATE_ALERTING; 1075 } else { 1076 // if there 0 or more than one call in dialing state, return error 1077 print('ctrlServerCmdSetCallAlert: no valid calls in dialing state'); 1078 result.rilErrCode = CTRL_STATUS_ERR; 1079 return result; 1080 } 1081 // send unsolicited call state change response 1082 simulatedRadioWorker.add( 1083 {'reqNum' : CMD_UNSOL_CALL_STATE_CHANGED}); 1084 1085 result.rilErrCode = CTRL_STATUS_OK; 1086 return result; 1087 } 1088 1089 /** 1090 * Set the alserting call to active 1091 */ 1092 this.ctrlServerCmdSetCallActive = function(req) { // 1005 1093 print('ctrlServerCmdSetCallActive: E'); 1094 1095 if (callTransitionFlag == false) { 1096 print('ctrlServerCmdSetCallActive: need to set the flag firt'); 1097 result.rilErrCode = CTRL_STATUS_ERR; 1098 return result; 1099 } 1100 if (numberActiveCalls <= 0) { 1101 print('ctrlServerCmdSetCallActive: no active calls'); 1102 result.rilErrCode = CTRL_STATUS_ERR; 1103 return result; 1104 } 1105 var alertingCalls = this.countCallsInState(CALLSTATE_ALERTING); 1106 var index = this.getCallIdByState(CALLSTATE_ALERTING); 1107 if ((alertingCalls == 1) && (index != null)) { 1108 calls[index].state = CALLSTATE_ACTIVE; 1109 } else { 1110 print('ctrlServerCmdSetCallActive: no valid calls in alert state'); 1111 result.rilErrCode = CTRL_STATUS_ERR; 1112 return result; 1113 } 1114 // send out unsolicited call state change response 1115 simulatedRadioWorker.add( 1116 {'reqNum' : CMD_UNSOL_CALL_STATE_CHANGED}); 1117 1118 result.rilErrCode = CTRL_STATUS_OK; 1119 return result; 1120 } 1121 1122 /** 1123 * Add a dialing call 1124 */ 1125 this.ctrlServerCmdAddDialingCall = function(req) { // 1006 1126 print('ctrlServerCmdAddDialingCall: E'); 1127 1128 var phoneNumber = req.data.phoneNumber; 1129 var dialingCalls = this.countCallsInState(CALLSTATE_DIALING); 1130 if (dialingCalls == 0) { 1131 this.addCall(CALLSTATE_DIALING, phoneNumber, ''); 1132 result.rilErrCode = CTRL_STATUS_OK; 1133 } else { 1134 print('ctrlServerCmdAddDialingCall: add dialing call failed'); 1135 result.rilErrCode = CTRL_STATUS_ERR; 1136 } 1137 return result; 1138 } 1139 1140 /** 1141 * Process the request by dispatching to the request handlers 1142 */ 1143 this.process = function(req) { 1144 try { 1145 print('Radio E: req.reqNum=' + req.reqNum + ' req.token=' + req.token); 1146 1147 // Assume the result will be true, successful and nothing to return 1148 result.sendResponse = true; 1149 result.rilErrCode = RIL_E_SUCCESS; 1150 result.responseProtobuf = emptyProtobuf; 1151 1152 try { 1153 // Pass "this" object to each ril request call such that 1154 // they have the same scope 1155 result = (this.radioDispatchTable[req.reqNum]).call(this, req); 1156 } catch (err) { 1157 print('Radio:process err = ' + err); 1158 print('Radio: Unknown reqNum=' + req.reqNum); 1159 result.rilErrCode = RIL_E_REQUEST_NOT_SUPPORTED; 1160 } 1161 1162 if (req.reqNum < 200) { 1163 lastReq = req.reqNum; 1164 } 1165 if (result.sendResponse) { 1166 if (isCtrlServerDispatchCommand(req.reqNum)) { 1167 //print('Command ' + req.reqNum + ' is a control server command'); 1168 sendCtrlRequestComplete(result.rilErrCode, req.reqNum, 1169 req.token, result.responseProtobuf); 1170 } else { 1171 //print('Request ' + req.reqNum + ' is a ril request'); 1172 sendRilRequestComplete(result.rilErrCode, req.reqNum, 1173 req.token, result.responseProtobuf); 1174 } 1175 } 1176 //print('Radio X: req.reqNum=' + req.reqNum + ' req.token=' + req.token); 1177 } catch (err) { 1178 print('Radio: Exception req.reqNum=' + 1179 req.reqNum + ' req.token=' + req.token + ' err=' + err); 1180 } 1181 } 1182 1183 /** 1184 * Construct the simulated radio 1185 */ 1186 print('Radio: constructor E'); 1187 this.radioDispatchTable = new Array(); 1188 this.radioDispatchTable[RIL_REQUEST_GET_CURRENT_CALLS] = // 9 1189 this.rilRequestGetCurrentCalls; 1190 this.radioDispatchTable[RIL_REQUEST_DIAL] = // 10 1191 this.rilRequestDial; 1192 this.radioDispatchTable[RIL_REQUEST_HANGUP] = // 12 1193 this.rilRequestHangUp; 1194 this.radioDispatchTable[RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND] = // 13 1195 this.rilRequestHangupWaitingOrBackground; 1196 this.radioDispatchTable[RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND] = // 14 1197 this.rilRequestHangUpForegroundResumeBackground; 1198 this.radioDispatchTable[RIL_REQUEST_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE] = // 15 1199 this.rilRequestSwitchWaitingOrHoldingAndActive; 1200 this.radioDispatchTable[RIL_REQUEST_CONFERENCE] = // 16 1201 this.rilRequestConference; 1202 this.radioDispatchTable[RIL_REQUEST_LAST_CALL_FAIL_CAUSE] = // 18 1203 this.rilRequestLastCallFailCause; 1204 this.radioDispatchTable[RIL_REQUEST_SIGNAL_STRENGTH] = // 19 1205 this.rilRequestSignalStrength; 1206 this.radioDispatchTable[RIL_REQUEST_VOICE_REGISTRATION_STATE] = // 20 1207 this.rilRequestVoiceRegistrationState; 1208 this.radioDispatchTable[RIL_REQUEST_DATA_REGISTRATION_STATE] = // 21 1209 this.rilRequestDataRegistrationState; 1210 this.radioDispatchTable[RIL_REQUEST_ANSWER] = // 40 1211 this.rilRequestAnswer; 1212 this.radioDispatchTable[RIL_REQUEST_QUERY_NETWORK_SELECTION_MODE] = // 45 1213 this.rilRequestQueryNeworkSelectionMode; 1214 this.radioDispatchTable[RIL_REQUEST_SET_NETWORK_SELECTION_AUTOMATIC] = // 46 1215 this.rilRequestSetNeworkSelectionAutomatic; 1216 this.radioDispatchTable[RIL_REQUEST_BASEBAND_VERSION] = // 51 1217 this.rilRequestBaseBandVersion; 1218 this.radioDispatchTable[RIL_REQUEST_SEPARATE_CONNECTION] = // 52 1219 this.rilReqestSeparateConnection; 1220 this.radioDispatchTable[RIL_REQUEST_SET_MUTE] = // 53 1221 this.rilRequestSetMute; 1222 this.radioDispatchTable[RIL_REQUEST_SCREEN_STATE] = // 61 1223 this.rilRequestScreenState; 1224 1225 this.radioDispatchTable[CTRL_CMD_SET_MT_CALL] = //1001 1226 this.ctrlServerCmdStartInComingCall; 1227 this.radioDispatchTable[CTRL_CMD_HANGUP_CONN_REMOTE] = //1002 1228 this.ctrlServerCmdHangupConnRemote; 1229 this.radioDispatchTable[CTRL_CMD_SET_CALL_TRANSITION_FLAG] = //1003 1230 this.ctrlServerCmdSetCallTransitionFlag; 1231 this.radioDispatchTable[CTRL_CMD_SET_CALL_ALERT] = // 1004 1232 this.ctrlServerCmdSetCallAlert; 1233 this.radioDispatchTable[CTRL_CMD_SET_CALL_ACTIVE] = // 1005 1234 this.ctrlServerCmdSetCallActive; 1235 this.radioDispatchTable[CTRL_CMD_ADD_DIALING_CALL] = // 1006 1236 this.ctrlServerCmdAddDialingCall; 1237 1238 this.radioDispatchTable[CMD_DELAY_TEST] = // 2000 1239 this.cmdDelayTest; 1240 this.radioDispatchTable[CMD_UNSOL_SIGNAL_STRENGTH] = // 2001 1241 this.cmdUnsolSignalStrength; 1242 this.radioDispatchTable[CMD_UNSOL_CALL_STATE_CHANGED] = // 2002 1243 this.cmdUnsolCallStateChanged; 1244 this.radioDispatchTable[CMD_CALL_STATE_CHANGE] = //2003 1245 this.cmdCallStateChange; 1246 this.radioDispatchTable[CMD_UNSOL_CALL_RING] = //2004 1247 this.cmdUnsolCallRing; 1248 1249 print('Radio: constructor X'); 1250 } 1251 1252 // The simulated radio instance and its associated Worker 1253 var simulatedRadio = new Radio(); 1254 var simulatedRadioWorker = new Worker(function (req) { 1255 simulatedRadio.process(req); 1256 }); 1257 simulatedRadioWorker.run(); 1258 1259 // TODO: this is a workaround for bug http://b/issue?id=3001613 1260 // When adding a new all, two RIL_REQUEST_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE 1261 // will be sent from the framework. 1262 var lastReq = 0; 1263 1264 /** 1265 * Optional tests 1266 */ 1267 if (false) { 1268 include("simulated_radio_tests.js"); 1269 } 1270