@Override
  protected void processUnsolicited(Parcel p) {
    int response;
    Object ret;

    response = p.readInt();

    try {
      switch (response) {
          /*
          cat libs/telephony/ril_unsol_commands.h \
          | egrep "^ *{RIL_" \
          | sed -re 's/\{([^,]+),[^,]+,([^}]+).+/case \1: \2(rr, p); break;/'
               */

        case RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED:
          ret = responseVoid(p);
          break;
        case RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED:
          ret = responseVoid(p);
          break;
        case RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED:
          ret = responseVoid(p);
          break;
        case RIL_UNSOL_RESPONSE_NEW_SMS:
          ret = responseString(p);
          break;
        case RIL_UNSOL_RESPONSE_NEW_SMS_STATUS_REPORT:
          ret = responseString(p);
          break;
        case RIL_UNSOL_RESPONSE_NEW_SMS_ON_SIM:
          ret = responseInts(p);
          break;
        case RIL_UNSOL_ON_USSD:
          ret = responseStrings(p);
          break;
        case RIL_UNSOL_NITZ_TIME_RECEIVED:
          ret = responseString(p);
          break;
        case RIL_UNSOL_SIGNAL_STRENGTH:
          ret = responseSignalStrength(p);
          break;
        case RIL_UNSOL_DATA_CALL_LIST_CHANGED:
          ret = responseDataCallList(p);
          break;
        case RIL_UNSOL_SUPP_SVC_NOTIFICATION:
          ret = responseSuppServiceNotification(p);
          break;
        case RIL_UNSOL_STK_SESSION_END:
          ret = responseVoid(p);
          break;
        case RIL_UNSOL_STK_PROACTIVE_COMMAND:
          ret = responseString(p);
          break;
        case RIL_UNSOL_STK_EVENT_NOTIFY:
          ret = responseString(p);
          break;
        case RIL_UNSOL_STK_CALL_SETUP:
          ret = responseInts(p);
          break;
        case RIL_UNSOL_SIM_SMS_STORAGE_FULL:
          ret = responseVoid(p);
          break;
        case RIL_UNSOL_SIM_REFRESH:
          ret = responseInts(p);
          break;
        case RIL_UNSOL_CALL_RING:
          ret = responseCallRing(p);
          break;
        case RIL_UNSOL_RESTRICTED_STATE_CHANGED:
          ret = responseInts(p);
          break;
        case RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED:
          ret = responseVoid(p);
          break;
        case RIL_UNSOL_RESPONSE_CDMA_NEW_SMS:
          ret = responseCdmaSms(p);
          break;
        case RIL_UNSOL_RESPONSE_NEW_BROADCAST_SMS:
          ret = responseString(p);
          break;
        case RIL_UNSOL_CDMA_RUIM_SMS_STORAGE_FULL:
          ret = responseVoid(p);
          break;
        case RIL_UNSOL_ENTER_EMERGENCY_CALLBACK_MODE:
          ret = responseVoid(p);
          break;
        case RIL_UNSOL_CDMA_CALL_WAITING:
          ret = responseCdmaCallWaiting(p);
          break;
        case RIL_UNSOL_CDMA_OTA_PROVISION_STATUS:
          ret = responseInts(p);
          break;
        case RIL_UNSOL_CDMA_INFO_REC:
          ret = responseCdmaInformationRecord(p);
          break;
        case RIL_UNSOL_OEM_HOOK_RAW:
          ret = responseRaw(p);
          break;
        case RIL_UNSOL_RINGBACK_TONE:
          ret = responseInts(p);
          break;
        case RIL_UNSOL_RESEND_INCALL_MUTE:
          ret = responseVoid(p);
          break;
        case RIL_UNSOL_HSDPA_STATE_CHANGED:
          ret = responseVoid(p);
          break;

          // fixing anoying Exceptions caused by the new Samsung states
          // FIXME figure out what the states mean an what data is in the parcel

        case RIL_UNSOL_O2_HOME_ZONE_INFO:
          ret = responseVoid(p);
          break;
        case RIL_UNSOL_STK_SEND_SMS_RESULT:
          ret = responseVoid(p);
          break;
        case RIL_UNSOL_DEVICE_READY_NOTI:
          ret = responseVoid(p);
          break;
        case RIL_UNSOL_SAMSUNG_UNKNOWN_MAGIC_REQUEST:
          ret = responseVoid(p);
          break;
        case RIL_UNSOL_SAMSUNG_UNKNOWN_MAGIC_REQUEST_2:
          ret = responseVoid(p);
          break;
        case RIL_UNSOL_SAMSUNG_UNKNOWN_MAGIC_REQUEST_3:
          ret = responseVoid(p);
          break;

        default:
          throw new RuntimeException("Unrecognized unsol response: " + response);
          // break; (implied)
      }
    } catch (Throwable tr) {
      Log.e(
          LOG_TAG,
          "Exception processing unsol response: " + response + "Exception:" + tr.toString());
      return;
    }

    switch (response) {
      case RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED:
        /* has bonus radio state int */
        RadioState newState = getRadioStateFromInt(p.readInt());
        if (RILJ_LOGD) unsljLogMore(response, newState.toString());

        switchToRadioState(newState);
        break;
      case RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED:
        if (RILJ_LOGD) unsljLog(response);

        mCallStateRegistrants.notifyRegistrants(new AsyncResult(null, null, null));
        break;
      case RIL_UNSOL_HSDPA_STATE_CHANGED:
        if (RILJ_LOGD) unsljLog(response);

        mVoiceNetworkStateRegistrants.notifyRegistrants(new AsyncResult(null, null, null));
        break;

      case RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED:
        if (RILJ_LOGD) unsljLog(response);

        mVoiceNetworkStateRegistrants.notifyRegistrants(new AsyncResult(null, null, null));
        break;
      case RIL_UNSOL_RESPONSE_NEW_SMS:
        {
          if (RILJ_LOGD) unsljLog(response);

          // FIXME this should move up a layer
          String a[] = new String[2];

          a[1] = (String) ret;

          SmsMessage sms;

          sms = SmsMessage.newFromCMT(a);
          if (mGsmSmsRegistrant != null) {
            mGsmSmsRegistrant.notifyRegistrant(new AsyncResult(null, sms, null));
          }
          break;
        }
      case RIL_UNSOL_RESPONSE_NEW_SMS_STATUS_REPORT:
        if (RILJ_LOGD) unsljLogRet(response, ret);

        if (mSmsStatusRegistrant != null) {
          mSmsStatusRegistrant.notifyRegistrant(new AsyncResult(null, ret, null));
        }
        break;
      case RIL_UNSOL_RESPONSE_NEW_SMS_ON_SIM:
        if (RILJ_LOGD) unsljLogRet(response, ret);

        int[] smsIndex = (int[]) ret;

        if (smsIndex.length == 1) {
          if (mSmsOnSimRegistrant != null) {
            mSmsOnSimRegistrant.notifyRegistrant(new AsyncResult(null, smsIndex, null));
          }
        } else {
          if (RILJ_LOGD) riljLog(" NEW_SMS_ON_SIM ERROR with wrong length " + smsIndex.length);
        }
        break;
      case RIL_UNSOL_ON_USSD:
        String[] resp = (String[]) ret;

        if (resp.length < 2) {
          resp = new String[2];
          resp[0] = ((String[]) ret)[0];
          resp[1] = null;
        }
        if (RILJ_LOGD) unsljLogMore(response, resp[0]);
        if (mUSSDRegistrant != null) {
          mUSSDRegistrant.notifyRegistrant(new AsyncResult(null, resp, null));
        }
        break;
      case RIL_UNSOL_NITZ_TIME_RECEIVED:
        if (RILJ_LOGD) unsljLogRet(response, ret);

        // has bonus long containing milliseconds since boot that the NITZ
        // time was received
        long nitzReceiveTime = p.readLong();

        Object[] result = new Object[2];

        String nitz = (String) ret;
        if (RILJ_LOGD)
          riljLog(" RIL_UNSOL_NITZ_TIME_RECEIVED length = " + nitz.split("[/:,+-]").length);
        // remove the tailing information that samsung added to the string
        // it will screw the NITZ parser
        if (nitz.split("[/:,+-]").length >= 9) nitz = nitz.substring(0, (nitz.lastIndexOf(",")));
        if (RILJ_LOGD) riljLog(" RIL_UNSOL_NITZ_TIME_RECEIVED striped nitz = " + nitz);
        result[0] = nitz;
        result[1] = Long.valueOf(nitzReceiveTime);

        if (mNITZTimeRegistrant != null) {

          mNITZTimeRegistrant.notifyRegistrant(new AsyncResult(null, result, null));
        } else {
          // in case NITZ time registrant isnt registered yet
          mLastNITZTimeInfo = nitz;
        }
        break;

      case RIL_UNSOL_SIGNAL_STRENGTH:
        // Note this is set to "verbose" because it happens
        // frequently
        if (RILJ_LOGV) unsljLogvRet(response, ret);

        if (mSignalStrengthRegistrant != null) {
          mSignalStrengthRegistrant.notifyRegistrant(new AsyncResult(null, ret, null));
        }
        break;
      case RIL_UNSOL_DATA_CALL_LIST_CHANGED:
        if (RILJ_LOGD) unsljLogRet(response, ret);

        mDataNetworkStateRegistrants.notifyRegistrants(new AsyncResult(null, ret, null));
        break;

      case RIL_UNSOL_SUPP_SVC_NOTIFICATION:
        if (RILJ_LOGD) unsljLogRet(response, ret);

        if (mSsnRegistrant != null) {
          mSsnRegistrant.notifyRegistrant(new AsyncResult(null, ret, null));
        }
        break;

      case RIL_UNSOL_STK_SESSION_END:
        if (RILJ_LOGD) unsljLog(response);

        if (mCatSessionEndRegistrant != null) {
          mCatSessionEndRegistrant.notifyRegistrant(new AsyncResult(null, ret, null));
        }
        break;

      case RIL_UNSOL_STK_PROACTIVE_COMMAND:
        if (RILJ_LOGD) unsljLogRet(response, ret);

        if (mCatProCmdRegistrant != null) {
          mCatProCmdRegistrant.notifyRegistrant(new AsyncResult(null, ret, null));
        }
        break;

      case RIL_UNSOL_STK_EVENT_NOTIFY:
        if (RILJ_LOGD) unsljLogRet(response, ret);

        if (mCatEventRegistrant != null) {
          mCatEventRegistrant.notifyRegistrant(new AsyncResult(null, ret, null));
        }
        break;

      case RIL_UNSOL_STK_CALL_SETUP:
        if (RILJ_LOGD) unsljLogRet(response, ret);

        if (mCatCallSetUpRegistrant != null) {
          mCatCallSetUpRegistrant.notifyRegistrant(new AsyncResult(null, ret, null));
        }
        break;

      case RIL_UNSOL_SIM_SMS_STORAGE_FULL:
        if (RILJ_LOGD) unsljLog(response);

        if (mIccSmsFullRegistrant != null) {
          mIccSmsFullRegistrant.notifyRegistrant();
        }
        break;

      case RIL_UNSOL_SIM_REFRESH:
        if (RILJ_LOGD) unsljLogRet(response, ret);

        if (mIccRefreshRegistrants != null) {
          mIccRefreshRegistrants.notifyRegistrants(new AsyncResult(null, ret, null));
        }
        break;

      case RIL_UNSOL_CALL_RING:
        if (RILJ_LOGD) unsljLogRet(response, ret);

        if (mRingRegistrant != null) {
          mRingRegistrant.notifyRegistrant(new AsyncResult(null, ret, null));
        }
        break;

      case RIL_UNSOL_RESTRICTED_STATE_CHANGED:
        if (RILJ_LOGD) unsljLogvRet(response, ret);
        if (mRestrictedStateRegistrant != null) {
          mRestrictedStateRegistrant.notifyRegistrant(new AsyncResult(null, ret, null));
        }
        break;

      case RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED:
        if (RILJ_LOGD) unsljLog(response);

        if (mIccStatusChangedRegistrants != null) {
          mIccStatusChangedRegistrants.notifyRegistrants();
        }
        break;

      case RIL_UNSOL_RESPONSE_CDMA_NEW_SMS:
        if (RILJ_LOGD) unsljLog(response);

        SmsMessage sms = (SmsMessage) ret;

        if (mCdmaSmsRegistrant != null) {
          mCdmaSmsRegistrant.notifyRegistrant(new AsyncResult(null, sms, null));
        }
        break;

      case RIL_UNSOL_RESPONSE_NEW_BROADCAST_SMS:
        if (RILJ_LOGD) unsljLog(response);

        if (mGsmBroadcastSmsRegistrant != null) {
          mGsmBroadcastSmsRegistrant.notifyRegistrant(new AsyncResult(null, ret, null));
        }
        break;

      case RIL_UNSOL_CDMA_RUIM_SMS_STORAGE_FULL:
        if (RILJ_LOGD) unsljLog(response);

        if (mIccSmsFullRegistrant != null) {
          mIccSmsFullRegistrant.notifyRegistrant();
        }
        break;

      case RIL_UNSOL_ENTER_EMERGENCY_CALLBACK_MODE:
        if (RILJ_LOGD) unsljLog(response);

        if (mEmergencyCallbackModeRegistrant != null) {
          mEmergencyCallbackModeRegistrant.notifyRegistrant();
        }
        break;

      case RIL_UNSOL_CDMA_CALL_WAITING:
        if (RILJ_LOGD) unsljLogRet(response, ret);

        if (mCallWaitingInfoRegistrants != null) {
          mCallWaitingInfoRegistrants.notifyRegistrants(new AsyncResult(null, ret, null));
        }
        break;

      case RIL_UNSOL_CDMA_OTA_PROVISION_STATUS:
        if (RILJ_LOGD) unsljLogRet(response, ret);

        if (mOtaProvisionRegistrants != null) {
          mOtaProvisionRegistrants.notifyRegistrants(new AsyncResult(null, ret, null));
        }
        break;

      case RIL_UNSOL_CDMA_INFO_REC:
        ArrayList<CdmaInformationRecords> listInfoRecs;

        try {
          listInfoRecs = (ArrayList<CdmaInformationRecords>) ret;
        } catch (ClassCastException e) {
          Log.e(LOG_TAG, "Unexpected exception casting to listInfoRecs", e);
          break;
        }

        for (CdmaInformationRecords rec : listInfoRecs) {
          if (RILJ_LOGD) unsljLogRet(response, rec);
          notifyRegistrantsCdmaInfoRec(rec);
        }
        break;

      case RIL_UNSOL_OEM_HOOK_RAW:
        if (RILJ_LOGD) unsljLogvRet(response, IccUtils.bytesToHexString((byte[]) ret));
        if (mUnsolOemHookRawRegistrant != null) {
          mUnsolOemHookRawRegistrant.notifyRegistrant(new AsyncResult(null, ret, null));
        }
        break;

      case RIL_UNSOL_RINGBACK_TONE:
        if (RILJ_LOGD) unsljLogvRet(response, ret);
        if (mRingbackToneRegistrants != null) {
          boolean playtone = (((int[]) ret)[0] == 1);
          mRingbackToneRegistrants.notifyRegistrants(new AsyncResult(null, playtone, null));
        }
        break;

      case RIL_UNSOL_RESEND_INCALL_MUTE:
        if (RILJ_LOGD) unsljLogRet(response, ret);

        if (mResendIncallMuteRegistrants != null) {
          mResendIncallMuteRegistrants.notifyRegistrants(new AsyncResult(null, ret, null));
        }
    }
  }
  @Override
  protected void processUnsolicited(Parcel p) {
    Object ret;
    int dataPosition = p.dataPosition();
    int response = p.readInt();

    switch (response) {
      case RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED:
        ret = responseVoid(p);
        break;
      case RIL_UNSOL_RESPONSE_NEW_BROADCAST_SMS:
        ret = responseString(p);
        break;
      case RIL_UNSOL_RIL_CONNECTED:
        ret = responseInts(p);
        break;
        // SAMSUNG STATES
      case RIL_UNSOL_AM:
        ret = responseString(p);
        break;
      case RIL_UNSOL_DUN_PIN_CONTROL_SIGNAL:
        ret = responseVoid(p);
        break;
      case RIL_UNSOL_DATA_SUSPEND_RESUME:
        ret = responseInts(p);
        break;
      case RIL_UNSOL_STK_CALL_CONTROL_RESULT:
        ret = responseVoid(p);
        break;
      case RIL_UNSOL_TWO_MIC_STATE:
        ret = responseInts(p);
        break;
      case RIL_UNSOL_WB_AMR_STATE:
        ret = responseInts(p);
        break;

      default:
        // Rewind the Parcel
        p.setDataPosition(dataPosition);

        // Forward responses that we are not overriding to the super class
        super.processUnsolicited(p);
        return;
    }

    switch (response) {
      case RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED:
        /* has bonus radio state int */
        int state = p.readInt();
        Log.d(LOG_TAG, "Radio state: " + state);

        switch (state) {
          case 2:
            // RADIO_UNAVAILABLE
            state = 1;
            break;
          case 3:
            // RADIO_ON
            state = 10;
            break;
          case 4:
            // RADIO_ON
            state = 10;
            // When SIM is PIN-unlocked, RIL doesn't respond with
            // RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED.
            // We notify the system here.
            Log.d(LOG_TAG, "SIM is PIN-unlocked now");
            if (mIccStatusChangedRegistrants != null) {
              mIccStatusChangedRegistrants.notifyRegistrants();
            }
            break;
        }
        RadioState newState = getRadioStateFromInt(state);
        Log.d(LOG_TAG, "New Radio state: " + state + " (" + newState.toString() + ")");
        switchToRadioState(newState);
        break;
      case RIL_UNSOL_RESPONSE_NEW_BROADCAST_SMS:
        if (RILJ_LOGD) unsljLogRet(response, ret);

        if (mGsmBroadcastSmsRegistrant != null) {
          mGsmBroadcastSmsRegistrant.notifyRegistrant(new AsyncResult(null, ret, null));
        }
        break;
      case RIL_UNSOL_RIL_CONNECTED:
        if (RILJ_LOGD) unsljLogRet(response, ret);

        // Initial conditions
        setRadioPower(false, null);
        sendPreferedNetworktype(mPreferredNetworkType, null);
        setCdmaSubscriptionSource(mCdmaSubscription, null);
        notifyRegistrantsRilConnectionChanged(((int[]) ret)[0]);
        break;
        // SAMSUNG STATES
      case RIL_UNSOL_AM:
        if (RILJ_LOGD) samsungUnsljLogRet(response, ret);
        String amString = (String) ret;
        Log.d(LOG_TAG, "Executing AM: " + amString);

        try {
          Runtime.getRuntime().exec("am " + amString);
        } catch (IOException e) {
          e.printStackTrace();
          Log.e(LOG_TAG, "am " + amString + " could not be executed.");
        }
        break;
      case RIL_UNSOL_DUN_PIN_CONTROL_SIGNAL:
        if (RILJ_LOGD) samsungUnsljLogRet(response, ret);
        break;
      case RIL_UNSOL_DATA_SUSPEND_RESUME:
        if (RILJ_LOGD) samsungUnsljLogRet(response, ret);
        break;
      case RIL_UNSOL_STK_CALL_CONTROL_RESULT:
        if (RILJ_LOGD) samsungUnsljLogRet(response, ret);
        break;
      case RIL_UNSOL_TWO_MIC_STATE:
        if (RILJ_LOGD) samsungUnsljLogRet(response, ret);
        break;
      case RIL_UNSOL_WB_AMR_STATE:
        if (RILJ_LOGD) samsungUnsljLogRet(response, ret);
        setWbAmr(((int[]) ret)[0]);
        break;
    }
  }