/* Intentionally private for singleton */ private CatService( CommandsInterface ci, UiccCardApplication ca, IccRecords ir, Context context, IccFileHandler fh, UiccCard ic) { if (ci == null || ca == null || ir == null || context == null || fh == null || ic == null) { throw new NullPointerException("Service: Input parameters must not be null"); } mCmdIf = ci; mContext = context; // Get the RilMessagesDecoder for decoding the messages. mMsgDecoder = RilMessageDecoder.getInstance(this, fh); // Register ril events handling. mCmdIf.setOnCatSessionEnd(this, MSG_ID_SESSION_END, null); mCmdIf.setOnCatProactiveCmd(this, MSG_ID_PROACTIVE_COMMAND, null); mCmdIf.setOnCatEvent(this, MSG_ID_EVENT_NOTIFY, null); mCmdIf.setOnCatCallSetUp(this, MSG_ID_CALL_SETUP, null); // mCmdIf.setOnSimRefresh(this, MSG_ID_REFRESH, null); mIccRecords = ir; mUiccApplication = ca; // Register for SIM ready event. mUiccApplication.registerForReady(this, MSG_ID_SIM_READY, null); mIccRecords.registerForRecordsLoaded(this, MSG_ID_ICC_RECORDS_LOADED, null); // Check if STK application is availalbe mStkAppInstalled = isStkAppInstalled(); CatLog.d(this, "Running CAT service. STK app installed:" + mStkAppInstalled); }
// Constructor private CdmaSubscriptionSourceManager(Context context, CommandsInterface ci) { mContext = context; mCM = ci; mCM.registerForCdmaSubscriptionChanged(this, EVENT_CDMA_SUBSCRIPTION_SOURCE_CHANGED, null); mCM.registerForOn(this, EVENT_RADIO_ON, null); mCM.registerForSubscriptionStatusChanged(this, EVENT_SUBSCRIPTION_STATUS_CHANGED, null); getDefaultCdmaSubscriptionSource(); }
public void dispose() { mIccRecords.unregisterForRecordsLoaded(this); mCmdIf.unSetOnCatSessionEnd(this); mCmdIf.unSetOnCatProactiveCmd(this); mCmdIf.unSetOnCatEvent(this); mCmdIf.unSetOnCatCallSetUp(this); this.removeCallbacksAndMessages(null); }
/** Unregisters for the registered event with RIL */ public void dispose(Handler h) { mCdmaSubscriptionSourceChangedRegistrants.remove(h); synchronized (sReferenceCountMonitor) { sReferenceCount--; if (sReferenceCount <= 0) { mCM.unregisterForCdmaSubscriptionChanged(this); mCM.unregisterForOn(this); mCM.unregisterForSubscriptionStatusChanged(this); sInstance = null; } } }
/** Unregisters for the registered event with RIL */ public void dispose(Handler handler) { if (null != handler) { mCdmaSubscriptionSourceChangedRegistrants.remove(handler); } mRef--; if (mRef <= 0) { mCM.unregisterForCdmaSubscriptionSourceChanged(this); mCM.unregisterForOn(this); mCM.unregisterForSubscriptionStatusChanged(this); mCdmaSSMInstances.remove(mCM); } }
// Hide constructor private CdmaSubscriptionSourceManager(Context context, CommandsInterface ci) { if (context == null) { Log.w(LOG_TAG, "Context shouldn't be null"); } else { mContext = context; getDefaultCdmaSubscriptionSource(); } if (ci == null) { Log.w(LOG_TAG, "CommandsInterface shouldn't be null"); } else { mCM = ci; mCM.registerForCdmaSubscriptionSourceChanged( this, EVENT_CDMA_SUBSCRIPTION_SOURCE_CHANGED, null); mCM.registerForOn(this, EVENT_RADIO_ON, null); mCM.registerForSubscriptionStatusChanged(this, EVENT_SUBSCRIPTION_STATUS_CHANGED, null); } }
public void dispose() { CatLog.d(this, "Disposing CatService object for slot: " + mSlotId); // Clean up stk icon if dispose is called broadcastCardStateAndIccRefreshResp(CardState.CARDSTATE_ABSENT, null); mCmdIf.unSetOnCatSessionEnd(this); mCmdIf.unSetOnCatProactiveCmd(this); mCmdIf.unSetOnCatEvent(this); mCmdIf.unSetOnCatCallSetUp(this); mCmdIf.unSetOnCatCcAlphaNotify(this); mCmdIf.unSetOnCatSendSmsResult(this); mCmdIf.unregisterForIccRefresh(this); if (mUiccController != null) { mUiccController.unregisterForIccChanged(this); mUiccController = null; } if (mMsgDecoder != null) { mMsgDecoder.dispose(mSlotId); mMsgDecoder = null; } mHandlerThread.quit(); mHandlerThread = null; removeCallbacksAndMessages(null); }
/* * (non-Javadoc) * @see android.os.Handler#handleMessage(android.os.Message) */ @Override public void handleMessage(Message msg) { AsyncResult ar; switch (msg.what) { case EVENT_CDMA_SUBSCRIPTION_SOURCE_CHANGED: { Log.d(LOG_TAG, "EVENT_CDMA_SUBSCRIPTION_SOURCE_CHANGED"); ar = (AsyncResult) msg.obj; handleCdmaSubscriptionSource(ar); } break; case EVENT_GET_CDMA_SUBSCRIPTION_SOURCE: { Log.d(LOG_TAG, "EVENT_GET_CDMA_SUBSCRIPTION_SOURCE"); ar = (AsyncResult) msg.obj; handleCdmaSubscriptionSource(ar); } break; case EVENT_RADIO_ON: { mCM.getCdmaSubscriptionSource(obtainMessage(EVENT_GET_CDMA_SUBSCRIPTION_SOURCE)); } break; case EVENT_SUBSCRIPTION_STATUS_CHANGED: { Log.d(LOG_TAG, "EVENT_SUBSCRIPTION_STATUS_CHANGED"); ar = (AsyncResult) msg.obj; if (ar.exception == null) { int actStatus = ((int[]) ar.result)[0]; Log.d(LOG_TAG, "actStatus = " + actStatus); if (actStatus == 1) { // Subscription Activated // In case of multi-SIM, framework should wait for the subscription ready // to send any request to RIL. Otherwise it will return failure. Log.d(LOG_TAG, "get Cdma Subscription Source"); mCM.getCdmaSubscriptionSource(obtainMessage(EVENT_GET_CDMA_SUBSCRIPTION_SOURCE)); } } } break; default: super.handleMessage(msg); } }
private void eventDownload( int event, int sourceId, int destinationId, byte[] additionalInfo, boolean oneShot) { ByteArrayOutputStream buf = new ByteArrayOutputStream(); // tag int tag = BerTlv.BER_EVENT_DOWNLOAD_TAG; buf.write(tag); // length buf.write(0x00); // place holder, assume length < 128. // event list tag = 0x80 | ComprehensionTlvTag.EVENT_LIST.value(); buf.write(tag); buf.write(0x01); // length buf.write(event); // event value // device identities tag = 0x80 | ComprehensionTlvTag.DEVICE_IDENTITIES.value(); buf.write(tag); buf.write(0x02); // length buf.write(sourceId); // source device id buf.write(destinationId); // destination device id // additional information if (additionalInfo != null) { for (byte b : additionalInfo) { buf.write(b); } } byte[] rawData = buf.toByteArray(); // write real length int len = rawData.length - 2; // minus (tag + length) rawData[1] = (byte) len; String hexString = IccUtils.bytesToHexString(rawData); mCmdIf.sendEnvelope(hexString, null); }
void updateIccAvailability() { if (null == mUiccController) { return; } CardState newState = CardState.CARDSTATE_ABSENT; UiccCard newCard = mUiccController.getUiccCard(mSlotId); if (newCard != null) { newState = newCard.getCardState(); } CardState oldState = mCardState; mCardState = newState; CatLog.d(this, "New Card State = " + newState + " " + "Old Card State = " + oldState); if (oldState == CardState.CARDSTATE_PRESENT && newState != CardState.CARDSTATE_PRESENT) { broadcastCardStateAndIccRefreshResp(newState, null); } else if (oldState != CardState.CARDSTATE_PRESENT && newState == CardState.CARDSTATE_PRESENT) { // Card moved to PRESENT STATE. mCmdIf.reportStkServiceIsRunning(null); } }
private void sendMenuSelection(int menuId, boolean helpRequired) { ByteArrayOutputStream buf = new ByteArrayOutputStream(); // tag int tag = BerTlv.BER_MENU_SELECTION_TAG; buf.write(tag); // length buf.write(0x00); // place holder // device identities tag = 0x80 | ComprehensionTlvTag.DEVICE_IDENTITIES.value(); buf.write(tag); buf.write(0x02); // length buf.write(DEV_ID_KEYPAD); // source device id buf.write(DEV_ID_UICC); // destination device id // item identifier tag = 0x80 | ComprehensionTlvTag.ITEM_ID.value(); buf.write(tag); buf.write(0x01); // length buf.write(menuId); // menu identifier chosen // help request if (helpRequired) { tag = ComprehensionTlvTag.HELP_REQUEST.value(); buf.write(tag); buf.write(0x00); // length } byte[] rawData = buf.toByteArray(); // write real length int len = rawData.length - 2; // minus (tag + length) rawData[1] = (byte) len; String hexString = IccUtils.bytesToHexString(rawData); mCmdIf.sendEnvelope(hexString, null); }
@Override public void handleMessage(Message msg) { switch (msg.what) { case MSG_ID_SESSION_END: case MSG_ID_PROACTIVE_COMMAND: case MSG_ID_EVENT_NOTIFY: case MSG_ID_REFRESH: CatLog.d(this, "ril message arrived"); String data = null; if (msg.obj != null) { AsyncResult ar = (AsyncResult) msg.obj; if (ar != null && ar.result != null) { try { data = (String) ar.result; } catch (ClassCastException e) { break; } } } mMsgDecoder.sendStartDecodingMessageParams(new RilMessage(msg.what, data)); break; case MSG_ID_CALL_SETUP: mMsgDecoder.sendStartDecodingMessageParams(new RilMessage(msg.what, null)); break; case MSG_ID_ICC_RECORDS_LOADED: break; case MSG_ID_RIL_MSG_DECODED: handleRilMsg((RilMessage) msg.obj); break; case MSG_ID_RESPONSE: handleCmdResponse((CatResponseMessage) msg.obj); break; case MSG_ID_SIM_READY: CatLog.d(this, "SIM ready. Reporting STK service running now..."); mCmdIf.reportStkServiceIsRunning(null); break; default: throw new AssertionError("Unrecognized CAT command: " + msg.what); } }
/* For multisim catservice should not be singleton */ CatService(CommandsInterface ci, Context context, IccFileHandler fh, int slotId) { if (ci == null || context == null || fh == null) { throw new NullPointerException("Service: Input parameters must not be null"); } mCmdIf = ci; mContext = context; mSlotId = slotId; mHandlerThread = new HandlerThread("Cat Telephony service" + slotId); mHandlerThread.start(); // Get the RilMessagesDecoder for decoding the messages. mMsgDecoder = RilMessageDecoder.getInstance(this, fh, slotId); if (null == mMsgDecoder) { CatLog.d(this, "Null RilMessageDecoder instance"); return; } mMsgDecoder.start(); // Register ril events handling. mCmdIf.setOnCatSessionEnd(this, MSG_ID_SESSION_END, null); mCmdIf.setOnCatProactiveCmd(this, MSG_ID_PROACTIVE_COMMAND, null); mCmdIf.setOnCatEvent(this, MSG_ID_EVENT_NOTIFY, null); mCmdIf.setOnCatCallSetUp(this, MSG_ID_CALL_SETUP, null); mCmdIf.setOnCatSendSmsResult(this, MSG_ID_SEND_SMS_RESULT, null); // Samsung STK // mCmdIf.setOnSimRefresh(this, MSG_ID_REFRESH, null); mCmdIf.registerForIccRefresh(this, MSG_ID_ICC_REFRESH, null); mCmdIf.setOnCatCcAlphaNotify(this, MSG_ID_ALPHA_NOTIFY, null); mUiccController = UiccController.getInstance(); mUiccController.registerForIccChanged(this, MSG_ID_ICC_CHANGED, null); // Check if STK application is availalbe mStkAppInstalled = isStkAppInstalled(); CatLog.d( this, "Running CAT service on Slotid: " + mSlotId + ". STK app installed:" + mStkAppInstalled); }
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; }
private void eventDownload( int event, int sourceId, int destinationId, byte[] additionalInfo, boolean oneShot) { ByteArrayOutputStream buf = new ByteArrayOutputStream(); // tag int tag = BerTlv.BER_EVENT_DOWNLOAD_TAG; buf.write(tag); // length buf.write(0x00); // place holder, assume length < 128. // event list tag = 0x80 | ComprehensionTlvTag.EVENT_LIST.value(); buf.write(tag); buf.write(0x01); // length buf.write(event); // event value // device identities tag = 0x80 | ComprehensionTlvTag.DEVICE_IDENTITIES.value(); buf.write(tag); buf.write(0x02); // length buf.write(sourceId); // source device id buf.write(destinationId); // destination device id /* * Check for type of event download to be sent to UICC - Browser * termination,Idle screen available, User activity, Language selection * etc as mentioned under ETSI TS 102 223 section 7.5 */ /* * Currently the below events are supported: * Idle Screen Available, * Language Selection Event and * HCI Connectivity. * Other event download commands should be encoded similar way */ /* TODO: eventDownload should be extended for other Envelope Commands */ switch (event) { case IDLE_SCREEN_AVAILABLE_EVENT: CatLog.d(this, " Sending Idle Screen Available event download to ICC"); break; case LANGUAGE_SELECTION_EVENT: CatLog.d(this, " Sending Language Selection event download to ICC"); tag = 0x80 | ComprehensionTlvTag.LANGUAGE.value(); buf.write(tag); // Language length should be 2 byte buf.write(0x02); break; case HCI_CONNECTIVITY_EVENT: CatLog.d(this, " Sending HCI Connectivity event download to ICC"); break; default: break; } // additional information if (additionalInfo != null) { for (byte b : additionalInfo) { buf.write(b); } } byte[] rawData = buf.toByteArray(); // write real length int len = rawData.length - 2; // minus (tag + length) rawData[1] = (byte) len; String hexString = IccUtils.bytesToHexString(rawData); CatLog.d(this, "ENVELOPE COMMAND: " + hexString); mCmdIf.sendEnvelope(hexString, null); }
private void sendTerminalResponse( CommandDetails cmdDet, ResultCode resultCode, boolean includeAdditionalInfo, int additionalInfo, ResponseData resp) { if (cmdDet == null) { return; } ByteArrayOutputStream buf = new ByteArrayOutputStream(); Input cmdInput = null; if (mCurrntCmd != null) { cmdInput = mCurrntCmd.geInput(); } // command details int tag = ComprehensionTlvTag.COMMAND_DETAILS.value(); if (cmdDet.compRequired) { tag |= 0x80; } buf.write(tag); buf.write(0x03); // length buf.write(cmdDet.commandNumber); buf.write(cmdDet.typeOfCommand); buf.write(cmdDet.commandQualifier); // device identities // According to TS102.223/TS31.111 section 6.8 Structure of // TERMINAL RESPONSE, "For all SIMPLE-TLV objects with Min=N, // the ME should set the CR(comprehension required) flag to // comprehension not required.(CR=0)" // Since DEVICE_IDENTITIES and DURATION TLVs have Min=N, // the CR flag is not set. tag = ComprehensionTlvTag.DEVICE_IDENTITIES.value(); buf.write(tag); buf.write(0x02); // length buf.write(DEV_ID_TERMINAL); // source device id buf.write(DEV_ID_UICC); // destination device id // result tag = ComprehensionTlvTag.RESULT.value(); if (cmdDet.compRequired) { tag |= 0x80; } buf.write(tag); int length = includeAdditionalInfo ? 2 : 1; buf.write(length); buf.write(resultCode.value()); // additional info if (includeAdditionalInfo) { buf.write(additionalInfo); } // Fill optional data for each corresponding command if (resp != null) { resp.format(buf); } else { encodeOptionalTags(cmdDet, resultCode, cmdInput, buf); } byte[] rawData = buf.toByteArray(); String hexString = IccUtils.bytesToHexString(rawData); if (DBG) { CatLog.d(this, "TERMINAL RESPONSE: " + hexString); } mCmdIf.sendTerminalResponse(hexString, null); }
/** * Handles RIL_UNSOL_STK_EVENT_NOTIFY or RIL_UNSOL_STK_PROACTIVE_COMMAND command from RIL. Sends * valid proactive command data to the application using intents. * RIL_REQUEST_STK_SEND_TERMINAL_RESPONSE will be send back if the command is from * RIL_UNSOL_STK_PROACTIVE_COMMAND. */ private void handleCommand(CommandParams cmdParams, boolean isProactiveCmd) { CatLog.d(this, cmdParams.getCommandType().name()); // Log all proactive commands. if (isProactiveCmd) { if (mUiccController != null) { mUiccController.addCardLog( "ProactiveCommand mSlotId=" + mSlotId + " cmdParams=" + cmdParams); } } CharSequence message; ResultCode resultCode; CatCmdMessage cmdMsg = new CatCmdMessage(cmdParams); switch (cmdParams.getCommandType()) { case SET_UP_MENU: if (removeMenu(cmdMsg.getMenu())) { mMenuCmd = null; } else { mMenuCmd = cmdMsg; } resultCode = cmdParams.mLoadIconFailed ? ResultCode.PRFRMD_ICON_NOT_DISPLAYED : ResultCode.OK; if (isProactiveCmd) { sendTerminalResponse(cmdParams.mCmdDet, resultCode, false, 0, null); } break; case DISPLAY_TEXT: break; case REFRESH: // Stk app service displays alpha id to user if it is present, nothing to do here CatLog.d(this, "Pass Refresh to Stk app"); break; case SET_UP_IDLE_MODE_TEXT: resultCode = cmdParams.mLoadIconFailed ? ResultCode.PRFRMD_ICON_NOT_DISPLAYED : ResultCode.OK; if (isProactiveCmd) { sendTerminalResponse(cmdParams.mCmdDet, resultCode, false, 0, null); } break; case SET_UP_EVENT_LIST: if (isProactiveCmd) { if (isSupportedSetupEventCommand(cmdMsg)) { sendTerminalResponse(cmdParams.mCmdDet, ResultCode.OK, false, 0, null); } else { sendTerminalResponse( cmdParams.mCmdDet, ResultCode.BEYOND_TERMINAL_CAPABILITY, false, 0, null); } } break; case PROVIDE_LOCAL_INFORMATION: ResponseData resp; switch (cmdParams.mCmdDet.commandQualifier) { case CommandParamsFactory.DTTZ_SETTING: resp = new DTTZResponseData(null); sendTerminalResponse(cmdParams.mCmdDet, ResultCode.OK, false, 0, resp); break; case CommandParamsFactory.LANGUAGE_SETTING: resp = new LanguageResponseData(Locale.getDefault().getLanguage()); sendTerminalResponse(cmdParams.mCmdDet, ResultCode.OK, false, 0, resp); break; default: sendTerminalResponse(cmdParams.mCmdDet, ResultCode.OK, false, 0, null); } // No need to start STK app here. return; case LAUNCH_BROWSER: if ((((LaunchBrowserParams) cmdParams).mConfirmMsg.text != null) && (((LaunchBrowserParams) cmdParams).mConfirmMsg.text.equals(STK_DEFAULT))) { message = mContext.getText(com.android.internal.R.string.launchBrowserDefault); ((LaunchBrowserParams) cmdParams).mConfirmMsg.text = message.toString(); } break; case SELECT_ITEM: case GET_INPUT: case GET_INKEY: break; case SEND_DTMF: case SEND_SMS: // Samsung STK if (cmdParams instanceof SendSMSParams) { handleProactiveCommandSendSMS((SendSMSParams) cmdParams); } // Fall through case SEND_SS: case SEND_USSD: // Samsung STK if (cmdParams instanceof SendUSSDParams) { handleProactiveCommandSendUSSD((SendUSSDParams) cmdParams); } if ((((DisplayTextParams) cmdParams).mTextMsg.text != null) && (((DisplayTextParams) cmdParams).mTextMsg.text.equals(STK_DEFAULT))) { message = mContext.getText(com.android.internal.R.string.sending); ((DisplayTextParams) cmdParams).mTextMsg.text = message.toString(); } break; case PLAY_TONE: break; case SET_UP_CALL: if ((((CallSetupParams) cmdParams).mConfirmMsg.text != null) && (((CallSetupParams) cmdParams).mConfirmMsg.text.equals(STK_DEFAULT))) { message = mContext.getText(com.android.internal.R.string.SetupCallDefault); ((CallSetupParams) cmdParams).mConfirmMsg.text = message.toString(); } break; case OPEN_CHANNEL: case CLOSE_CHANNEL: case RECEIVE_DATA: case SEND_DATA: BIPClientParams cmd = (BIPClientParams) cmdParams; /* Per 3GPP specification 102.223, * if the alpha identifier is not provided by the UICC, * the terminal MAY give information to the user * noAlphaUsrCnf defines if you need to show user confirmation or not */ boolean noAlphaUsrCnf = false; try { noAlphaUsrCnf = mContext .getResources() .getBoolean(com.android.internal.R.bool.config_stkNoAlphaUsrCnf); } catch (NotFoundException e) { noAlphaUsrCnf = false; } if ((cmd.mTextMsg.text == null) && (cmd.mHasAlphaId || noAlphaUsrCnf)) { CatLog.d(this, "cmd " + cmdParams.getCommandType() + " with null alpha id"); // If alpha length is zero, we just respond with OK. if (isProactiveCmd) { sendTerminalResponse(cmdParams.mCmdDet, ResultCode.OK, false, 0, null); } else if (cmdParams.getCommandType() == CommandType.OPEN_CHANNEL) { mCmdIf.handleCallSetupRequestFromSim(true, null); } return; } // Respond with permanent failure to avoid retry if STK app is not present. if (!mStkAppInstalled) { CatLog.d(this, "No STK application found."); if (isProactiveCmd) { sendTerminalResponse( cmdParams.mCmdDet, ResultCode.BEYOND_TERMINAL_CAPABILITY, false, 0, null); return; } } /* * CLOSE_CHANNEL, RECEIVE_DATA and SEND_DATA can be delivered by * either PROACTIVE_COMMAND or EVENT_NOTIFY. * If PROACTIVE_COMMAND is used for those commands, send terminal * response here. */ if (isProactiveCmd && ((cmdParams.getCommandType() == CommandType.CLOSE_CHANNEL) || (cmdParams.getCommandType() == CommandType.RECEIVE_DATA) || (cmdParams.getCommandType() == CommandType.SEND_DATA))) { sendTerminalResponse(cmdParams.mCmdDet, ResultCode.OK, false, 0, null); } break; case ACTIVATE: // TO DO: Retrieve the target of the ACTIVATE cmd from the cmd. // Target : '01' = UICC-CFL interface according to TS 102 613 [39]; // '00' and '02' to 'FF' = RFU (Reserved for Future Use). resultCode = ResultCode.OK; sendTerminalResponse(cmdParams.mCmdDet, resultCode, false, 0, null); break; default: CatLog.d(this, "Unsupported command"); return; } mCurrntCmd = cmdMsg; broadcastCatCmdIntent(cmdMsg); }
/** * Samsung STK SEND_USSD * * @param cmdPar */ private void handleProactiveCommandSendUSSD(SendUSSDParams cmdPar) { CatLog.d(this, "The USSD is: " + cmdPar.ussdString); mCmdIf.sendUSSD(cmdPar.ussdString, null); // Sent USSD, let framework handle the rest }
/** * Samsung STK SEND_SMS * * @param cmdPar */ private void handleProactiveCommandSendSMS(SendSMSParams cmdPar) { CatLog.d(this, "The smscaddress is: " + cmdPar.smscAddress); CatLog.d(this, "The SMS tpdu is: " + cmdPar.pdu); mCmdIf.sendSMS(cmdPar.smscAddress, cmdPar.pdu, null); startTimeOut(WAITING_SMS_RESULT, WAITING_SMS_RESULT_TIME); }
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; }
/** * Handles RIL_UNSOL_STK_EVENT_NOTIFY or RIL_UNSOL_STK_PROACTIVE_COMMAND command from RIL. Sends * valid proactive command data to the application using intents. * RIL_REQUEST_STK_SEND_TERMINAL_RESPONSE will be send back if the command is from * RIL_UNSOL_STK_PROACTIVE_COMMAND. */ private void handleCommand(CommandParams cmdParams, boolean isProactiveCmd) { CatLog.d(this, cmdParams.getCommandType().name()); CharSequence message; CatCmdMessage cmdMsg = new CatCmdMessage(cmdParams); switch (cmdParams.getCommandType()) { case SET_UP_MENU: if (removeMenu(cmdMsg.getMenu())) { mMenuCmd = null; } else { mMenuCmd = cmdMsg; } sendTerminalResponse(cmdParams.cmdDet, ResultCode.OK, false, 0, null); break; case DISPLAY_TEXT: // when application is not required to respond, send an immediate response. if (!cmdMsg.geTextMessage().responseNeeded) { sendTerminalResponse(cmdParams.cmdDet, ResultCode.OK, false, 0, null); } break; case REFRESH: // ME side only handles refresh commands which meant to remove IDLE // MODE TEXT. cmdParams.cmdDet.typeOfCommand = CommandType.SET_UP_IDLE_MODE_TEXT.value(); break; case SET_UP_IDLE_MODE_TEXT: sendTerminalResponse(cmdParams.cmdDet, ResultCode.OK, false, 0, null); break; case PROVIDE_LOCAL_INFORMATION: ResponseData resp; switch (cmdParams.cmdDet.commandQualifier) { case CommandParamsFactory.DTTZ_SETTING: resp = new DTTZResponseData(null); sendTerminalResponse(cmdParams.cmdDet, ResultCode.OK, false, 0, resp); break; case CommandParamsFactory.LANGUAGE_SETTING: resp = new LanguageResponseData(Locale.getDefault().getLanguage()); sendTerminalResponse(cmdParams.cmdDet, ResultCode.OK, false, 0, resp); break; default: sendTerminalResponse(cmdParams.cmdDet, ResultCode.OK, false, 0, null); } // No need to start STK app here. return; case LAUNCH_BROWSER: if ((((LaunchBrowserParams) cmdParams).confirmMsg.text != null) && (((LaunchBrowserParams) cmdParams).confirmMsg.text.equals(STK_DEFAULT))) { message = mContext.getText(com.android.internal.R.string.launchBrowserDefault); ((LaunchBrowserParams) cmdParams).confirmMsg.text = message.toString(); } break; case SELECT_ITEM: case GET_INPUT: case GET_INKEY: break; case SEND_DTMF: case SEND_SMS: case SEND_SS: case SEND_USSD: if ((((DisplayTextParams) cmdParams).textMsg.text != null) && (((DisplayTextParams) cmdParams).textMsg.text.equals(STK_DEFAULT))) { message = mContext.getText(com.android.internal.R.string.sending); ((DisplayTextParams) cmdParams).textMsg.text = message.toString(); } break; case PLAY_TONE: break; case SET_UP_CALL: if ((((CallSetupParams) cmdParams).confirmMsg.text != null) && (((CallSetupParams) cmdParams).confirmMsg.text.equals(STK_DEFAULT))) { message = mContext.getText(com.android.internal.R.string.SetupCallDefault); ((CallSetupParams) cmdParams).confirmMsg.text = message.toString(); } break; case OPEN_CHANNEL: case CLOSE_CHANNEL: case RECEIVE_DATA: case SEND_DATA: BIPClientParams cmd = (BIPClientParams) cmdParams; /* * If the text mesg is null, need to send the response * back to the card in the following scenarios * - It has alpha ID tag with no Text Msg (or) * - If alphaUsrCnf is not set. In the above cases * there should be no UI indication given to the user. */ boolean alphaUsrCnf = SystemProperties.getBoolean(TelephonyProperties.PROPERTY_ALPHA_USRCNF, false); CatLog.d(this, "alphaUsrCnf: " + alphaUsrCnf + ", bHasAlphaId: " + cmd.bHasAlphaId); if ((cmd.textMsg.text == null) && (cmd.bHasAlphaId || !alphaUsrCnf)) { CatLog.d(this, "cmd " + cmdParams.getCommandType() + " with null alpha id"); // If alpha length is zero, we just respond with OK. if (isProactiveCmd) { sendTerminalResponse(cmdParams.cmdDet, ResultCode.OK, false, 0, null); } else if (cmdParams.getCommandType() == CommandType.OPEN_CHANNEL) { mCmdIf.handleCallSetupRequestFromSim(true, null); } return; } // Respond with permanent failure to avoid retry if STK app is not present. if (!mStkAppInstalled) { CatLog.d(this, "No STK application found."); if (isProactiveCmd) { sendTerminalResponse( cmdParams.cmdDet, ResultCode.BEYOND_TERMINAL_CAPABILITY, false, 0, null); return; } } /* * CLOSE_CHANNEL, RECEIVE_DATA and SEND_DATA can be delivered by * either PROACTIVE_COMMAND or EVENT_NOTIFY. * If PROACTIVE_COMMAND is used for those commands, send terminal * response here. */ if (isProactiveCmd && ((cmdParams.getCommandType() == CommandType.CLOSE_CHANNEL) || (cmdParams.getCommandType() == CommandType.RECEIVE_DATA) || (cmdParams.getCommandType() == CommandType.SEND_DATA))) { sendTerminalResponse(cmdParams.cmdDet, ResultCode.OK, false, 0, null); } break; default: CatLog.d(this, "Unsupported command"); return; } mCurrntCmd = cmdMsg; Intent intent = new Intent(AppInterface.CAT_CMD_ACTION); intent.putExtra("STK CMD", cmdMsg); mContext.sendBroadcast(intent); }