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 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());

    // 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);
  }
  /**
   * 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);
  }