我已经开发了一个用于发送SMS消息的应用程序,它使用broadcastReceivers成功地发送和(未)发送了消息.
在邮件的接收方中,我想获取时间,以便将邮件发送给目标接收方.由于发送和接收设备有时都可能会关闭,因此我认为将接收广播的时间视为实际的发送时间是不正确的.
有没有办法在我的广播接收器中获得正确的传送时间?
谢谢.
解决方法:
这是一个可行的解决方案.
通过研究com.android.internal.telephony.gsm.SmsMessage类(AndroID的内部类,用于解析GSM / 3GPP网络上的SMS PDU)的源代码,我发现SMS-STATUS-REPORTS(=“交付报告”)包含第二个时间戳值,即“放电”时间”.不幸的是,公共SmsMessage类未公开此值,它是您想要的传送时间(由传送网络基础结构感知).
使用下面的类,您可以通过调用getdischargeTime()获得此值.
getServiceCenterTimeStamp()方法返回的值与您从SmsMessage#getTimestampMillis()获得的值相同,即SMS服务中心接收原始消息的时间.
导入androID.telephony.PhoneNumberUtils;
导入androID.text.format.Time;
/** * A helper class to parse (from pdu byte[]) and represent a GSM SMS-STATUS-REPORT message (= delivery report). * * Only works for GSM/3GPP networks (not CDMA/3GPP2). * * Based on the source code of the following AndroID classes: * - com.androID.internal.telephony.gsm.SmsMessage (almost everything) * - com.androID.internal.telephony.uicc.IccUtils (1 method) * All licensed under the Apache license, Version 2.0. * The code is taken from AndroID v5.1.0_r1 (+ 1 line from v4.2_r1). * * @author mstevens */public class SMsstatusReport{ static final String LOG_TAG = SMsstatusReport.class.getSimplename(); /** * TP-Message-Type-Indicator * 9.2.3 */ private int mMti; /** * TP-Status - status of a prevIoUsly submitted SMS. * This fIEld applIEs to SMS-STATUS-REPORT messages. 0 indicates success; * see TS 23.040, 9.2.3.15 for description of other possible values. */ private int mStatus; /** * TP-Status - status of a prevIoUsly submitted SMS. * This fIEld is true iff the message is a SMS-STATUS-REPORT message. */ private boolean mIsstatusReportMessage = false; /** * TP-Service-Centre-Time-Stamp */ private long serviceCenterTimeStamp; /** * TP-discharge-Time */ private long dischargeTime; /** * Constructor * * @param pdu */ public SMsstatusReport(byte[] pdu) { // Parse: createFromPdu(pdu); if(!mIsstatusReportMessage) throw new IllegalArgumentException("This is not the pdu of a GSM SMS-STATUS-REPORT message"); } /** * TS 27.005 3.1, <pdu> 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... * * @param pdu * * @see Adapted from {@link com.androID.internal.telephony.gsm.SmsMessage#createFromPdu(byte[])} (originally static) */ private voID createFromPdu(byte[] pdu) { PduParser p = new PduParser(pdu); /*Object mScAddress = */p.getSCAddress(); // 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: throw new RuntimeException("Unsupported message type"); } } /** * Parses a SMS-STATUS-REPORT message. * * @param p A PduParser, cued past the first byte. * @param firstByte The first byte of the PDU, which contains MTI, etc. */ private voID parseSmsstatusReport(PduParser p, int firstByte) { mIsstatusReportMessage = true; // TP-Message-Reference /*int mMessageRef = */p.getByte(); // TP-RecipIEnt-Address /*Object mRecipIEntAddress = */p.getAddress(); // TP-Service-Centre-Time-Stamp serviceCenterTimeStamp = p.getSCTimestampMillis(); // TP-discharge-Time (line taken from AndroID v4.2_r1) dischargeTime = p.getSCTimestampMillis(); // TP-Status mStatus = p.getByte(); // The following are optional fIElds that may or may not be present. if (p.moreDataPresent()) {/* // TP-Parameter-Indicator int extraParams = p.getByte(); int moreExtraParams = extraParams; while ((moreExtraParams & 0x80) != 0) { // We only kNow how to parse a few extra parameters, all // indicated in the first TP-PI octet, so skip over any // additional TP-PI octets. moreExtraParams = p.getByte(); } // As per 3GPP 23.040 section 9.2.3.27 TP-Parameter-Indicator, // only process the byte if the reserved bits (bits3 to 6) are zero. if ((extraParams & 0x78) == 0) { // TP-Protocol-IDentifIEr if ((extraParams & 0x01) != 0) { mProtocolIDentifIEr = p.getByte(); } // TP-Data-Coding-Scheme if ((extraParams & 0x02) != 0) { mDataCodingScheme = p.getByte(); } // TP-User-Data-Length (implIEs existence of TP-User-Data) if ((extraParams & 0x04) != 0) { boolean hasUserDataheader = (firstByte & 0x40) == 0x40; parseUserData(p, hasUserDataheader); } }*/ } } /** * @return whether or not the original message was received on the receiver handset */ public boolean isReceived() { return mStatus == 0; } /** * @return the serviceCenterTimeStamp */ public long getServiceCenterTimeStamp() { return serviceCenterTimeStamp; } /** * @return the dischargeTime */ public long getdischargeTime() { return dischargeTime; } private static class PduParser { byte mPdu[]; int mCur; PduParser(byte[] pdu) { mPdu = pdu; mCur = 0; } /** * 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) { ret = null; } } mCur += len; return ret; } /** * returns non-sign-extended byte value */ int getByte() { return mPdu[mCur++] & 0xff; } /** * Any address except the SC address (eg, originating address) * See TS 23.040 9.1.2.5 * * mstevens: Made NON-FUNCTIONAL to remove dependency on internal AndroID classes. Always returns null but skips right number of bytes. */ Object/*GsmSmsAddress*/ getAddress() { //GsmSmsAddress ret; // "The Address-Length fIEld is an integer representation of // the number fIEld, i.e. excludes any semi-octet containing only // fill bits." // The TOA fIEld is not included as part of this int addressLength = mPdu[mCur] & 0xff; int lengthBytes = 2 + (addressLength + 1) / 2; /*try { ret = new GsmSmsAddress(mPdu, mCur, lengthBytes); } catch (ParseException e) { ret = null; //This is caught by createFromPdu(byte[] pdu) throw new RuntimeException(e.getMessage()); }*/ mCur += lengthBytes; return null;//ret; } /** * Parses an SC timestamp and returns a currentTimeMillis()-style timestamp * * @see http://en.wikipedia.org/wiki/GSM_03.40#Time_Format */ long getSCTimestampMillis() { // TP-Service-Centre-Time-Stamp int year = gsmBcdBytetoInt(mPdu[mCur++]); int month = gsmBcdBytetoInt(mPdu[mCur++]); int day = gsmBcdBytetoInt(mPdu[mCur++]); int hour = gsmBcdBytetoInt(mPdu[mCur++]); int minute = gsmBcdBytetoInt(mPdu[mCur++]); int second = gsmBcdBytetoInt(mPdu[mCur++]); // For the timezone, the most significant bit of the // least significant nibble is the sign byte // (meaning the max range of this fIEld is 79 quarter-hours, // which is more than enough) byte tzByte = mPdu[mCur++]; // Mask out sign bit. int timezoneOffset = gsmBcdBytetoInt((byte) (tzByte & (~0x08))); timezoneOffset = ((tzByte & 0x08) == 0) ? timezoneOffset : -timezoneOffset; Time time = new Time(Time.TIMEZONE_UTC); // It's 2006. Should I really support years < 2000? time.year = year >= 90 ? year + 1900 : year + 2000; time.month = month - 1; time.monthDay = day; time.hour = hour; time.minute = minute; time.second = second; // Timezone offset is in quarter hours. return time.toMillis(true) - (timezoneOffset * 15 * 60 * 1000); } /** * Decodes a GSM-style BCD byte, returning an int ranging from 0-99. * * In GSM land, the least significant BCD digit is stored in the most * significant nibble. * * Out-of-range digits are treated as 0 for the sake of the time stamp, * because of this: * * TS 23.040 section 9.2.3.11 * "if the MS receives a non-integer value in the SCTS, it shall * assume the digit is set to 0 but shall store the entire fIEld * exactly as received" * * @see Taken from com.androID.internal.telephony.uicc.IccUtils */ public static int gsmBcdBytetoInt(byte b) { int ret = 0; // treat out-of-range BCD values as 0 if((b & 0xf0) <= 0x90) ret = (b >> 4) & 0xf; if((b & 0x0f) <= 0x09) ret += (b & 0xf) * 10; return ret; } public boolean moreDataPresent() { return (mPdu.length > mCur); } }}
一些免责声明:
>这仅适用于GSM / 3GPP网络,不适用于CDMA / 3GPP;
>因为它基于AndroID源代码,所以上面的代码是Apache license v2.0许可的.
以上是内存溢出为你收集整理的Android:获取短信发送时间全部内容,希望文章能够帮你解决Android:获取短信发送时间所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)