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;
  }