private void onUpdateIccAvailability() {
    if (mUiccController == null) {
      return;
    }

    UiccCardApplication newUiccApplication = getUiccCardApplication();

    UiccCardApplication app = mUiccApplication.get();
    if (app != newUiccApplication) {
      if (app != null) {
        Rlog.d(TAG, "Removing stale icc objects.");
        if (mIccRecords.get() != null) {
          mIccRecords.get().unregisterForNewSms(this);
        }
        mIccRecords.set(null);
        mUiccApplication.set(null);
      }
      if (newUiccApplication != null) {
        Rlog.d(TAG, "New Uicc application found");
        mUiccApplication.set(newUiccApplication);
        mIccRecords.set(newUiccApplication.getIccRecords());
        if (mIccRecords.get() != null) {
          mIccRecords.get().registerForNewSms(this, EVENT_NEW_ICC_SMS, null);
        }
      }
    }
  }
  /* Sets the default subscription. If only one phone instance is active that
   * subscription is set as default subscription. If both phone instances
   * are active the first instance "0" is set as default subscription
   */
  public static void setDefaultSubscription(int subId) {
    SystemProperties.set(PROPERTY_DEFAULT_SUBSCRIPTION, Integer.toString(subId));
    int phoneId = SubscriptionController.getInstance().getPhoneId(subId);

    synchronized (sLockProxyPhones) {
      // Set the default phone in base class
      if (phoneId >= 0 && phoneId < sProxyPhones.length) {
        sProxyPhone = sProxyPhones[phoneId];
        sCommandsInterface = sCommandsInterfaces[phoneId];
        sMadeDefaults = true;
      }
    }

    // Update MCC MNC device configuration information
    String defaultMccMnc = TelephonyManager.getDefault().getSimOperatorNumericForPhone(phoneId);
    if (DBG) Rlog.d(LOG_TAG, "update mccmnc=" + defaultMccMnc);
    MccTable.updateMccMncConfiguration(sContext, defaultMccMnc, false);

    // Broadcast an Intent for default sub change
    Intent intent = new Intent(TelephonyIntents.ACTION_DEFAULT_SUBSCRIPTION_CHANGED);
    intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
    SubscriptionManager.putPhoneIdAndSubIdExtra(intent, phoneId);
    Rlog.d(
        LOG_TAG,
        "setDefaultSubscription : " + subId + " Broadcasting Default Subscription Changed...");
    sContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
  }
  /**
   * Returns the tpdu from the pdu
   *
   * @return the tpdu for the message.
   * @hide
   */
  public byte[] getTpdu(String format) {
    Rlog.d(LOG_TAG, "call getTpdu with format: " + format);
    byte[] pdu = this.getPdu();
    if (format.equals(FORMAT_3GPP)) {
      if (pdu == null) {
        Rlog.d(LOG_TAG, "pdu is null");
        return null;
      }

      int smsc_len = (pdu[0] & 0xff) + 1;
      int tpdu_len = pdu.length - smsc_len;
      byte[] tpdu = new byte[tpdu_len];

      try {
        System.arraycopy(pdu, smsc_len, tpdu, 0, tpdu.length);
        return tpdu;
      } catch (ArrayIndexOutOfBoundsException e) {
        Rlog.e(LOG_TAG, "Out of boudns");
        return null;
      }
    } else if (format.equals(FORMAT_3GPP2)) {
      return pdu;
    }

    return super.getTpdu();
  }
 /**
  * Set audio parameter "wb_amr" for HD-Voice (Wideband AMR).
  *
  * @param state: 0 = unsupported, 1 = supported. REQUIRED FOR JF FAMILY THIS SETS THE INFORMATION
  *     CRASHES WITHOUT THIS FUNCTION part of the new csd binary
  */
 private void setWbAmr(int state) {
   if (state == 1) {
     Rlog.d(RILJ_LOG_TAG, "setWbAmr(): setting audio parameter - wb_amr=on");
     mAudioManager.setParameters("wide_voice_enable=true");
   } else if (state == 0) {
     Rlog.d(RILJ_LOG_TAG, "setWbAmr(): setting audio parameter - wb_amr=off");
     mAudioManager.setParameters("wide_voice_enable=false");
   }
 }
Example #5
0
  private void loadSpnOverrides() {
    FileReader spnReader;

    File spnFile = new File(Environment.getRootDirectory(), PARTNER_SPN_OVERRIDE_PATH);
    File oemSpnFile = new File(Environment.getOemDirectory(), OEM_SPN_OVERRIDE_PATH);

    if (oemSpnFile.exists()) {
      // OEM image exist SPN xml, get the timestamp from OEM & System image for comparison.
      long oemSpnTime = oemSpnFile.lastModified();
      long sysSpnTime = spnFile.lastModified();
      Rlog.d(LOG_TAG, "SPN Timestamp: oemTime = " + oemSpnTime + " sysTime = " + sysSpnTime);

      // To get the newer version of SPN from OEM image
      if (oemSpnTime > sysSpnTime) {
        Rlog.d(LOG_TAG, "SPN in OEM image is newer than System image");
        spnFile = oemSpnFile;
      }
    } else {
      // No SPN in OEM image, so load it from system image.
      Rlog.d(
          LOG_TAG, "No SPN in OEM image = " + oemSpnFile.getPath() + " Load SPN from system image");
    }

    try {
      spnReader = new FileReader(spnFile);
    } catch (FileNotFoundException e) {
      Rlog.w(LOG_TAG, "Can not open " + spnFile.getAbsolutePath());
      return;
    }

    try {
      XmlPullParser parser = Xml.newPullParser();
      parser.setInput(spnReader);

      XmlUtils.beginDocument(parser, "spnOverrides");

      while (true) {
        XmlUtils.nextElement(parser);

        String name = parser.getName();
        if (!"spnOverride".equals(name)) {
          break;
        }

        String numeric = parser.getAttributeValue(null, "numeric");
        String data = parser.getAttributeValue(null, "spn");

        mCarrierSpnMap.put(numeric, data);
      }
      spnReader.close();
    } catch (XmlPullParserException e) {
      Rlog.w(LOG_TAG, "Exception in spn-conf parser " + e);
    } catch (IOException e) {
      Rlog.w(LOG_TAG, "Exception in spn-conf parser " + e);
    }
  }
 /**
  * Create an SmsMessage from a raw PDU.
  *
  * @param pdu raw data for creating short message
  * @param simId SIM ID
  */
 public static GeminiSmsMessage createFromPdu(byte[] pdu, int simId) {
   String format = GeminiSmsMessage.getSmsFormat(simId);
   Rlog.d(LOG_TAG, "create SmsMessage from pdu with format " + format);
   SmsMessage sms = createFromPdu(pdu, format);
   if (sms != null) {
     return new GeminiSmsMessage(sms, simId);
   } else {
     Rlog.d(LOG_TAG, "fail to create SmsMessage from pdu");
     return null;
   }
 }
 private void readFromParcel(Parcel in) {
   dialogSize = in.readInt();
   Rlog.d(TAG, "readFromParcel size = " + dialogSize);
   if (dialogSize < 0) {
     return;
   }
   callInfo = new ArrayList<String[]>();
   for (int i = 0; i < dialogSize; i++) {
     String[] info = new String[INDEX_MAX];
     info = in.createStringArray(); // read each string[]
     callInfo.add(info);
   }
   Rlog.d(TAG, "readFromParcel - " + toString());
 }
  private void parseSmsDeliver(PduParser p, int firstByte) {
    mReplyPathPresent = (firstByte & 0x80) == 0x80;

    mOriginatingAddress = p.getAddress();

    if (mOriginatingAddress != null) {
      if (VDBG) Rlog.v(LOG_TAG, "SMS originating address: " + mOriginatingAddress.address);
    }

    // TP-Protocol-Identifier (TP-PID)
    // TS 23.040 9.2.3.9
    mProtocolIdentifier = p.getByte();

    // TP-Data-Coding-Scheme
    // see TS 23.038
    mDataCodingScheme = p.getByte();

    if (VDBG) {
      Rlog.v(
          LOG_TAG,
          "SMS TP-PID:" + mProtocolIdentifier + " data coding scheme: " + mDataCodingScheme);
    }

    mScTimeMillis = p.getSCTimestampMillis();

    if (VDBG) Rlog.d(LOG_TAG, "SMS SC timestamp: " + mScTimeMillis);

    boolean hasUserDataHeader = (firstByte & 0x40) == 0x40;

    parseUserData(p, hasUserDataHeader);
  }
  // Workaround for Samsung CDMA "ring of death" bug:
  //
  // Symptom: As soon as the phone receives notice of an incoming call, an
  // audible "old fashioned ring" is emitted through the earpiece and
  // persists through the duration of the call, or until reboot if the call
  // isn't answered.
  //
  // Background: The CDMA telephony stack implements a number of "signal info
  // tones" that are locally generated by ToneGenerator and mixed into the
  // voice call path in response to radio RIL_UNSOL_CDMA_INFO_REC requests.
  // One of these tones, IS95_CONST_IR_SIG_IS54B_L, is requested by the
  // radio just prior to notice of an incoming call when the voice call
  // path is muted. CallNotifier is responsible for stopping all signal
  // tones (by "playing" the TONE_CDMA_SIGNAL_OFF tone) upon receipt of a
  // "new ringing connection", prior to unmuting the voice call path.
  //
  // Problem: CallNotifier's incoming call path is designed to minimize
  // latency to notify users of incoming calls ASAP. Thus,
  // SignalInfoTonePlayer requests are handled asynchronously by spawning a
  // one-shot thread for each. Unfortunately the ToneGenerator API does
  // not provide a mechanism to specify an ordering on requests, and thus,
  // unexpected thread interleaving may result in ToneGenerator processing
  // them in the opposite order that CallNotifier intended. In this case,
  // playing the "signal off" tone first, followed by playing the "old
  // fashioned ring" indefinitely.
  //
  // Solution: An API change to ToneGenerator is required to enable
  // SignalInfoTonePlayer to impose an ordering on requests (i.e., drop any
  // request that's older than the most recent observed). Such a change,
  // or another appropriate fix should be implemented in AOSP first.
  //
  // Workaround: Intercept RIL_UNSOL_CDMA_INFO_REC requests from the radio,
  // check for a signal info record matching IS95_CONST_IR_SIG_IS54B_L, and
  // drop it so it's never seen by CallNotifier. If other signal tones are
  // observed to cause this problem, they should be dropped here as well.
  @Override
  protected void notifyRegistrantsCdmaInfoRec(CdmaInformationRecords infoRec) {
    final int response = RIL_UNSOL_CDMA_INFO_REC;

    if (infoRec.record instanceof CdmaSignalInfoRec) {
      CdmaSignalInfoRec sir = (CdmaSignalInfoRec) infoRec.record;
      if (sir != null
          && sir.isPresent
          && sir.signalType == SignalToneUtil.IS95_CONST_IR_SIGNAL_IS54B
          && sir.alertPitch == SignalToneUtil.IS95_CONST_IR_ALERT_MED
          && sir.signal == SignalToneUtil.IS95_CONST_IR_SIG_IS54B_L) {

        Rlog.d(
            RILJ_LOG_TAG,
            "Dropping \""
                + responseToString(response)
                + " "
                + retToString(response, sir)
                + "\" to prevent \"ring of death\" bug.");
        return;
      }
    }

    super.notifyRegistrantsCdmaInfoRec(infoRec);
  }
 /**
  * dialogIds Will have following information - dialogIds[INDEX_DIALOG_ID] - Holds Unique DialogId
  * dialogIds[INDEX_NUMBER] - Holds number/uri dialogIds[INDEX_ISPULLABLE] - Pullable/NonPullable
  * (true, false) dialogIds[INDEX_CALLTYPE] - CallType CallType - volteactive, volteheld, vttxrx,
  * vttx, vtrx, vtheld dialogIds[INDEX_DIRECTION] - Direction of the call (Originator/recipent)
  */
 public QtiViceInfo(List<String[]> dialogIds) {
   if (dialogIds != null) {
     callInfo = new ArrayList<String[]>();
     dialogSize = dialogIds.size();
     callInfo = dialogIds;
     Rlog.d(TAG, "QtiViceInfo const = " + toString());
   }
 }
Example #11
0
  /** Process a MMI PUK code */
  void processCode() {
    try {
      if (isPinPukCommand()) {
        // TODO: This is the same as the code in GsmMmiCode.java,
        // MmiCode should be an abstract or base class and this and
        // other common variables and code should be promoted.

        // sia = old PIN or PUK
        // sib = new PIN
        // sic = new PIN
        String oldPinOrPuk = mSia;
        String newPinOrPuk = mSib;
        int pinLen = newPinOrPuk.length();
        if (isRegister()) {
          if (!newPinOrPuk.equals(mSic)) {
            // password mismatch; return error
            handlePasswordError(com.android.internal.R.string.mismatchPin);
          } else if (pinLen < 4 || pinLen > 8) {
            // invalid length
            handlePasswordError(com.android.internal.R.string.invalidPin);
          } else if (mSc.equals(SC_PIN)
              && mUiccApplication != null
              && mUiccApplication.getState() == AppState.APPSTATE_PUK) {
            // Sim is puk-locked
            handlePasswordError(com.android.internal.R.string.needPuk);
          } else if (mUiccApplication != null) {
            Rlog.d(LOG_TAG, "process mmi service code using UiccApp sc=" + mSc);

            // We have an app and the pre-checks are OK
            if (mSc.equals(SC_PIN)) {
              mUiccApplication.changeIccLockPassword(
                  oldPinOrPuk, newPinOrPuk, obtainMessage(EVENT_SET_COMPLETE, this));
            } else if (mSc.equals(SC_PIN2)) {
              mUiccApplication.changeIccFdnPassword(
                  oldPinOrPuk, newPinOrPuk, obtainMessage(EVENT_SET_COMPLETE, this));
            } else if (mSc.equals(SC_PUK)) {
              mUiccApplication.supplyPuk(
                  oldPinOrPuk, newPinOrPuk, obtainMessage(EVENT_SET_COMPLETE, this));
            } else if (mSc.equals(SC_PUK2)) {
              mUiccApplication.supplyPuk2(
                  oldPinOrPuk, newPinOrPuk, obtainMessage(EVENT_SET_COMPLETE, this));
            } else {
              throw new RuntimeException("Unsupported service code=" + mSc);
            }
          } else {
            throw new RuntimeException("No application mUiccApplicaiton is null");
          }
        } else {
          throw new RuntimeException("Ivalid register/action=" + mAction);
        }
      }
    } catch (RuntimeException exc) {
      mState = State.FAILED;
      mMessage = mContext.getText(com.android.internal.R.string.mmiError);
      mPhone.onMMIDone(this);
    }
  }
  @Override
  protected void processUnsolicited(Parcel p) {
    Object ret;
    int dataPosition = p.dataPosition(); // save off position within the Parcel
    int response = p.readInt();

    switch (response) {
      case RIL_UNSOL_RIL_CONNECTED: // Fix for NV/RUIM setting on CDMA SIM devices
        // skip getcdmascriptionsource as if qualcomm handles it in the ril binary
        ret = responseInts(p);
        setRadioPower(false, null);
        setPreferredNetworkType(mPreferredNetworkType, null);
        int cdmaSubscription =
            Settings.Global.getInt(
                mContext.getContentResolver(), Settings.Global.CDMA_SUBSCRIPTION_MODE, -1);
        if (cdmaSubscription != -1) {
          setCdmaSubscriptionSource(mCdmaSubscription, null);
        }
        setCellInfoListRate(Integer.MAX_VALUE, null);
        notifyRegistrantsRilConnectionChanged(((int[]) ret)[0]);
        break;
      case RIL_UNSOL_NITZ_TIME_RECEIVED:
        handleNitzTimeReceived(p);
        break;
        // SAMSUNG STATES
      case SamsungExynos4RIL.RIL_UNSOL_AM:
        ret = responseString(p);
        String amString = (String) ret;
        Rlog.d(RILJ_LOG_TAG, "Executing AM: " + amString);

        try {
          Runtime.getRuntime().exec("am " + amString);
        } catch (IOException e) {
          e.printStackTrace();
          Rlog.e(RILJ_LOG_TAG, "am " + amString + " could not be executed.");
        }
        break;
      case SamsungExynos4RIL.RIL_UNSOL_RESPONSE_HANDOVER:
        ret = responseVoid(p);
        break;
      case 1036:
        ret = responseVoid(p);
        break;
      case SamsungExynos4RIL.RIL_UNSOL_WB_AMR_STATE:
        ret = responseInts(p);
        setWbAmr(((int[]) ret)[0]);
        break;
      default:
        // Rewind the Parcel
        p.setDataPosition(dataPosition);

        // Forward responses that we are not overriding to the super class
        super.processUnsolicited(p);
        return;
    }
  }
  /** {@inheritDoc} */
  @Override
  protected void sendSms(SmsTracker tracker) {
    HashMap<String, Object> map = tracker.mData;

    byte pdu[] = (byte[]) map.get("pdu");

    if (tracker.mRetryCount > 0) {
      Rlog.d(
          TAG,
          "sendSms: "
              + " mRetryCount="
              + tracker.mRetryCount
              + " mMessageRef="
              + tracker.mMessageRef
              + " SS="
              + mPhone.getServiceState().getState());

      // per TS 23.040 Section 9.2.3.6:  If TP-MTI SMS-SUBMIT (0x01) type
      //   TP-RD (bit 2) is 1 for retry
      //   and TP-MR is set to previously failed sms TP-MR
      if (((0x01 & pdu[0]) == 0x01)) {
        pdu[0] |= 0x04; // TP-RD
        pdu[1] = (byte) tracker.mMessageRef; // TP-MR
      }
    }
    Rlog.d(
        TAG,
        "sendSms: "
            + " isIms()="
            + isIms()
            + " mRetryCount="
            + tracker.mRetryCount
            + " mImsRetry="
            + tracker.mImsRetry
            + " mMessageRef="
            + tracker.mMessageRef
            + " SS="
            + mPhone.getServiceState().getState());

    sendSmsByPstn(tracker);
  }
 public GsmSMSDispatcher(
     PhoneBase phone,
     SmsUsageMonitor usageMonitor,
     ImsSMSDispatcher imsSMSDispatcher,
     GsmInboundSmsHandler gsmInboundSmsHandler) {
   super(phone, usageMonitor, imsSMSDispatcher);
   mCi.setOnSmsStatus(this, EVENT_NEW_SMS_STATUS_REPORT, null);
   mCi.setOnSmsOnSim(this, EVENT_SMS_ON_ICC, null);
   mGsmInboundSmsHandler = gsmInboundSmsHandler;
   mUiccController = UiccController.getInstance();
   mUiccController.registerForIccChanged(this, EVENT_ICC_CHANGED, null);
   Rlog.d(TAG, "GsmSMSDispatcher created");
 }
 /** The contents of the /proc/cmdline file */
 private static String getProcCmdLine() {
   String cmdline = "";
   FileInputStream is = null;
   try {
     is = new FileInputStream("/proc/cmdline");
     byte[] buffer = new byte[2048];
     int count = is.read(buffer);
     if (count > 0) {
       cmdline = new String(buffer, 0, count);
     }
   } catch (IOException e) {
     Rlog.d(TAG, "No /proc/cmdline exception=" + e);
   } finally {
     if (is != null) {
       try {
         is.close();
       } catch (IOException e) {
       }
     }
   }
   Rlog.d(TAG, "/proc/cmdline=" + cmdline);
   return cmdline;
 }
 // TODO: Fix when we "properly" have TelephonyDevController/SubscriptionController ..
 public static int calculatePreferredNetworkType(Context context, int phoneSubId) {
   int networkType =
       android.provider.Settings.Global.getInt(
           context.getContentResolver(),
           android.provider.Settings.Global.PREFERRED_NETWORK_MODE + phoneSubId,
           RILConstants.PREFERRED_NETWORK_MODE);
   Rlog.d(
       LOG_TAG,
       "calculatePreferredNetworkType: phoneSubId = "
           + phoneSubId
           + " networkType = "
           + networkType);
   return networkType;
 }
  /* Returns User SMS Prompt property,  enabled or not */
  public static boolean isSMSPromptEnabled() {
    boolean prompt = false;
    int value = 0;
    try {
      value =
          Settings.Global.getInt(
              sContext.getContentResolver(), Settings.Global.MULTI_SIM_SMS_PROMPT);
    } catch (SettingNotFoundException snfe) {
      Rlog.e(LOG_TAG, "Settings Exception Reading Dual Sim SMS Prompt Values");
    }
    prompt = (value == 0) ? false : true;
    Rlog.d(LOG_TAG, "SMS Prompt option:" + prompt);

    return prompt;
  }
 protected void updatePhoneObject() {
   if (mPhoneBase
       .getContext()
       .getResources()
       .getBoolean(com.android.internal.R.bool.config_switch_phone_on_voice_reg_state_change)) {
     // If the phone is not registered on a network, no need to update.
     boolean isRegistered =
         mSS.getVoiceRegState() == ServiceState.STATE_IN_SERVICE
             || mSS.getVoiceRegState() == ServiceState.STATE_EMERGENCY_ONLY;
     if (!isRegistered) {
       Rlog.d(LOG_TAG, "updatePhoneObject: Ignore update");
       return;
     }
     mPhoneBase.updatePhoneObject(mSS.getRilVoiceRadioTechnology());
   }
 }
  /**
   * Create the beginning of a SUBMIT PDU. This is the part of the SUBMIT PDU that is common to the
   * two versions of {@link #getSubmitPdu}, one of which takes a byte array and the other of which
   * takes a <code>String</code>.
   *
   * @param scAddress Service Centre address. null == use default
   * @param destinationAddress the address of the destination for the message
   * @param mtiByte
   * @param ret <code>SubmitPdu</code> containing the encoded SC address, if applicable, and the
   *     encoded message
   */
  private static ByteArrayOutputStream getSubmitPduHead(
      String scAddress,
      String destinationAddress,
      byte mtiByte,
      boolean statusReportRequested,
      SubmitPdu ret) {
    ByteArrayOutputStream bo = new ByteArrayOutputStream(MAX_USER_DATA_BYTES + 40);

    // SMSC address with length octet, or 0
    if (scAddress == null) {
      ret.encodedScAddress = null;
    } else {
      ret.encodedScAddress = PhoneNumberUtils.networkPortionToCalledPartyBCDWithLength(scAddress);
    }

    // TP-Message-Type-Indicator (and friends)
    if (statusReportRequested) {
      // Set TP-Status-Report-Request bit.
      mtiByte |= 0x20;
      if (VDBG) Rlog.d(LOG_TAG, "SMS status report requested");
    }
    bo.write(mtiByte);

    // space for TP-Message-Reference
    bo.write(0);

    byte[] daBytes;

    daBytes = PhoneNumberUtils.networkPortionToCalledPartyBCD(destinationAddress);

    // destination address length in BCD digits, ignoring TON byte and pad
    // TODO Should be better.
    bo.write((daBytes.length - 1) * 2 - ((daBytes[daBytes.length - 1] & 0xf0) == 0xf0 ? 1 : 0));

    // destination address
    bo.write(daBytes, 0, daBytes.length);

    // TP-Protocol-Identifier
    bo.write(0);
    return bo;
  }
  /** {@inheritDoc} */
  @Override
  protected void sendText(
      String destAddr,
      String scAddr,
      String text,
      PendingIntent sentIntent,
      PendingIntent deliveryIntent,
      Uri messageUri,
      String callingPkg,
      int priority,
      boolean isExpectMore,
      int validityPeriod) {
    SmsMessage.SubmitPdu pdu =
        SmsMessage.getSubmitPdu(scAddr, destAddr, text, (deliveryIntent != null), validityPeriod);
    if (pdu != null) {
      HashMap map = getSmsTrackerMap(destAddr, scAddr, text, pdu);
      SmsTracker tracker =
          getSmsTracker(
              map,
              sentIntent,
              deliveryIntent,
              getFormat(),
              messageUri,
              isExpectMore,
              text /*fullMessageText*/,
              true /*isText*/,
              validityPeriod);

      String carrierPackage = getCarrierAppPackageName();
      if (carrierPackage != null) {
        Rlog.d(TAG, "Found carrier package.");
        TextSmsSender smsSender = new TextSmsSender(tracker);
        smsSender.sendSmsByCarrierApp(carrierPackage, new SmsSenderCallback(smsSender));
      } else {
        Rlog.v(TAG, "No carrier package.");
        sendRawPdu(tracker);
      }
    } else {
      Rlog.e(TAG, "GsmSMSDispatcher.sendText(): getSubmitPdu() returned null");
    }
  }
 private void smsLock() {
   // Do not send a new SMS until the response for the previous SMS has been received
   //   * for the error case where the response never comes back, time out after
   //     30 seconds and just try the next SEND_SMS
   synchronized (mSMSLock) {
     long timeoutTime = SystemClock.elapsedRealtime() + SEND_SMS_TIMEOUT_IN_MS;
     long waitTimeLeft = SEND_SMS_TIMEOUT_IN_MS;
     while (mIsSendingSMS && (waitTimeLeft > 0)) {
       Rlog.d(RILJ_LOG_TAG, "sendSMS() waiting for response of previous SEND_SMS");
       try {
         mSMSLock.wait(waitTimeLeft);
       } catch (InterruptedException ex) {
         // ignore the interrupt and rewait for the remainder
       }
       waitTimeLeft = timeoutTime - SystemClock.elapsedRealtime();
     }
     if (waitTimeLeft <= 0) {
       Rlog.e(RILJ_LOG_TAG, "sendSms() timed out waiting for response of previous CDMA_SEND_SMS");
     }
     mIsSendingSMS = true;
   }
 }
 public String toString() {
   if (callInfo != null) {
     Rlog.d(TAG, "mCallInfo size = " + dialogSize);
     StringBuilder sb = new StringBuilder();
     for (int i = 0; i < dialogSize; i++) {
       String[] callinfo = callInfo.get(i);
       sb.append("QtiViceInfo :");
       sb.append("DialogId - ");
       sb.append(callinfo[INDEX_DIALOG_ID]);
       sb.append("Number - ");
       sb.append(callinfo[INDEX_NUMBER]);
       sb.append("IsPullable - ");
       sb.append(callinfo[INDEX_ISPULLABLE]);
       sb.append("CallType - ");
       sb.append(callinfo[INDEX_CALLTYPE]);
       sb.append("Direction - ");
       sb.append(callinfo[INDEX_DIRECTION]);
     }
     return sb.toString();
   }
   return null;
 }
  /**
   * TS 27.005 3.1, &lt;pdu&gt; definition "In the case of SMS: 3GPP TS 24.011 [6] SC address
   * followed by 3GPP TS 23.040 [3] TPDU in hexadecimal format: ME/TA converts each octet of TP data
   * unit into two IRA character long hex number (e.g. octet with integer value 42 is presented to
   * TE as two characters 2A (IRA 50 and 65))" ...in the case of cell broadcast, something else...
   */
  private void parsePdu(byte[] pdu) {
    mPdu = pdu;
    // Rlog.d(LOG_TAG, "raw sms message:");
    // Rlog.d(LOG_TAG, s);

    PduParser p = new PduParser(pdu);

    mScAddress = p.getSCAddress();

    if (mScAddress != null) {
      if (VDBG) Rlog.d(LOG_TAG, "SMS SC address: " + mScAddress);
    }

    // TODO(mkf) support reply path, user data header indicator

    // TP-Message-Type-Indicator
    // 9.2.3
    int firstByte = p.getByte();

    mMti = firstByte & 0x3;
    switch (mMti) {
        // TP-Message-Type-Indicator
        // 9.2.3
      case 0:
      case 3: // GSM 03.40 9.2.3.1: MTI == 3 is Reserved.
        // This should be processed in the same way as MTI == 0 (Deliver)
        parseSmsDeliver(p, firstByte);
        break;
      case 1:
        parseSmsSubmit(p, firstByte);
        break;
      case 2:
        parseSmsStatusReport(p, firstByte);
        break;
      default:
        // TODO(mkf) the rest of these
        throw new RuntimeException("Unsupported message type");
    }
  }
  /** {@inheritDoc} */
  @Override
  protected void sendData(
      String destAddr,
      String scAddr,
      int destPort,
      int origPort,
      byte[] data,
      PendingIntent sentIntent,
      PendingIntent deliveryIntent) {
    SmsMessage.SubmitPdu pdu =
        SmsMessage.getSubmitPdu(
            scAddr, destAddr, destPort, origPort, data, (deliveryIntent != null));
    if (pdu != null) {
      HashMap map = getSmsTrackerMap(destAddr, scAddr, destPort, origPort, data, pdu);
      SmsTracker tracker =
          getSmsTracker(
              map,
              sentIntent,
              deliveryIntent,
              getFormat(),
              null /*messageUri*/,
              false /*isExpectMore*/,
              null /*fullMessageText*/,
              false /*isText*/);

      String carrierPackage = getCarrierAppPackageName();
      if (carrierPackage != null) {
        Rlog.d(TAG, "Found carrier package.");
        DataSmsSender smsSender = new DataSmsSender(tracker);
        smsSender.sendSmsByCarrierApp(carrierPackage, new SmsSenderCallback(smsSender));
      } else {
        Rlog.v(TAG, "No carrier package.");
        sendRawPdu(tracker);
      }
    } else {
      Rlog.e(TAG, "GsmSMSDispatcher.sendData(): getSubmitPdu() returned null");
    }
  }
  @Override
  protected RadioState getRadioStateFromInt(int stateInt) {
    if (!oldRilState) super.getRadioStateFromInt(stateInt);
    RadioState state;

    /* RIL_RadioState ril.h */
    switch (stateInt) {
      case 0:
        state = RadioState.RADIO_OFF;
        break;
      case 1:
      case 2:
        state = RadioState.RADIO_UNAVAILABLE;
        break;
      case 4:
        // When SIM is PIN-unlocked, RIL doesn't respond with RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED.
        // We notify the system here.
        Rlog.d(RILJ_LOG_TAG, "SIM is PIN-unlocked now");
        if (mIccStatusChangedRegistrants != null) {
          mIccStatusChangedRegistrants.notifyRegistrants();
        }
      case 3:
      case 5:
      case 6:
      case 7:
      case 8:
      case 9:
      case 10:
      case 13:
        state = RadioState.RADIO_ON;
        break;

      default:
        throw new RuntimeException("Unrecognized RIL_RadioState: " + stateInt);
    }
    return state;
  }
  public static Phone getPhone(int phoneId) {
    Phone phone;
    String dbgInfo = "";

    synchronized (sLockProxyPhones) {
      if (!sMadeDefaults) {
        throw new IllegalStateException("Default phones haven't been made yet!");
        // CAF_MSIM FIXME need to introduce default phone id ?
      } else if (phoneId == SubscriptionManager.DEFAULT_PHONE_INDEX) {
        if (DBG) dbgInfo = "phoneId == DEFAULT_PHONE_ID return sProxyPhone";
        phone = sProxyPhone;
      } else {
        if (DBG) dbgInfo = "phoneId != DEFAULT_PHONE_ID return sProxyPhones[phoneId]";
        phone =
            (((phoneId >= 0) && (phoneId < TelephonyManager.getDefault().getPhoneCount()))
                ? sProxyPhones[phoneId]
                : null);
      }
      if (DBG) {
        Rlog.d(LOG_TAG, "getPhone:- " + dbgInfo + " phoneId=" + phoneId + " phone=" + phone);
      }
      return phone;
    }
  }
    /**
     * Parse and return the SC address prepended to SMS messages coming via the TS 27.005 / AT
     * interface. Returns null on invalid address
     */
    String getSCAddress() {
      int len;
      String ret;

      // length of SC Address
      len = getByte();

      if (len == 0) {
        // no SC address
        ret = null;
      } else {
        // SC address
        try {
          ret = PhoneNumberUtils.calledPartyBCDToString(mPdu, mCur, len);
        } catch (RuntimeException tr) {
          Rlog.d(LOG_TAG, "invalid SC address: ", tr);
          ret = null;
        }
      }

      mCur += len;

      return ret;
    }
  /**
   * Return if the current radio is LTE on CDMA. This is a tri-state return value as for a period of
   * time the mode may be unknown.
   *
   * @return {@link PhoneConstants#LTE_ON_CDMA_UNKNOWN}, {@link PhoneConstants#LTE_ON_CDMA_FALSE} or
   *     {@link PhoneConstants#LTE_ON_CDMA_TRUE}
   * @hide
   */
  public static int getLteOnCdmaModeStatic() {
    int retVal;
    int curVal;
    String productType = "";

    curVal =
        SystemProperties.getInt(
            TelephonyProperties.PROPERTY_LTE_ON_CDMA_DEVICE, PhoneConstants.LTE_ON_CDMA_UNKNOWN);
    retVal = curVal;
    if (retVal == PhoneConstants.LTE_ON_CDMA_UNKNOWN) {
      Matcher matcher = sProductTypePattern.matcher(sKernelCmdLine);
      if (matcher.find()) {
        productType = matcher.group(1);
        if (sLteOnCdmaProductType.equals(productType)) {
          retVal = PhoneConstants.LTE_ON_CDMA_TRUE;
        } else {
          retVal = PhoneConstants.LTE_ON_CDMA_FALSE;
        }
      } else {
        retVal = PhoneConstants.LTE_ON_CDMA_FALSE;
      }
    }

    Rlog.d(
        TAG,
        "getLteOnCdmaMode="
            + retVal
            + " curVal="
            + curVal
            + " product_type='"
            + productType
            + "' lteOnCdmaProductType='"
            + sLteOnCdmaProductType
            + "'");
    return retVal;
  }
 protected void log(String msg) {
   Rlog.d(LOG_TAG, "[GsmCallTracker] " + msg);
 }
  protected synchronized void handlePollCalls(AsyncResult ar) {
    List polledCalls;

    if (ar.exception == null) {
      polledCalls = (List) ar.result;
    } else if (isCommandExceptionRadioNotAvailable(ar.exception)) {
      // just a dummy empty ArrayList to cause the loop
      // to hang up all the calls
      polledCalls = new ArrayList();
    } else {
      // Radio probably wasn't ready--try again in a bit
      // But don't keep polling if the channel is closed
      pollCallsAfterDelay();
      return;
    }

    Connection newRinging = null; // or waiting
    boolean hasNonHangupStateChanged = false; // Any change besides
    // a dropped connection
    boolean needsPollDelay = false;
    boolean unknownConnectionAppeared = false;

    for (int i = 0, curDC = 0, dcSize = polledCalls.size(); i < connections.length; i++) {
      GsmConnection conn = connections[i];
      DriverCall dc = null;

      // polledCall list is sparse
      if (curDC < dcSize) {
        dc = (DriverCall) polledCalls.get(curDC);

        if (dc.index == i + 1) {
          curDC++;
        } else {
          dc = null;
        }
      }

      if (DBG_POLL) log("poll: conn[i=" + i + "]=" + conn + ", dc=" + dc);

      if (conn == null && dc != null) {
        // Connection appeared in CLCC response that we don't know about
        if (pendingMO != null && pendingMO.compareTo(dc)) {

          if (DBG_POLL) log("poll: pendingMO=" + pendingMO);

          // It's our pending mobile originating call
          connections[i] = pendingMO;
          pendingMO.index = i;
          pendingMO.update(dc);
          pendingMO = null;

          // Someone has already asked to hangup this call
          if (hangupPendingMO) {
            hangupPendingMO = false;
            try {
              if (Phone.DEBUG_PHONE) log("poll: hangupPendingMO, hangup conn " + i);
              hangup(connections[i]);
            } catch (CallStateException ex) {
              Rlog.e(LOG_TAG, "unexpected error on hangup");
            }

            // Do not continue processing this poll
            // Wait for hangup and repoll
            return;
          }
        } else {
          connections[i] = new GsmConnection(phone.getContext(), dc, this, i);

          // it's a ringing call
          if (connections[i].getCall() == ringingCall) {
            newRinging = connections[i];
          } else {
            // Something strange happened: a call appeared
            // which is neither a ringing call or one we created.
            // Either we've crashed and re-attached to an existing
            // call, or something else (eg, SIM) initiated the call.

            Rlog.i(LOG_TAG, "Phantom call appeared " + dc);

            // If it's a connected call, set the connect time so that
            // it's non-zero.  It may not be accurate, but at least
            // it won't appear as a Missed Call.
            if (dc.state != DriverCall.State.ALERTING && dc.state != DriverCall.State.DIALING) {
              connections[i].onConnectedInOrOut();
              if (dc.state == DriverCall.State.HOLDING) {
                // We've transitioned into HOLDING
                connections[i].onStartedHolding();
              }
            }

            unknownConnectionAppeared = true;
          }
        }
        hasNonHangupStateChanged = true;
      } else if (conn != null && dc == null) {
        // Connection missing in CLCC response that we were
        // tracking.
        droppedDuringPoll.add(conn);
        // Dropped connections are removed from the CallTracker
        // list but kept in the GsmCall list
        connections[i] = null;
      } else if (conn != null && dc != null && !conn.compareTo(dc)) {
        // Connection in CLCC response does not match what
        // we were tracking. Assume dropped call and new call

        droppedDuringPoll.add(conn);
        connections[i] = new GsmConnection(phone.getContext(), dc, this, i);

        if (connections[i].getCall() == ringingCall) {
          newRinging = connections[i];
        } // else something strange happened
        hasNonHangupStateChanged = true;
      } else if (conn != null && dc != null) {
          /* implicit conn.compareTo(dc) */
        boolean changed;
        changed = conn.update(dc);
        hasNonHangupStateChanged = hasNonHangupStateChanged || changed;
      }

      if (REPEAT_POLLING) {
        if (dc != null) {
          // FIXME with RIL, we should not need this anymore
          if ((dc.state == DriverCall.State.DIALING
              /*&& cm.getOption(cm.OPTION_POLL_DIALING)*/ )
              || (dc.state == DriverCall.State.ALERTING
              /*&& cm.getOption(cm.OPTION_POLL_ALERTING)*/ )
              || (dc.state == DriverCall.State.INCOMING
              /*&& cm.getOption(cm.OPTION_POLL_INCOMING)*/ )
              || (dc.state == DriverCall.State.WAITING
              /*&& cm.getOption(cm.OPTION_POLL_WAITING)*/ )) {
            // Sometimes there's no unsolicited notification
            // for state transitions
            needsPollDelay = true;
          }
        }
      }
    }

    // This is the first poll after an ATD.
    // We expect the pending call to appear in the list
    // If it does not, we land here
    if (pendingMO != null) {
      Rlog.d(LOG_TAG, "Pending MO dropped before poll fg state:" + foregroundCall.getState());

      droppedDuringPoll.add(pendingMO);
      pendingMO = null;
      hangupPendingMO = false;
    }

    if (newRinging != null) {
      phone.notifyNewRingingConnection(newRinging);
    }

    // clear the "local hangup" and "missed/rejected call"
    // cases from the "dropped during poll" list
    // These cases need no "last call fail" reason
    for (int i = droppedDuringPoll.size() - 1; i >= 0; i--) {
      GsmConnection conn = droppedDuringPoll.get(i);

      if (conn.isIncoming() && conn.getConnectTime() == 0) {
        // Missed or rejected call
        Connection.DisconnectCause cause;
        if (conn.cause == Connection.DisconnectCause.LOCAL) {
          cause = Connection.DisconnectCause.INCOMING_REJECTED;
        } else {
          cause = Connection.DisconnectCause.INCOMING_MISSED;
        }

        if (Phone.DEBUG_PHONE) {
          log("missed/rejected call, conn.cause=" + conn.cause);
          log("setting cause to " + cause);
        }
        droppedDuringPoll.remove(i);
        conn.onDisconnect(cause);
      } else if (conn.cause == Connection.DisconnectCause.LOCAL) {
        // Local hangup
        droppedDuringPoll.remove(i);
        conn.onDisconnect(Connection.DisconnectCause.LOCAL);
      } else if (conn.cause == Connection.DisconnectCause.INVALID_NUMBER) {
        droppedDuringPoll.remove(i);
        conn.onDisconnect(Connection.DisconnectCause.INVALID_NUMBER);
      }
    }

    // Any non-local disconnects: determine cause
    if (droppedDuringPoll.size() > 0) {
      cm.getLastCallFailCause(obtainNoPollCompleteMessage(EVENT_GET_LAST_CALL_FAIL_CAUSE));
    }

    if (needsPollDelay) {
      pollCallsAfterDelay();
    }

    // Cases when we can no longer keep disconnected Connection's
    // with their previous calls
    // 1) the phone has started to ring
    // 2) A Call/Connection object has changed state...
    //    we may have switched or held or answered (but not hung up)
    if (newRinging != null || hasNonHangupStateChanged) {
      internalClearDisconnected();
    }

    updatePhoneState();

    if (unknownConnectionAppeared) {
      phone.notifyUnknownConnection();
    }

    if (hasNonHangupStateChanged || newRinging != null) {
      phone.notifyPreciseCallStateChanged();
    }

    // dumpState();
  }