public void run() {
    Xlog.d(MmsApp.TXN_TAG, "NotificationTransaction: run()");
    DownloadManager downloadManager = DownloadManager.getInstance();
    // boolean autoDownload = downloadManager.isAuto();
    // boolean dataSuspended = (MmsApp.getApplication().getTelephonyManager().getDataState() ==
    //        TelephonyManager.DATA_SUSPENDED);
    boolean autoDownload = false;
    boolean dataSuspended = false;
    // add for gemini
    if (FeatureOption.MTK_GEMINI_SUPPORT) {
      autoDownload = downloadManager.isAuto(mSimId);
      int datastate =
          MmsApp.getApplication()
              .getTelephonyManager()
              .getDataStateGemini(SIMInfo.getSlotById(mContext, mSimId));
      dataSuspended =
          (datastate == TelephonyManager.DATA_SUSPENDED
              || datastate == TelephonyManager.DATA_DISCONNECTED);
    } else {
      autoDownload = downloadManager.isAuto();
      dataSuspended =
          (MmsApp.getApplication().getTelephonyManager().getDataState()
              == TelephonyManager.DATA_SUSPENDED);
    }

    try {
      if (LOCAL_LOGV) {
        Log.v(TAG, "Notification transaction launched: " + this);
      }

      // By default, we set status to STATUS_DEFERRED because we
      // should response MMSC with STATUS_DEFERRED when we cannot
      // download a MM immediately.
      int status = STATUS_DEFERRED;

      // Check expiry state
      Date CurrentDate = new Date(System.currentTimeMillis());
      Date ExpiryDate = new Date(mNotificationInd.getExpiry() * 1000);
      Xlog.d(
          MmsApp.TXN_TAG,
          "expiry time="
              + ExpiryDate.toLocaleString()
              + "\t current="
              + CurrentDate.toLocaleString());

      // MTK_OP01_PROTECT_START
      /*
      String optr = SystemProperties.get("ro.operator.optr");
      if (optr.equals("OP01")) {
          // Check Message size
          int msgSize = 0;
          Cursor cursor = SqliteWrapper.query(mContext, mContext.getContentResolver(),
                           mUri, new String[] {Mms.MESSAGE_SIZE}, null, null, null);
          if (cursor != null && cursor.getCount() == 1 && cursor.moveToFirst()) {
              try{
                  msgSize = cursor.getInt(0);
                  Xlog.v(MmsApp.TXN_TAG, "msg Size = " + msgSize);
              }finally{
                  cursor.close();
              }
          }

          String netWorkType = null;
          int slotId = -1;
          if (FeatureOption.MTK_GEMINI_SUPPORT) {
              // convert sim id to slot id
              slotId = SIMInfo.getSlotById(mContext, mSimId);
              netWorkType = SystemProperties.get(slotId == 0 ?
                      TelephonyProperties.PROPERTY_CS_NETWORK_TYPE : TelephonyProperties.PROPERTY_CS_NETWORK_TYPE_2);
          } else {
              netWorkType = SystemProperties.get(TelephonyProperties.PROPERTY_CS_NETWORK_TYPE);
          }

          boolean bTDNetwork = Integer.parseInt(netWorkType) > 2 ? true : false;
          if ((!bTDNetwork && MmsConfig.getReceiveMmsLimitFor2G() < msgSize/1024)
                  || (bTDNetwork && MmsConfig.getReceiveMmsLimitForTD() < msgSize/1024)) {
              Xlog.v(MmsApp.TXN_TAG, "Message size exceed limitation, rejected.");

              status = STATUS_REJECTED;
              sendNotifyRespInd(status);
              return;
          }
      }
      */
      // MTK_OP01_PROTECT_END
      // Don't try to download when data is suspended, as it will fail, so defer download
      if (!autoDownload || dataSuspended) {
        Xlog.d(
            MmsApp.TXN_TAG,
            "Not autoDownload! autoDonwload=" + autoDownload + ", dataSuspended=" + dataSuspended);
        if (FeatureOption.MTK_GEMINI_SUPPORT) {
          downloadManager.markState(mUri, DownloadManager.STATE_UNSTARTED, mSimId);
        } else {
          downloadManager.markState(mUri, DownloadManager.STATE_UNSTARTED);
        }
        sendNotifyRespInd(status);
        return;
      }

      if (FeatureOption.MTK_GEMINI_SUPPORT) {
        downloadManager.markState(mUri, DownloadManager.STATE_DOWNLOADING, mSimId);
      } else {
        downloadManager.markState(mUri, DownloadManager.STATE_DOWNLOADING);
      }

      if (LOCAL_LOGV) {
        Log.v(TAG, "Content-Location: " + mContentLocation);
      }

      byte[] retrieveConfData = null;
      // We should catch exceptions here to response MMSC
      // with STATUS_DEFERRED.
      try {
        Xlog.d(MmsApp.TXN_TAG, "NotificationTransaction: before getpdu");
        retrieveConfData = getPdu(mContentLocation);
        Xlog.d(MmsApp.TXN_TAG, "NotificationTransaction: after getpdu");
      } catch (IOException e) {
        mTransactionState.setState(FAILED);
      }

      if (retrieveConfData != null) {
        GenericPdu pdu = new PduParser(retrieveConfData).parse();
        if ((pdu == null) || (pdu.getMessageType() != MESSAGE_TYPE_RETRIEVE_CONF)) {
          Log.e(TAG, "Invalid M-RETRIEVE.CONF PDU.");
          mTransactionState.setState(FAILED);
          status = STATUS_UNRECOGNIZED;
        } else {
          // Save the received PDU (must be a M-RETRIEVE.CONF).
          PduPersister p = PduPersister.getPduPersister(mContext);
          Uri uri = p.persist(pdu, Inbox.CONTENT_URI);
          Xlog.d(MmsApp.TXN_TAG, "PDU Saved, Uri=" + uri + "\nDelete Notify Ind, Uri=" + mUri);
          // add for gemini
          if (FeatureOption.MTK_GEMINI_SUPPORT) {
            ContentResolver cr = mContext.getContentResolver();
            ContentValues values = new ContentValues(1);
            values.put(Mms.SIM_ID, mSimId);
            SqliteWrapper.update(mContext, cr, uri, values, null, null);
          }

          // set message size
          int messageSize = retrieveConfData.length;
          ContentValues sizeValue = new ContentValues();
          sizeValue.put(Mms.MESSAGE_SIZE, messageSize);
          SqliteWrapper.update(mContext, mContext.getContentResolver(), uri, sizeValue, null, null);

          // We have successfully downloaded the new MM. Delete the
          // M-NotifyResp.ind from Inbox.
          String notifId = mUri.getLastPathSegment();
          String msgId = uri.getLastPathSegment();
          if (!notifId.equals(msgId)) {
            SqliteWrapper.delete(mContext, mContext.getContentResolver(), mUri, null, null);
          }
          // Notify observers with newly received MM.
          mUri = uri;
          status = STATUS_RETRIEVED;
        }
      } else {
        Xlog.e(MmsApp.TXN_TAG, "retrieveConfData is null");
        mTransactionState.setState(FAILED);
        status = STATUS_UNRECOGNIZED;
      }

      // Check the status and update the result state of this Transaction.
      switch (status) {
        case STATUS_RETRIEVED:
          mTransactionState.setState(SUCCESS);
          break;
        case STATUS_DEFERRED:
          // STATUS_DEFERRED, may be a failed immediate retrieval.
          if (mTransactionState.getState() == INITIALIZED) {
            mTransactionState.setState(SUCCESS);
          }
          break;
      }
      // if the status is STATUS_UNRECOGNIZED, this happened when we don't get mms pdu from server,
      // this may be a server problem or network problem.
      // our policy is will retry later, so we must response a deferred status not this one.
      // otherwise the server may delete this mms, and when we retry it, it's another mms created by
      // server to
      // inform us that the old mms is not exist yet.
      if (status == STATUS_UNRECOGNIZED) {
        status = STATUS_DEFERRED;
      }
      sendNotifyRespInd(status);

      // Make sure this thread isn't over the limits in message count.
      Recycler.getMmsRecycler().deleteOldMessagesInSameThreadAsMessage(mContext, mUri);
    } catch (Throwable t) {
      Log.e(TAG, Log.getStackTraceString(t));
      if (null != mUri) {
        Recycler.getMmsRecycler().deleteOldMessagesInSameThreadAsMessage(mContext, mUri);
      }
    } finally {
      mTransactionState.setContentUri(mUri);
      if (!autoDownload /*|| dataSuspended*/ /*comment this case for 81452*/) {
        // Always mark the transaction successful for deferred
        // download since any error here doesn't make sense.
        mTransactionState.setState(SUCCESS);
      }
      if (mTransactionState.getState() != SUCCESS) {
        mTransactionState.setState(FAILED);
        Xlog.w(MmsApp.TXN_TAG, "NotificationTransaction failed.");
      }
      notifyObservers();
    }
  }
  public void run() {
    DownloadManager downloadManager = DownloadManager.getInstance();
    boolean autoDownload = downloadManager.isAuto();
    boolean dataSuspended =
        (TelephonyManager.getDefault().getDataState() == TelephonyManager.DATA_SUSPENDED);
    try {
      if (LOCAL_LOGV) {
        Log.v(TAG, "Notification transaction launched: " + this);
      }

      // By default, we set status to STATUS_DEFERRED because we
      // should response MMSC with STATUS_DEFERRED when we cannot
      // download a MM immediately.
      int status = STATUS_DEFERRED;
      // Don't try to download when data is suspended, as it will fail, so defer download
      if (!autoDownload || dataSuspended) {
        downloadManager.markState(mUri, DownloadManager.STATE_UNSTARTED);
        sendNotifyRespInd(status);
        return;
      }

      downloadManager.markState(mUri, DownloadManager.STATE_DOWNLOADING);

      if (LOCAL_LOGV) {
        Log.v(TAG, "Content-Location: " + mContentLocation);
      }

      byte[] retrieveConfData = null;
      // We should catch exceptions here to response MMSC
      // with STATUS_DEFERRED.
      try {
        retrieveConfData = getPdu(mContentLocation);
      } catch (IOException e) {
        mTransactionState.setState(FAILED);
      }

      if (retrieveConfData != null) {
        GenericPdu pdu = new PduParser(retrieveConfData).parse();
        if ((pdu == null) || (pdu.getMessageType() != MESSAGE_TYPE_RETRIEVE_CONF)) {
          Log.e(TAG, "Invalid M-RETRIEVE.CONF PDU.");
          mTransactionState.setState(FAILED);
          status = STATUS_UNRECOGNIZED;
        } else {
          // Save the received PDU (must be a M-RETRIEVE.CONF).
          PduPersister p = PduPersister.getPduPersister(mContext);
          Uri uri = p.persist(pdu, Inbox.CONTENT_URI);
          // We have successfully downloaded the new MM. Delete the
          // M-NotifyResp.ind from Inbox.
          SqliteWrapper.delete(mContext, mContext.getContentResolver(), mUri, null, null);
          // Notify observers with newly received MM.
          mUri = uri;
          status = STATUS_RETRIEVED;
        }
      }

      if (LOCAL_LOGV) {
        Log.v(TAG, "status=0x" + Integer.toHexString(status));
      }

      // Check the status and update the result state of this Transaction.
      switch (status) {
        case STATUS_RETRIEVED:
          mTransactionState.setState(SUCCESS);
          break;
        case STATUS_DEFERRED:
          // STATUS_DEFERRED, may be a failed immediate retrieval.
          if (mTransactionState.getState() == INITIALIZED) {
            mTransactionState.setState(SUCCESS);
          }
          break;
      }

      sendNotifyRespInd(status);

      // Make sure this thread isn't over the limits in message count.
      Recycler.getMmsRecycler().deleteOldMessagesInSameThreadAsMessage(mContext, mUri);
    } catch (Throwable t) {
      Log.e(TAG, Log.getStackTraceString(t));
    } finally {
      mTransactionState.setContentUri(mUri);
      if (!autoDownload || dataSuspended) {
        // Always mark the transaction successful for deferred
        // download since any error here doesn't make sense.
        mTransactionState.setState(SUCCESS);
      }
      if (mTransactionState.getState() != SUCCESS) {
        mTransactionState.setState(FAILED);
        Log.e(TAG, "NotificationTransaction failed.");
      }
      notifyObservers();
    }
  }
  private void bindNotifInd() {
    showMmsView(false);

    String msgSizeText =
        mContext.getString(R.string.message_size_label)
            + String.valueOf((mMessageItem.mMessageSize + 1023) / 1024)
            + mContext.getString(R.string.kilobyte);

    mBodyTextView.setText(
        formatMessage(
            mMessageItem,
            mMessageItem.mContact,
            null,
            mMessageItem.mSubject,
            mMessageItem.mHighlight,
            mMessageItem.mTextContentType));

    mDateView.setText(msgSizeText + " " + mMessageItem.mTimestamp);

    switch (mMessageItem.getMmsDownloadStatus()) {
      case DownloadManager.STATE_DOWNLOADING:
        showDownloadingAttachment();
        break;
      case DownloadManager.STATE_UNKNOWN:
      case DownloadManager.STATE_UNSTARTED:
        DownloadManager downloadManager = DownloadManager.getInstance();
        boolean autoDownload = downloadManager.isAuto();
        boolean dataSuspended =
            (MmsApp.getApplication().getTelephonyManager().getDataState()
                == TelephonyManager.DATA_SUSPENDED);

        // If we're going to automatically start downloading the mms attachment, then
        // don't bother showing the download button for an instant before the actual
        // download begins. Instead, show downloading as taking place.
        if (autoDownload && !dataSuspended) {
          showDownloadingAttachment();
          break;
        }
      case DownloadManager.STATE_TRANSIENT_FAILURE:
      case DownloadManager.STATE_PERMANENT_FAILURE:
      default:
        setLongClickable(true);
        inflateDownloadControls();
        mDownloadingLabel.setVisibility(View.GONE);
        mDownloadButton.setVisibility(View.VISIBLE);
        mDownloadButton.setOnClickListener(
            new OnClickListener() {
              @Override
              public void onClick(View v) {
                mDownloadingLabel.setVisibility(View.VISIBLE);
                mDownloadButton.setVisibility(View.GONE);
                Intent intent = new Intent(mContext, TransactionService.class);
                intent.putExtra(TransactionBundle.URI, mMessageItem.mMessageUri.toString());
                intent.putExtra(
                    TransactionBundle.TRANSACTION_TYPE, Transaction.RETRIEVE_TRANSACTION);
                mContext.startService(intent);
              }
            });
        break;
    }

    // Hide the indicators.
    mLockedIndicator.setVisibility(View.GONE);
    mDeliveredIndicator.setVisibility(View.GONE);
    mDetailsIndicator.setVisibility(View.GONE);
    updateAvatarView(mMessageItem.mAddress, false);
  }