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);
  }
 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;
 }
コード例 #3
0
  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;
  }