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