private void encodeOptionalTags( CommandDetails cmdDet, ResultCode resultCode, Input cmdInput, ByteArrayOutputStream buf) { CommandType cmdType = AppInterface.CommandType.fromInt(cmdDet.typeOfCommand); if (cmdType != null) { switch (cmdType) { case GET_INKEY: // ETSI TS 102 384,27.22.4.2.8.4.2. // If it is a response for GET_INKEY command and the response timeout // occured, then add DURATION TLV for variable timeout case. if ((resultCode.value() == ResultCode.NO_RESPONSE_FROM_USER.value()) && (cmdInput != null) && (cmdInput.duration != null)) { getInKeyResponse(buf, cmdInput); } break; case PROVIDE_LOCAL_INFORMATION: if ((cmdDet.commandQualifier == CommandParamsFactory.LANGUAGE_SETTING) && (resultCode.value() == ResultCode.OK.value())) { getPliResponse(buf); } break; default: CatLog.d(this, "encodeOptionalTags() Unsupported Cmd details=" + cmdDet); break; } } else { CatLog.d(this, "encodeOptionalTags() bad Cmd details=" + cmdDet); } }
private boolean processBIPClient(CommandDetails cmdDet, List<ComprehensionTlv> ctlvs) throws ResultException { AppInterface.CommandType commandType = AppInterface.CommandType.fromInt(cmdDet.typeOfCommand); if (commandType != null) { CatLog.d(this, "process " + commandType.name()); } TextMessage textMsg = new TextMessage(); IconId iconId = null; ComprehensionTlv ctlv = null; boolean has_alpha_id = false; // parse alpha identifier ctlv = searchForTag(ComprehensionTlvTag.ALPHA_ID, ctlvs); if (ctlv != null) { textMsg.text = ValueParser.retrieveAlphaId(ctlv); CatLog.d(this, "alpha TLV text=" + textMsg.text); has_alpha_id = true; } // parse icon identifier ctlv = searchForTag(ComprehensionTlvTag.ICON_ID, ctlvs); if (ctlv != null) { iconId = ValueParser.retrieveIconId(ctlv); textMsg.iconSelfExplanatory = iconId.selfExplanatory; } textMsg.responseNeeded = false; mCmdParams = new BIPClientParams(cmdDet, textMsg, has_alpha_id); if (iconId != null) { mIconLoadState = LOAD_SINGLE_ICON; mIconLoader.loadIcon(iconId.recordNumber, this.obtainMessage(MSG_ID_LOAD_ICON_DONE)); return true; } return false; }
private void handleCmdResponse(CatResponseMessage resMsg) { // Make sure the response details match the last valid command. An invalid // response is a one that doesn't have a corresponding proactive command // and sending it can "confuse" the baseband/ril. // One reason for out of order responses can be UI glitches. For example, // if the application launch an activity, and that activity is stored // by the framework inside the history stack. That activity will be // available for relaunch using the latest application dialog // (long press on the home button). Relaunching that activity can send // the same command's result again to the CatService and can cause it to // get out of sync with the SIM. This can happen in case of // non-interactive type Setup Event List and SETUP_MENU proactive commands. // Stk framework would have already sent Terminal Response to Setup Event // List and SETUP_MENU proactive commands. After sometime Stk app will send // Envelope Command/Event Download. In which case, the response details doesn't // match with last valid command (which are not related). // However, we should allow Stk framework to send the message to ICC. if (!validateResponse(resMsg)) { return; } ResponseData resp = null; boolean helpRequired = false; CommandDetails cmdDet = resMsg.getCmdDetails(); AppInterface.CommandType type = AppInterface.CommandType.fromInt(cmdDet.typeOfCommand); switch (resMsg.mResCode) { case HELP_INFO_REQUIRED: helpRequired = true; // fall through case OK: case PRFRMD_WITH_PARTIAL_COMPREHENSION: case PRFRMD_WITH_MISSING_INFO: case PRFRMD_WITH_ADDITIONAL_EFS_READ: case PRFRMD_ICON_NOT_DISPLAYED: case PRFRMD_MODIFIED_BY_NAA: case PRFRMD_LIMITED_SERVICE: case PRFRMD_WITH_MODIFICATION: case PRFRMD_NAA_NOT_ACTIVE: case PRFRMD_TONE_NOT_PLAYED: case LAUNCH_BROWSER_ERROR: case TERMINAL_CRNTLY_UNABLE_TO_PROCESS: switch (type) { case SET_UP_MENU: helpRequired = resMsg.mResCode == ResultCode.HELP_INFO_REQUIRED; sendMenuSelection(resMsg.mUsersMenuSelection, helpRequired); return; case SELECT_ITEM: resp = new SelectItemResponseData(resMsg.mUsersMenuSelection); break; case GET_INPUT: case GET_INKEY: Input input = mCurrntCmd.geInput(); if (!input.yesNo) { // when help is requested there is no need to send the text // string object. if (!helpRequired) { resp = new GetInkeyInputResponseData(resMsg.mUsersInput, input.ucs2, input.packed); } } else { resp = new GetInkeyInputResponseData(resMsg.mUsersYesNoSelection); } break; case DISPLAY_TEXT: if (resMsg.mResCode == ResultCode.TERMINAL_CRNTLY_UNABLE_TO_PROCESS) { // For screenbusy case there will be addtional information in the terminal // response. And the value of the additional information byte is 0x01. resMsg.setAdditionalInfo(0x01); } else { resMsg.mIncludeAdditionalInfo = false; resMsg.mAdditionalInfo = 0; } break; case LAUNCH_BROWSER: break; // 3GPP TS.102.223: Open Channel alpha confirmation should not send TR case OPEN_CHANNEL: case SET_UP_CALL: mCmdIf.handleCallSetupRequestFromSim(resMsg.mUsersConfirm, null); // No need to send terminal response for SET UP CALL. The user's // confirmation result is send back using a dedicated ril message // invoked by the CommandInterface call above. mCurrntCmd = null; return; case SET_UP_EVENT_LIST: if (IDLE_SCREEN_AVAILABLE_EVENT == resMsg.mEventValue) { eventDownload( resMsg.mEventValue, DEV_ID_DISPLAY, DEV_ID_UICC, resMsg.mAddedInfo, false); } else { eventDownload( resMsg.mEventValue, DEV_ID_TERMINAL, DEV_ID_UICC, resMsg.mAddedInfo, false); } // No need to send the terminal response after event download. return; default: break; } break; case BACKWARD_MOVE_BY_USER: case USER_NOT_ACCEPT: // if the user dismissed the alert dialog for a // setup call/open channel, consider that as the user // rejecting the call. Use dedicated API for this, rather than // sending a terminal response. if (type == CommandType.SET_UP_CALL || type == CommandType.OPEN_CHANNEL) { mCmdIf.handleCallSetupRequestFromSim(false, null); mCurrntCmd = null; return; } else { resp = null; } break; case NO_RESPONSE_FROM_USER: // No need to send terminal response for SET UP CALL on user timeout. if (type == CommandType.SET_UP_CALL) { mCurrntCmd = null; return; } case UICC_SESSION_TERM_BY_USER: resp = null; break; default: return; } sendTerminalResponse( cmdDet, resMsg.mResCode, resMsg.mIncludeAdditionalInfo, resMsg.mAdditionalInfo, resp); mCurrntCmd = null; }
void make(BerTlv berTlv, IconLoader iconLoader) { if (berTlv == null) { return; } CatLog.d(this, "IconLoader received: " + iconLoader); // reset global state parameters. mIconLoader = iconLoader; mCmdParams = null; mIconLoadState = LOAD_NO_ICON; // only proactive command messages are processed. if (berTlv.getTag() != BerTlv.BER_PROACTIVE_COMMAND_TAG) { sendCmdParams(ResultCode.CMD_TYPE_NOT_UNDERSTOOD); return; } boolean cmdPending = false; List<ComprehensionTlv> ctlvs = berTlv.getComprehensionTlvs(); // process command dtails from the tlv list. CommandDetails cmdDet = processCommandDetails(ctlvs); if (cmdDet == null) { sendCmdParams(ResultCode.CMD_TYPE_NOT_UNDERSTOOD); return; } // extract command type enumeration from the raw value stored inside // the Command Details object. AppInterface.CommandType cmdType = AppInterface.CommandType.fromInt(cmdDet.typeOfCommand); if (cmdType == null) { // This PROACTIVE COMMAND is presently not handled. Hence set // result code as BEYOND_TERMINAL_CAPABILITY in TR. mCmdParams = new CommandParams(cmdDet); sendCmdParams(ResultCode.BEYOND_TERMINAL_CAPABILITY); return; } try { switch (cmdType) { case SET_UP_MENU: cmdPending = processSelectItem(cmdDet, ctlvs); break; case SELECT_ITEM: cmdPending = processSelectItem(cmdDet, ctlvs); break; case DISPLAY_TEXT: cmdPending = processDisplayText(cmdDet, ctlvs); break; case SET_UP_IDLE_MODE_TEXT: cmdPending = processSetUpIdleModeText(cmdDet, ctlvs); break; case GET_INKEY: cmdPending = processGetInkey(cmdDet, ctlvs); break; case GET_INPUT: cmdPending = processGetInput(cmdDet, ctlvs); break; case SEND_DTMF: case SEND_SMS: case SEND_SS: case SEND_USSD: cmdPending = processEventNotify(cmdDet, ctlvs); break; case GET_CHANNEL_STATUS: case SET_UP_CALL: cmdPending = processSetupCall(cmdDet, ctlvs); break; case REFRESH: processRefresh(cmdDet, ctlvs); cmdPending = false; break; case LAUNCH_BROWSER: cmdPending = processLaunchBrowser(cmdDet, ctlvs); break; case PLAY_TONE: cmdPending = processPlayTone(cmdDet, ctlvs); break; case SET_UP_EVENT_LIST: cmdPending = processSetUpEventList(cmdDet, ctlvs); break; case PROVIDE_LOCAL_INFORMATION: cmdPending = processProvideLocalInfo(cmdDet, ctlvs); break; case OPEN_CHANNEL: case CLOSE_CHANNEL: case RECEIVE_DATA: case SEND_DATA: cmdPending = processBIPClient(cmdDet, ctlvs); break; default: // unsupported proactive commands mCmdParams = new CommandParams(cmdDet); sendCmdParams(ResultCode.BEYOND_TERMINAL_CAPABILITY); return; } } catch (ResultException e) { CatLog.d(this, "make: caught ResultException e=" + e); mCmdParams = new CommandParams(cmdDet); sendCmdParams(e.result()); return; } if (!cmdPending) { sendCmdParams(ResultCode.OK); } }
/* external API to be used by application */ public AppInterface.CommandType getCmdType() { return AppInterface.CommandType.fromInt(mCmdDet.typeOfCommand); }
private void handleCmdResponse(CatResponseMessage resMsg) { // Make sure the response details match the last valid command. An invalid // response is a one that doesn't have a corresponding proactive command // and sending it can "confuse" the baseband/ril. // One reason for out of order responses can be UI glitches. For example, // if the application launch an activity, and that activity is stored // by the framework inside the history stack. That activity will be // available for relaunch using the latest application dialog // (long press on the home button). Relaunching that activity can send // the same command's result again to the CatService and can cause it to // get out of sync with the SIM. if (!validateResponse(resMsg)) { return; } ResponseData resp = null; boolean helpRequired = false; CommandDetails cmdDet = resMsg.getCmdDetails(); AppInterface.CommandType type = AppInterface.CommandType.fromInt(cmdDet.typeOfCommand); switch (resMsg.resCode) { case HELP_INFO_REQUIRED: helpRequired = true; // fall through case OK: case PRFRMD_WITH_PARTIAL_COMPREHENSION: case PRFRMD_WITH_MISSING_INFO: case PRFRMD_WITH_ADDITIONAL_EFS_READ: case PRFRMD_ICON_NOT_DISPLAYED: case PRFRMD_MODIFIED_BY_NAA: case PRFRMD_LIMITED_SERVICE: case PRFRMD_WITH_MODIFICATION: case PRFRMD_NAA_NOT_ACTIVE: case PRFRMD_TONE_NOT_PLAYED: case TERMINAL_CRNTLY_UNABLE_TO_PROCESS: switch (type) { case SET_UP_MENU: helpRequired = resMsg.resCode == ResultCode.HELP_INFO_REQUIRED; sendMenuSelection(resMsg.usersMenuSelection, helpRequired); return; case SELECT_ITEM: resp = new SelectItemResponseData(resMsg.usersMenuSelection); break; case GET_INPUT: case GET_INKEY: Input input = mCurrntCmd.geInput(); if (!input.yesNo) { // when help is requested there is no need to send the text // string object. if (!helpRequired) { resp = new GetInkeyInputResponseData(resMsg.usersInput, input.ucs2, input.packed); } } else { resp = new GetInkeyInputResponseData(resMsg.usersYesNoSelection); } break; case DISPLAY_TEXT: case LAUNCH_BROWSER: break; case SET_UP_CALL: mCmdIf.handleCallSetupRequestFromSim(resMsg.usersConfirm, null); // No need to send terminal response for SET UP CALL. The user's // confirmation result is send back using a dedicated ril message // invoked by the CommandInterface call above. mCurrntCmd = null; return; } break; case BACKWARD_MOVE_BY_USER: case USER_NOT_ACCEPT: // if the user dismissed the alert dialog for a // setup call/open channel, consider that as the user // rejecting the call. Use dedicated API for this, rather than // sending a terminal response. if (type == CommandType.SET_UP_CALL || type == CommandType.OPEN_CHANNEL) { mCmdIf.handleCallSetupRequestFromSim(false, null); mCurrntCmd = null; return; } else { resp = null; } break; case NO_RESPONSE_FROM_USER: case UICC_SESSION_TERM_BY_USER: resp = null; break; default: return; } sendTerminalResponse( cmdDet, resMsg.resCode, resMsg.includeAdditionalInfo, resMsg.additionalInfo, resp); mCurrntCmd = null; }