예제 #1
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);
    }
  }
예제 #2
0
  /**
   * Create an SmsMessage from an SMS EF record.
   *
   * @param index Index of SMS record. This should be index in ArrayList returned by
   *     SmsManager.getAllMessagesFromSim + 1.
   * @param data Record data.
   * @return An SmsMessage representing the record.
   * @hide
   */
  public static SmsMessage createFromEfRecord(int index, byte[] data) {
    try {
      SmsMessage msg = new SmsMessage();

      msg.mIndexOnIcc = index;

      // First byte is status: RECEIVED_READ, RECEIVED_UNREAD, STORED_SENT,
      // or STORED_UNSENT
      // See TS 51.011 10.5.3
      if ((data[0] & 1) == 0) {
        Rlog.w(LOG_TAG, "SMS parsing failed: Trying to parse a free record");
        return null;
      } else {
        msg.mStatusOnIcc = data[0] & 0x07;
      }

      int size = data.length - 1;

      // Note: Data may include trailing FF's.  That's OK; message
      // should still parse correctly.
      byte[] pdu = new byte[size];
      System.arraycopy(data, 1, pdu, 0, size);
      msg.parsePdu(pdu);
      return msg;
    } catch (RuntimeException ex) {
      Rlog.e(LOG_TAG, "SMS PDU parsing failed: ", ex);
      return null;
    }
  }
예제 #3
0
  /**
   * @return a geographical description string for the specified number.
   * @see com.android.i18n.phonenumbers.PhoneNumberOfflineGeocoder
   */
  private static String getGeoDescription(Context context, String number) {
    if (VDBG) Rlog.v(TAG, "getGeoDescription('" + number + "')...");

    if (TextUtils.isEmpty(number)) {
      return null;
    }

    PhoneNumberUtil util = PhoneNumberUtil.getInstance();
    PhoneNumberOfflineGeocoder geocoder = PhoneNumberOfflineGeocoder.getInstance();

    Locale locale = context.getResources().getConfiguration().locale;
    String countryIso = getCurrentCountryIso(context, locale);
    PhoneNumber pn = null;
    try {
      if (VDBG) Rlog.v(TAG, "parsing '" + number + "' for countryIso '" + countryIso + "'...");
      pn = util.parse(number, countryIso);
      if (VDBG) Rlog.v(TAG, "- parsed number: " + pn);
    } catch (NumberParseException e) {
      Rlog.w(TAG, "getGeoDescription: NumberParseException for incoming number '" + number + "'");
    }

    if (pn != null) {
      String description = geocoder.getDescriptionForNumber(pn, locale);
      if (VDBG) Rlog.v(TAG, "- got description: '" + description + "'");
      return description;
    } else {
      return null;
    }
  }
예제 #4
0
  /**
   * Returns the column index to use to find the "person_id" field in the specified cursor, based on
   * the contact URI that was originally queried.
   *
   * <p>This is a helper function for the getCallerInfo() method that takes a Cursor. Looking up the
   * person_id is nontrivial (compared to all the other CallerInfo fields) since the column we need
   * to use depends on what query we originally ran.
   *
   * <p>Watch out: be sure to not do any database access in this method, since it's run from the UI
   * thread (see comments below for more info.)
   *
   * @return the columnIndex to use (with cursor.getLong()) to get the person_id, or -1 if we
   *     couldn't figure out what colum to use.
   *     <p>TODO: Add a unittest for this method. (This is a little tricky to test, since we'll need
   *     a live contacts database to test against, preloaded with at least some phone numbers and
   *     SIP addresses. And we'll probably have to hardcode the column indexes we expect, so the
   *     test might break whenever the contacts schema changes. But we can at least make sure we
   *     handle all the URI patterns we claim to, and that the mime types match what we expect...)
   */
  private static int getColumnIndexForPersonId(Uri contactRef, Cursor cursor) {
    // TODO: This is pretty ugly now, see bug 2269240 for
    // more details. The column to use depends upon the type of URL:
    // - content://com.android.contacts/data/phones ==> use the "contact_id" column
    // - content://com.android.contacts/phone_lookup ==> use the "_ID" column
    // - content://com.android.contacts/data ==> use the "contact_id" column
    // If it's none of the above, we leave columnIndex=-1 which means
    // that the person_id field will be left unset.
    //
    // The logic here *used* to be based on the mime type of contactRef
    // (for example Phone.CONTENT_ITEM_TYPE would tell us to use the
    // RawContacts.CONTACT_ID column).  But looking up the mime type requires
    // a call to context.getContentResolver().getType(contactRef), which
    // isn't safe to do from the UI thread since it can cause an ANR if
    // the contacts provider is slow or blocked (like during a sync.)
    //
    // So instead, figure out the column to use for person_id by just
    // looking at the URI itself.

    if (VDBG) Rlog.v(TAG, "- getColumnIndexForPersonId: contactRef URI = '" + contactRef + "'...");
    // Warning: Do not enable the following logging (due to ANR risk.)
    // if (VDBG) Rlog.v(TAG, "- MIME type: "
    //                 + context.getContentResolver().getType(contactRef));

    String url = contactRef.toString();
    String columnName = null;
    if (url.startsWith("content://com.android.contacts/data/phones")) {
      // Direct lookup in the Phone table.
      // MIME type: Phone.CONTENT_ITEM_TYPE (= "vnd.android.cursor.item/phone_v2")
      if (VDBG) Rlog.v(TAG, "'data/phones' URI; using RawContacts.CONTACT_ID");
      columnName = RawContacts.CONTACT_ID;
    } else if (url.startsWith("content://com.android.contacts/data")) {
      // Direct lookup in the Data table.
      // MIME type: Data.CONTENT_TYPE (= "vnd.android.cursor.dir/data")
      if (VDBG) Rlog.v(TAG, "'data' URI; using Data.CONTACT_ID");
      // (Note Data.CONTACT_ID and RawContacts.CONTACT_ID are equivalent.)
      columnName = Data.CONTACT_ID;
    } else if (url.startsWith("content://com.android.contacts/phone_lookup")) {
      // Lookup in the PhoneLookup table, which provides "fuzzy matching"
      // for phone numbers.
      // MIME type: PhoneLookup.CONTENT_TYPE (= "vnd.android.cursor.dir/phone_lookup")
      if (VDBG) Rlog.v(TAG, "'phone_lookup' URI; using PhoneLookup._ID");
      columnName = PhoneLookup._ID;
    } else {
      Rlog.w(TAG, "Unexpected prefix for contactRef '" + url + "'");
    }
    int columnIndex = (columnName != null) ? cursor.getColumnIndex(columnName) : -1;
    if (VDBG)
      Rlog.v(
          TAG,
          "==> Using column '"
              + columnName
              + "' (columnIndex = "
              + columnIndex
              + ") for person_id lookup...");
    return columnIndex;
  }
 /*package*/ void separate(GsmConnection conn) throws CallStateException {
   if (conn.owner != this) {
     throw new CallStateException(
         "GsmConnection " + conn + "does not belong to GsmCallTracker " + this);
   }
   try {
     cm.separateConnection(conn.getGSMIndex(), obtainCompleteMessage(EVENT_SEPARATE_RESULT));
   } catch (CallStateException ex) {
     // Ignore "connection not found"
     // Call may have hung up already
     Rlog.w(LOG_TAG, "GsmCallTracker WARN: separate() on absent connection " + conn);
   }
 }
예제 #6
0
 /** @return The ISO 3166-1 two letters country code of the country the user is in. */
 private static String getCurrentCountryIso(Context context, Locale locale) {
   String countryIso = null;
   CountryDetector detector = (CountryDetector) context.getSystemService(Context.COUNTRY_DETECTOR);
   if (detector != null) {
     Country country = detector.detectCountry();
     if (country != null) {
       countryIso = country.getCountryIso();
     } else {
       Rlog.e(TAG, "CountryDetector.detectCountry() returned null.");
     }
   }
   if (countryIso == null) {
     countryIso = locale.getCountry();
     Rlog.w(TAG, "No CountryDetector; falling back to countryIso based on locale: " + countryIso);
   }
   return countryIso;
 }
  /*package*/ void hangup(GsmConnection conn) throws CallStateException {
    if (conn.owner != this) {
      throw new CallStateException(
          "GsmConnection " + conn + "does not belong to GsmCallTracker " + this);
    }

    if (conn == pendingMO) {
      // We're hanging up an outgoing call that doesn't have it's
      // GSM index assigned yet

      if (Phone.DEBUG_PHONE) log("hangup: set hangupPendingMO to true");
      hangupPendingMO = true;
    } else {
      try {
        cm.hangupConnection(conn.getGSMIndex(), obtainCompleteMessage());
      } catch (CallStateException ex) {
        // Ignore "connection not found"
        // Call may have hung up already
        Rlog.w(LOG_TAG, "GsmCallTracker WARN: hangup() on absent connection " + conn);
      }
    }

    conn.onHangupLocal();
  }
예제 #8
0
 @Override
 public boolean isUssdRequest() {
   Rlog.w(LOG_TAG, "isUssdRequest is not implemented in CdmaMmiCode");
   return false;
 }
예제 #9
0
  /**
   * Get an SMS-SUBMIT PDU for a destination address and a message using the specified encoding.
   *
   * @param scAddress Service Centre address. Null means use default.
   * @param encoding Encoding defined by constants in
   *     com.android.internal.telephony.SmsConstants.ENCODING_*
   * @param languageTable
   * @param languageShiftTable
   * @return a <code>SubmitPdu</code> containing the encoded SC address, if applicable, and the
   *     encoded message. Returns null on encode error.
   * @hide
   */
  public static SubmitPdu getSubmitPdu(
      String scAddress,
      String destinationAddress,
      String message,
      boolean statusReportRequested,
      byte[] header,
      int encoding,
      int languageTable,
      int languageShiftTable) {

    // Perform null parameter checks.
    if (message == null || destinationAddress == null) {
      return null;
    }

    if (encoding == ENCODING_UNKNOWN) {
      // Find the best encoding to use
      TextEncodingDetails ted = calculateLength(message, false);
      encoding = ted.codeUnitSize;
      languageTable = ted.languageTable;
      languageShiftTable = ted.languageShiftTable;

      if (encoding == ENCODING_7BIT && (languageTable != 0 || languageShiftTable != 0)) {
        if (header != null) {
          SmsHeader smsHeader = SmsHeader.fromByteArray(header);
          if (smsHeader.languageTable != languageTable
              || smsHeader.languageShiftTable != languageShiftTable) {
            Rlog.w(
                LOG_TAG,
                "Updating language table in SMS header: "
                    + smsHeader.languageTable
                    + " -> "
                    + languageTable
                    + ", "
                    + smsHeader.languageShiftTable
                    + " -> "
                    + languageShiftTable);
            smsHeader.languageTable = languageTable;
            smsHeader.languageShiftTable = languageShiftTable;
            header = SmsHeader.toByteArray(smsHeader);
          }
        } else {
          SmsHeader smsHeader = new SmsHeader();
          smsHeader.languageTable = languageTable;
          smsHeader.languageShiftTable = languageShiftTable;
          header = SmsHeader.toByteArray(smsHeader);
        }
      }
    }

    SubmitPdu ret = new SubmitPdu();
    // MTI = SMS-SUBMIT, UDHI = header != null
    byte mtiByte = (byte) (0x01 | (header != null ? 0x40 : 0x00));
    ByteArrayOutputStream bo =
        getSubmitPduHead(scAddress, destinationAddress, mtiByte, statusReportRequested, ret);

    // User Data (and length)
    byte[] userData;
    try {
      if (encoding == ENCODING_7BIT) {
        userData =
            GsmAlphabet.stringToGsm7BitPackedWithHeader(
                message, header, languageTable, languageShiftTable);
      } else { // assume UCS-2
        try {
          userData = encodeUCS2(message, header);
        } catch (UnsupportedEncodingException uex) {
          Rlog.e(LOG_TAG, "Implausible UnsupportedEncodingException ", uex);
          return null;
        }
      }
    } catch (EncodeException ex) {
      // Encoding to the 7-bit alphabet failed. Let's see if we can
      // send it as a UCS-2 encoded message
      try {
        userData = encodeUCS2(message, header);
        encoding = ENCODING_16BIT;
      } catch (UnsupportedEncodingException uex) {
        Rlog.e(LOG_TAG, "Implausible UnsupportedEncodingException ", uex);
        return null;
      }
    }

    if (encoding == ENCODING_7BIT) {
      if ((0xff & userData[0]) > MAX_USER_DATA_SEPTETS) {
        // Message too long
        Rlog.e(LOG_TAG, "Message too long (" + (0xff & userData[0]) + " septets)");
        return null;
      }
      // TP-Data-Coding-Scheme
      // Default encoding, uncompressed
      // To test writing messages to the SIM card, change this value 0x00
      // to 0x12, which means "bits 1 and 0 contain message class, and the
      // class is 2". Note that this takes effect for the sender. In other
      // words, messages sent by the phone with this change will end up on
      // the receiver's SIM card. You can then send messages to yourself
      // (on a phone with this change) and they'll end up on the SIM card.
      bo.write(0x00);
    } else { // assume UCS-2
      if ((0xff & userData[0]) > MAX_USER_DATA_BYTES) {
        // Message too long
        Rlog.e(LOG_TAG, "Message too long (" + (0xff & userData[0]) + " bytes)");
        return null;
      }
      // TP-Data-Coding-Scheme
      // UCS-2 encoding, uncompressed
      bo.write(0x08);
    }

    // (no TP-Validity-Period)
    bo.write(userData, 0, userData.length);
    ret.encodedMessage = bo.toByteArray();
    return ret;
  }
예제 #10
0
  /**
   * Parses the User Data of an SMS.
   *
   * @param p The current PduParser.
   * @param hasUserDataHeader Indicates whether a header is present in the User Data.
   */
  private void parseUserData(PduParser p, boolean hasUserDataHeader) {
    boolean hasMessageClass = false;
    boolean userDataCompressed = false;

    int encodingType = ENCODING_UNKNOWN;

    // Look up the data encoding scheme
    if ((mDataCodingScheme & 0x80) == 0) {
      userDataCompressed = (0 != (mDataCodingScheme & 0x20));
      hasMessageClass = (0 != (mDataCodingScheme & 0x10));

      if (userDataCompressed) {
        Rlog.w(
            LOG_TAG,
            "4 - Unsupported SMS data coding scheme "
                + "(compression) "
                + (mDataCodingScheme & 0xff));
      } else {
        switch ((mDataCodingScheme >> 2) & 0x3) {
          case 0: // GSM 7 bit default alphabet
            encodingType = ENCODING_7BIT;
            break;

          case 2: // UCS 2 (16bit)
            encodingType = ENCODING_16BIT;
            break;

          case 1: // 8 bit data
            // Support decoding the user data payload as pack GSM 8-bit (a GSM alphabet string
            // that's stored in 8-bit unpacked format) characters.
            Resources r = Resources.getSystem();
            if (r.getBoolean(au.com.wallaceit.voicemail.R.bool.config_sms_decode_gsm_8bit_data)) {
              encodingType = ENCODING_8BIT;
              break;
            }

          case 3: // reserved
            Rlog.w(LOG_TAG, "1 - Unsupported SMS data coding scheme " + (mDataCodingScheme & 0xff));
            encodingType = ENCODING_8BIT;
            break;
        }
      }
    } else if ((mDataCodingScheme & 0xf0) == 0xf0) {
      hasMessageClass = true;
      userDataCompressed = false;

      if (0 == (mDataCodingScheme & 0x04)) {
        // GSM 7 bit default alphabet
        encodingType = ENCODING_7BIT;
      } else {
        // 8 bit data
        encodingType = ENCODING_8BIT;
      }
    } else if ((mDataCodingScheme & 0xF0) == 0xC0
        || (mDataCodingScheme & 0xF0) == 0xD0
        || (mDataCodingScheme & 0xF0) == 0xE0) {
      // 3GPP TS 23.038 V7.0.0 (2006-03) section 4

      // 0xC0 == 7 bit, don't store
      // 0xD0 == 7 bit, store
      // 0xE0 == UCS-2, store

      if ((mDataCodingScheme & 0xF0) == 0xE0) {
        encodingType = ENCODING_16BIT;
      } else {
        encodingType = ENCODING_7BIT;
      }

      userDataCompressed = false;
      boolean active = ((mDataCodingScheme & 0x08) == 0x08);
      // bit 0x04 reserved

      // VM - If TP-UDH is present, these values will be overwritten
      if ((mDataCodingScheme & 0x03) == 0x00) {
        mIsMwi = true; /* Indicates vmail */
        mMwiSense = active; /* Indicates vmail notification set/clear */
        mMwiDontStore = ((mDataCodingScheme & 0xF0) == 0xC0);

        /* Set voice mail count based on notification bit */
        if (active == true) {
          mVoiceMailCount = -1; // unknown number of messages waiting
        } else {
          mVoiceMailCount = 0; // no unread messages
        }

        Rlog.w(
            LOG_TAG,
            "MWI in DCS for Vmail. DCS = "
                + (mDataCodingScheme & 0xff)
                + " Dont store = "
                + mMwiDontStore
                + " vmail count = "
                + mVoiceMailCount);

      } else {
        mIsMwi = false;
        Rlog.w(LOG_TAG, "MWI in DCS for fax/email/other: " + (mDataCodingScheme & 0xff));
      }
    } else if ((mDataCodingScheme & 0xC0) == 0x80) {
      // 3GPP TS 23.038 V7.0.0 (2006-03) section 4
      // 0x80..0xBF == Reserved coding groups
      if (mDataCodingScheme == 0x84) {
        // This value used for KSC5601 by carriers in Korea.
        encodingType = ENCODING_KSC5601;
      } else {
        Rlog.w(LOG_TAG, "5 - Unsupported SMS data coding scheme " + (mDataCodingScheme & 0xff));
      }
    } else {
      Rlog.w(LOG_TAG, "3 - Unsupported SMS data coding scheme " + (mDataCodingScheme & 0xff));
    }

    // set both the user data and the user data header.
    int count = p.constructUserData(hasUserDataHeader, encodingType == ENCODING_7BIT);
    this.mUserData = p.getUserData();
    this.mUserDataHeader = p.getUserDataHeader();

    /*
     * Look for voice mail indication in TP_UDH TS23.040 9.2.3.24
     * ieid = 1 (0x1) (SPECIAL_SMS_MSG_IND)
     * ieidl =2 octets
     * ieda msg_ind_type = 0x00 (voice mail; discard sms )or
     *                   = 0x80 (voice mail; store sms)
     * msg_count = 0x00 ..0xFF
     */
    if (hasUserDataHeader && (mUserDataHeader.specialSmsMsgList.size() != 0)) {
      for (SmsHeader.SpecialSmsMsg msg : mUserDataHeader.specialSmsMsgList) {
        int msgInd = msg.msgIndType & 0xff;
        /*
         * TS 23.040 V6.8.1 Sec 9.2.3.24.2
         * bits 1 0 : basic message indication type
         * bits 4 3 2 : extended message indication type
         * bits 6 5 : Profile id bit 7 storage type
         */
        if ((msgInd == 0) || (msgInd == 0x80)) {
          mIsMwi = true;
          if (msgInd == 0x80) {
            /* Store message because TP_UDH indicates so*/
            mMwiDontStore = false;
          } else if (mMwiDontStore == false) {
            /* Storage bit is not set by TP_UDH
             * Check for conflict
             * between message storage bit in TP_UDH
             * & DCS. The message shall be stored if either of
             * the one indicates so.
             * TS 23.040 V6.8.1 Sec 9.2.3.24.2
             */
            if (!((((mDataCodingScheme & 0xF0) == 0xD0) || ((mDataCodingScheme & 0xF0) == 0xE0))
                && ((mDataCodingScheme & 0x03) == 0x00))) {
              /* Even DCS did not have voice mail with Storage bit
               * 3GPP TS 23.038 V7.0.0 section 4
               * So clear this flag*/
              mMwiDontStore = true;
            }
          }

          mVoiceMailCount = msg.msgCount & 0xff;

          /*
           * In the event of a conflict between message count setting
           * and DCS then the Message Count in the TP-UDH shall
           * override the indication in the TP-DCS. Set voice mail
           * notification based on count in TP-UDH
           */
          if (mVoiceMailCount > 0) mMwiSense = true;
          else mMwiSense = false;

          Rlog.w(
              LOG_TAG,
              "MWI in TP-UDH for Vmail. Msg Ind = "
                  + msgInd
                  + " Dont store = "
                  + mMwiDontStore
                  + " Vmail count = "
                  + mVoiceMailCount);

          /*
           * There can be only one IE for each type of message
           * indication in TP_UDH. In the event they are duplicated
           * last occurence will be used. Hence the for loop
           */
        } else {
          Rlog.w(
              LOG_TAG,
              "TP_UDH fax/email/" + "extended msg/multisubscriber profile. Msg Ind = " + msgInd);
        }
      } // end of for
    } // end of if UDH

    switch (encodingType) {
      case ENCODING_UNKNOWN:
        mMessageBody = null;
        break;

      case ENCODING_8BIT:
        // Support decoding the user data payload as pack GSM 8-bit (a GSM alphabet string
        // that's stored in 8-bit unpacked format) characters.
        Resources r = Resources.getSystem();
        if (r.getBoolean(au.com.wallaceit.voicemail.R.bool.config_sms_decode_gsm_8bit_data)) {
          mMessageBody = p.getUserDataGSM8bit(count);
        } else {
          mMessageBody = null;
        }
        break;

      case ENCODING_7BIT:
        mMessageBody =
            p.getUserDataGSM7Bit(
                count,
                hasUserDataHeader ? mUserDataHeader.languageTable : 0,
                hasUserDataHeader ? mUserDataHeader.languageShiftTable : 0);
        break;

      case ENCODING_16BIT:
        mMessageBody = p.getUserDataUCS2(count);
        break;

      case ENCODING_KSC5601:
        mMessageBody = p.getUserDataKSC5601(count);
        break;
    }

    if (VDBG) Rlog.v(LOG_TAG, "SMS message body (raw): '" + mMessageBody + "'");

    if (mMessageBody != null) {
      parseMessageBody();
    }

    if (!hasMessageClass) {
      messageClass = MessageClass.UNKNOWN;
    } else {
      switch (mDataCodingScheme & 0x3) {
        case 0:
          messageClass = MessageClass.CLASS_0;
          break;
        case 1:
          messageClass = MessageClass.CLASS_1;
          break;
        case 2:
          messageClass = MessageClass.CLASS_2;
          break;
        case 3:
          messageClass = MessageClass.CLASS_3;
          break;
      }
    }
  }
예제 #11
0
  /**
   * getCallerInfo given a Cursor.
   *
   * @param context the context used to retrieve string constants
   * @param contactRef the URI to attach to this CallerInfo object
   * @param cursor the first object in the cursor is used to build the CallerInfo object.
   * @return the CallerInfo which contains the caller id for the given number. The returned
   *     CallerInfo is null if no number is supplied.
   */
  public static CallerInfo getCallerInfo(Context context, Uri contactRef, Cursor cursor) {
    CallerInfo info = new CallerInfo();
    info.photoResource = 0;
    info.phoneLabel = null;
    info.numberType = 0;
    info.numberLabel = null;
    info.cachedPhoto = null;
    info.isCachedPhotoCurrent = false;
    info.contactExists = false;

    if (VDBG) Rlog.v(TAG, "getCallerInfo() based on cursor...");

    if (cursor != null) {
      if (cursor.moveToFirst()) {
        // TODO: photo_id is always available but not taken
        // care of here. Maybe we should store it in the
        // CallerInfo object as well.

        int columnIndex;

        // Look for the name
        columnIndex = cursor.getColumnIndex(PhoneLookup.DISPLAY_NAME);
        if (columnIndex != -1) {
          info.name = cursor.getString(columnIndex);
        }

        // Look for the number
        columnIndex = cursor.getColumnIndex(PhoneLookup.NUMBER);
        if (columnIndex != -1) {
          info.phoneNumber = cursor.getString(columnIndex);
        }

        // Look for the normalized number
        columnIndex = cursor.getColumnIndex(PhoneLookup.NORMALIZED_NUMBER);
        if (columnIndex != -1) {
          info.normalizedNumber = cursor.getString(columnIndex);
        }

        // Look for the label/type combo
        columnIndex = cursor.getColumnIndex(PhoneLookup.LABEL);
        if (columnIndex != -1) {
          int typeColumnIndex = cursor.getColumnIndex(PhoneLookup.TYPE);
          if (typeColumnIndex != -1) {
            info.numberType = cursor.getInt(typeColumnIndex);
            info.numberLabel = cursor.getString(columnIndex);
            info.phoneLabel =
                Phone.getDisplayLabel(context, info.numberType, info.numberLabel).toString();
          }
        }

        // Look for the person_id.
        columnIndex = getColumnIndexForPersonId(contactRef, cursor);
        if (columnIndex != -1) {
          final long contactId = cursor.getLong(columnIndex);
          if (contactId != 0 && !Contacts.isEnterpriseContactId(contactId)) {
            info.contactIdOrZero = contactId;
            if (VDBG) {
              Rlog.v(TAG, "==> got info.contactIdOrZero: " + info.contactIdOrZero);
            }
          }
        } else {
          // No valid columnIndex, so we can't look up person_id.
          Rlog.w(TAG, "Couldn't find contact_id column for " + contactRef);
          // Watch out: this means that anything that depends on
          // person_id will be broken (like contact photo lookups in
          // the in-call UI, for example.)
        }

        // Contact lookupKey
        columnIndex = cursor.getColumnIndex(PhoneLookup.LOOKUP_KEY);
        if (columnIndex != -1) {
          info.lookupKey = cursor.getString(columnIndex);
        }

        // Display photo URI.
        columnIndex = cursor.getColumnIndex(PhoneLookup.PHOTO_URI);
        if ((columnIndex != -1) && (cursor.getString(columnIndex) != null)) {
          info.contactDisplayPhotoUri = Uri.parse(cursor.getString(columnIndex));
        } else {
          info.contactDisplayPhotoUri = null;
        }

        // look for the custom ringtone, create from the string stored
        // in the database.
        columnIndex = cursor.getColumnIndex(PhoneLookup.CUSTOM_RINGTONE);
        if ((columnIndex != -1) && (cursor.getString(columnIndex) != null)) {
          info.contactRingtoneUri = Uri.parse(cursor.getString(columnIndex));
        } else {
          info.contactRingtoneUri = null;
        }

        // look for the send to voicemail flag, set it to true only
        // under certain circumstances.
        columnIndex = cursor.getColumnIndex(PhoneLookup.SEND_TO_VOICEMAIL);
        info.shouldSendToVoicemail = (columnIndex != -1) && ((cursor.getInt(columnIndex)) == 1);
        info.contactExists = true;
      }
      cursor.close();
      cursor = null;
    }

    info.needUpdate = false;
    info.name = normalize(info.name);
    info.contactRefUri = contactRef;

    return info;
  }
 /** log */
 private static void log(String s) {
   Rlog.w(LOG_TAG, s);
 }
  @Override
  protected RILRequest processSolicited(Parcel p) {
    int serial, error;
    boolean found = false;

    serial = p.readInt();
    error = p.readInt();

    RILRequest rr;

    rr = findAndRemoveRequestFromList(serial);

    if (rr == null) {
      Rlog.w(RILJ_LOG_TAG, "Unexpected solicited response! sn: " + serial + " error: " + error);
      return null;
    }

    Object ret = null;

    if (error == 0 || p.dataAvail() > 0) {
      // either command succeeds or command fails but with data payload
      try {
        switch (rr.mRequest) {
            /*
            cat libs/telephony/ril_commands.h \
            | egrep "^ *{RIL_" \
            | sed -re 's/\{([^,]+),[^,]+,([^}]+).+/case \1: ret = \2(p); break;/'
                        */
          case RIL_REQUEST_GET_SIM_STATUS:
            ret = responseIccCardStatus(p);
            break;
          case RIL_REQUEST_ENTER_SIM_PIN:
            ret = responseInts(p);
            break;
          case RIL_REQUEST_ENTER_SIM_PUK:
            ret = responseInts(p);
            break;
          case RIL_REQUEST_ENTER_SIM_PIN2:
            ret = responseInts(p);
            break;
          case RIL_REQUEST_ENTER_SIM_PUK2:
            ret = responseInts(p);
            break;
          case RIL_REQUEST_CHANGE_SIM_PIN:
            ret = responseInts(p);
            break;
          case RIL_REQUEST_CHANGE_SIM_PIN2:
            ret = responseInts(p);
            break;
          case RIL_REQUEST_ENTER_NETWORK_DEPERSONALIZATION:
            ret = responseInts(p);
            break;
          case RIL_REQUEST_GET_CURRENT_CALLS:
            ret = responseCallList(p);
            break;
          case RIL_REQUEST_DIAL:
            ret = responseVoid(p);
            break;
          case RIL_REQUEST_GET_IMSI:
            ret = responseString(p);
            break;
          case RIL_REQUEST_HANGUP:
            ret = responseVoid(p);
            break;
          case RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND:
            ret = responseVoid(p);
            break;
          case RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND:
            {
              if (mTestingEmergencyCall.getAndSet(false)) {
                if (mEmergencyCallbackModeRegistrant != null) {
                  riljLog("testing emergency call, notify ECM Registrants");
                  mEmergencyCallbackModeRegistrant.notifyRegistrant();
                }
              }
              ret = responseVoid(p);
              break;
            }
          case RIL_REQUEST_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE:
            ret = responseVoid(p);
            break;
          case RIL_REQUEST_CONFERENCE:
            ret = responseVoid(p);
            break;
          case RIL_REQUEST_UDUB:
            ret = responseVoid(p);
            break;
          case RIL_REQUEST_LAST_CALL_FAIL_CAUSE:
            ret = responseInts(p);
            break;
          case RIL_REQUEST_SIGNAL_STRENGTH:
            ret = responseSignalStrength(p);
            break;
            // modification start
            // prevent exceptions from happenimg because the null value is null or a hexadecimel. so
            // convert if it is not null
          case RIL_REQUEST_VOICE_REGISTRATION_STATE:
            ret = responseVoiceDataRegistrationState(p);
            break;
          case RIL_REQUEST_DATA_REGISTRATION_STATE:
            ret = responseVoiceDataRegistrationState(p);
            break;
            // this fixes bogus values the modem creates
            // sometimes the  ril may print out
            // (always on sprint)
            // sprint: (empty,empty,31000)
            // this problemaic on sprint, lte won't start, response is slow
            // speeds up response time on eherpderpd/lte networks
          case RIL_REQUEST_OPERATOR:
            ret = operatorCheck(p);
            break;
            // end modification
          case RIL_REQUEST_RADIO_POWER:
            ret = responseVoid(p);
            break;
          case RIL_REQUEST_DTMF:
            ret = responseVoid(p);
            break;
          case RIL_REQUEST_SEND_SMS:
            ret = responseSMS(p);
            break;
          case RIL_REQUEST_SEND_SMS_EXPECT_MORE:
            ret = responseSMS(p);
            break;
          case RIL_REQUEST_SETUP_DATA_CALL:
            ret = responseSetupDataCall(p);
            break;
          case RIL_REQUEST_SIM_IO:
            ret = responseICC_IO(p);
            break;
          case RIL_REQUEST_SEND_USSD:
            ret = responseVoid(p);
            break;
          case RIL_REQUEST_CANCEL_USSD:
            ret = responseVoid(p);
            break;
          case RIL_REQUEST_GET_CLIR:
            ret = responseInts(p);
            break;
          case RIL_REQUEST_SET_CLIR:
            ret = responseVoid(p);
            break;
          case RIL_REQUEST_QUERY_CALL_FORWARD_STATUS:
            ret = responseCallForward(p);
            break;
          case RIL_REQUEST_SET_CALL_FORWARD:
            ret = responseVoid(p);
            break;
          case RIL_REQUEST_QUERY_CALL_WAITING:
            ret = responseInts(p);
            break;
          case RIL_REQUEST_SET_CALL_WAITING:
            ret = responseVoid(p);
            break;
          case RIL_REQUEST_SMS_ACKNOWLEDGE:
            ret = responseVoid(p);
            break;
          case RIL_REQUEST_GET_IMEI:
            ret = responseString(p);
            break;
          case RIL_REQUEST_GET_IMEISV:
            ret = responseString(p);
            break;
          case RIL_REQUEST_ANSWER:
            ret = responseVoid(p);
            break;
          case RIL_REQUEST_DEACTIVATE_DATA_CALL:
            ret = responseVoid(p);
            break;
          case RIL_REQUEST_QUERY_FACILITY_LOCK:
            ret = responseInts(p);
            break;
          case RIL_REQUEST_SET_FACILITY_LOCK:
            ret = responseInts(p);
            break;
          case RIL_REQUEST_CHANGE_BARRING_PASSWORD:
            ret = responseVoid(p);
            break;
          case RIL_REQUEST_QUERY_NETWORK_SELECTION_MODE:
            ret = responseInts(p);
            break;
          case RIL_REQUEST_SET_NETWORK_SELECTION_AUTOMATIC:
            ret = responseVoid(p);
            break;
          case RIL_REQUEST_SET_NETWORK_SELECTION_MANUAL:
            ret = responseVoid(p);
            break;
          case RIL_REQUEST_QUERY_AVAILABLE_NETWORKS:
            ret = responseOperatorInfos(p);
            break;
          case RIL_REQUEST_DTMF_START:
            ret = responseVoid(p);
            break;
          case RIL_REQUEST_DTMF_STOP:
            ret = responseVoid(p);
            break;
          case RIL_REQUEST_BASEBAND_VERSION:
            ret = responseString(p);
            break;
          case RIL_REQUEST_SEPARATE_CONNECTION:
            ret = responseVoid(p);
            break;
          case RIL_REQUEST_SET_MUTE:
            ret = responseVoid(p);
            break;
          case RIL_REQUEST_GET_MUTE:
            ret = responseInts(p);
            break;
          case RIL_REQUEST_QUERY_CLIP:
            ret = responseInts(p);
            break;
          case RIL_REQUEST_LAST_DATA_CALL_FAIL_CAUSE:
            ret = responseInts(p);
            break;
          case RIL_REQUEST_DATA_CALL_LIST:
            ret = responseDataCallList(p);
            break;
          case RIL_REQUEST_RESET_RADIO:
            ret = responseVoid(p);
            break;
          case RIL_REQUEST_OEM_HOOK_RAW:
            ret = responseRaw(p);
            break;
          case RIL_REQUEST_OEM_HOOK_STRINGS:
            ret = responseStrings(p);
            break;
          case RIL_REQUEST_SCREEN_STATE:
            ret = responseVoid(p);
            break;
          case RIL_REQUEST_SET_SUPP_SVC_NOTIFICATION:
            ret = responseVoid(p);
            break;
          case RIL_REQUEST_WRITE_SMS_TO_SIM:
            ret = responseInts(p);
            break;
          case RIL_REQUEST_DELETE_SMS_ON_SIM:
            ret = responseVoid(p);
            break;
          case RIL_REQUEST_SET_BAND_MODE:
            ret = responseVoid(p);
            break;
          case RIL_REQUEST_QUERY_AVAILABLE_BAND_MODE:
            ret = responseInts(p);
            break;
          case RIL_REQUEST_STK_GET_PROFILE:
            ret = responseString(p);
            break;
          case RIL_REQUEST_STK_SET_PROFILE:
            ret = responseVoid(p);
            break;
          case RIL_REQUEST_STK_SEND_ENVELOPE_COMMAND:
            ret = responseString(p);
            break;
          case RIL_REQUEST_STK_SEND_TERMINAL_RESPONSE:
            ret = responseVoid(p);
            break;
          case RIL_REQUEST_STK_HANDLE_CALL_SETUP_REQUESTED_FROM_SIM:
            ret = responseInts(p);
            break;
          case RIL_REQUEST_EXPLICIT_CALL_TRANSFER:
            ret = responseVoid(p);
            break;
          case RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE:
            ret = responseVoid(p);
            break;
          case RIL_REQUEST_GET_PREFERRED_NETWORK_TYPE:
            ret = responseGetPreferredNetworkType(p);
            break;
          case RIL_REQUEST_GET_NEIGHBORING_CELL_IDS:
            ret = responseCellList(p);
            break;
          case RIL_REQUEST_SET_LOCATION_UPDATES:
            ret = responseVoid(p);
            break;
          case RIL_REQUEST_CDMA_SET_SUBSCRIPTION_SOURCE:
            ret = responseVoid(p);
            break;
          case RIL_REQUEST_CDMA_SET_ROAMING_PREFERENCE:
            ret = responseVoid(p);
            break;
          case RIL_REQUEST_CDMA_QUERY_ROAMING_PREFERENCE:
            ret = responseInts(p);
            break;
          case RIL_REQUEST_SET_TTY_MODE:
            ret = responseVoid(p);
            break;
          case RIL_REQUEST_QUERY_TTY_MODE:
            ret = responseInts(p);
            break;
          case RIL_REQUEST_CDMA_SET_PREFERRED_VOICE_PRIVACY_MODE:
            ret = responseVoid(p);
            break;
          case RIL_REQUEST_CDMA_QUERY_PREFERRED_VOICE_PRIVACY_MODE:
            ret = responseInts(p);
            break;
          case RIL_REQUEST_CDMA_FLASH:
            ret = responseVoid(p);
            break;
          case RIL_REQUEST_CDMA_BURST_DTMF:
            ret = responseVoid(p);
            break;
          case RIL_REQUEST_CDMA_SEND_SMS:
            ret = responseSMS(p);
            break;
          case RIL_REQUEST_CDMA_SMS_ACKNOWLEDGE:
            ret = responseVoid(p);
            break;
          case RIL_REQUEST_GSM_GET_BROADCAST_CONFIG:
            ret = responseGmsBroadcastConfig(p);
            break;
          case RIL_REQUEST_GSM_SET_BROADCAST_CONFIG:
            ret = responseVoid(p);
            break;
          case RIL_REQUEST_GSM_BROADCAST_ACTIVATION:
            ret = responseVoid(p);
            break;
          case RIL_REQUEST_CDMA_GET_BROADCAST_CONFIG:
            ret = responseCdmaBroadcastConfig(p);
            break;
          case RIL_REQUEST_CDMA_SET_BROADCAST_CONFIG:
            ret = responseVoid(p);
            break;
          case RIL_REQUEST_CDMA_BROADCAST_ACTIVATION:
            ret = responseVoid(p);
            break;
          case RIL_REQUEST_CDMA_VALIDATE_AND_WRITE_AKEY:
            ret = responseVoid(p);
            break;
          case RIL_REQUEST_CDMA_SUBSCRIPTION:
            ret = responseStrings(p);
            break;
          case RIL_REQUEST_CDMA_WRITE_SMS_TO_RUIM:
            ret = responseInts(p);
            break;
          case RIL_REQUEST_CDMA_DELETE_SMS_ON_RUIM:
            ret = responseVoid(p);
            break;
          case RIL_REQUEST_DEVICE_IDENTITY:
            ret = responseStrings(p);
            break;
          case RIL_REQUEST_GET_SMSC_ADDRESS:
            ret = responseString(p);
            break;
          case RIL_REQUEST_SET_SMSC_ADDRESS:
            ret = responseVoid(p);
            break;
          case RIL_REQUEST_EXIT_EMERGENCY_CALLBACK_MODE:
            ret = responseVoid(p);
            break;
          case RIL_REQUEST_REPORT_SMS_MEMORY_STATUS:
            ret = responseVoid(p);
            break;
          case RIL_REQUEST_REPORT_STK_SERVICE_IS_RUNNING:
            ret = responseVoid(p);
            break;
          case RIL_REQUEST_CDMA_GET_SUBSCRIPTION_SOURCE:
            ret = responseInts(p);
            break;
          case RIL_REQUEST_ISIM_AUTHENTICATION:
            ret = responseString(p);
            break;
          case RIL_REQUEST_ACKNOWLEDGE_INCOMING_GSM_SMS_WITH_PDU:
            ret = responseVoid(p);
            break;
          case RIL_REQUEST_STK_SEND_ENVELOPE_WITH_STATUS:
            ret = responseICC_IO(p);
            break;
          case RIL_REQUEST_VOICE_RADIO_TECH:
            ret = responseInts(p);
            break;
          case RIL_REQUEST_GET_CELL_INFO_LIST:
            ret = responseCellInfoList(p);
            break;
          case RIL_REQUEST_SET_UNSOL_CELL_INFO_LIST_RATE:
            ret = responseVoid(p);
            break;
          case RIL_REQUEST_SET_INITIAL_ATTACH_APN:
            ret = responseVoid(p);
            break;
          case RIL_REQUEST_IMS_REGISTRATION_STATE:
            ret = responseInts(p);
            break;
          case RIL_REQUEST_IMS_SEND_SMS:
            ret = responseSMS(p);
            break;
          default:
            throw new RuntimeException("Unrecognized solicited response: " + rr.mRequest);
            // break;
        }
      } catch (Throwable tr) {
        // Exceptions here usually mean invalid RIL responses

        Rlog.w(
            RILJ_LOG_TAG,
            rr.serialString()
                + "< "
                + requestToString(rr.mRequest)
                + " exception, possible invalid RIL response",
            tr);

        if (rr.mResult != null) {
          AsyncResult.forMessage(rr.mResult, null, tr);
          rr.mResult.sendToTarget();
        }
        return rr;
      }
    }

    // Here and below fake RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED, see b/7255789.
    // This is needed otherwise we don't automatically transition to the main lock
    // screen when the pin or puk is entered incorrectly.
    switch (rr.mRequest) {
      case RIL_REQUEST_ENTER_SIM_PUK:
      case RIL_REQUEST_ENTER_SIM_PUK2:
        if (mIccStatusChangedRegistrants != null) {
          if (RILJ_LOGD) {
            riljLog(
                "ON enter sim puk fakeSimStatusChanged: reg count="
                    + mIccStatusChangedRegistrants.size());
          }
          mIccStatusChangedRegistrants.notifyRegistrants();
        }
        break;
    }

    if (error != 0) {
      switch (rr.mRequest) {
        case RIL_REQUEST_ENTER_SIM_PIN:
        case RIL_REQUEST_ENTER_SIM_PIN2:
        case RIL_REQUEST_CHANGE_SIM_PIN:
        case RIL_REQUEST_CHANGE_SIM_PIN2:
        case RIL_REQUEST_SET_FACILITY_LOCK:
          if (mIccStatusChangedRegistrants != null) {
            if (RILJ_LOGD) {
              riljLog(
                  "ON some errors fakeSimStatusChanged: reg count="
                      + mIccStatusChangedRegistrants.size());
            }
            mIccStatusChangedRegistrants.notifyRegistrants();
          }
          break;
      }

      rr.onError(error, ret);
    } else {

      if (RILJ_LOGD)
        riljLog(
            rr.serialString()
                + "< "
                + requestToString(rr.mRequest)
                + " "
                + retToString(rr.mRequest, ret));

      if (rr.mResult != null) {
        AsyncResult.forMessage(rr.mResult, ret, null);
        rr.mResult.sendToTarget();
      }
    }
    return rr;
  }