gpt4 book ai didi

Android:获取短信发送时间

转载 作者:太空狗 更新时间:2023-10-29 12:44:55 24 4
gpt4 key购买 nike

我开发了一个用于发送 SMS 消息的应用程序,使用 BroadcastReceivers 成功发送和(未)传递消息。

在我的投递接收者中,我想知道消息被投递给目标收件人的时间。由于偶尔会关闭发送和接收设备,我认为将我收到传送广播的时间视为实际传送时间是不正确的。

有没有办法在我的广播接收器中获得正确的传送时间?谢谢。

最佳答案

这是一个可行的解决方案。

通过研究com.android.internal.telephony.gsm.SmsMessage的源代码类(这是处理在 GSM/3GPP 网络上解析 SMS PDU 的 Android 内部类)我发现 SMS-STATUS-REPORTS(=“发送报告”)包含第二个时间戳值,即“放电时间”。不幸的是,公共(public) 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:获取短信发送时间,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19681290/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com