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