Merge "New system API to create SMS PDU and expose copyMessageToIcc()"

am: ca45896352

Change-Id: I0a71827058f5ef75e164135516c6228649cfe072
This commit is contained in:
Taesu Lee
2020-01-22 09:17:14 -08:00
committed by android-build-merger
6 changed files with 463 additions and 139 deletions

View File

@@ -9182,6 +9182,7 @@ package android.telephony {
}
public final class SmsManager {
method @RequiresPermission(android.Manifest.permission.ACCESS_MESSAGES_ON_ICC) public boolean copyMessageToIcc(@Nullable byte[], @NonNull byte[], int);
method @RequiresPermission(android.Manifest.permission.ACCESS_MESSAGES_ON_ICC) public boolean deleteMessageFromIcc(int);
method public boolean disableCellBroadcastRange(int, int, int);
method public boolean enableCellBroadcastRange(int, int, int);
@@ -9193,6 +9194,7 @@ package android.telephony {
public class SmsMessage {
method @Nullable public static android.telephony.SmsMessage createFromNativeSmsSubmitPdu(@NonNull byte[], boolean);
method @Nullable public static android.telephony.SmsMessage.SubmitPdu getSmsPdu(int, int, @Nullable String, @NonNull String, @NonNull String, long);
method @NonNull @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public static byte[] getSubmitPduEncodedMessage(boolean, @NonNull String, @NonNull String, int, int, int, int, int, int);
}

View File

@@ -1577,7 +1577,7 @@ public final class SmsManager {
}
/**
* Copy a raw SMS PDU to the ICC.
* Copies a raw SMS PDU to the ICC.
* ICC (Integrated Circuit Card) is the card of the device.
* For example, this can be the SIM or USIM for GSM.
*
@@ -1591,21 +1591,26 @@ public final class SmsManager {
* operation is performed on the correct subscription.
* </p>
*
* @param smsc the SMSC for this message, or NULL for the default SMSC
* @param pdu the raw PDU to store
* @param status message status (STATUS_ON_ICC_READ, STATUS_ON_ICC_UNREAD,
* STATUS_ON_ICC_SENT, STATUS_ON_ICC_UNSENT)
* @return true for success
* @param smsc the SMSC for this messag or null for the default SMSC.
* @param pdu the raw PDU to store.
* @param status message status. One of these status:
* <code>STATUS_ON_ICC_READ</code>
* <code>STATUS_ON_ICC_UNREAD</code>
* <code>STATUS_ON_ICC_SENT</code>
* <code>STATUS_ON_ICC_UNSENT</code>
* @return true for success. Otherwise false.
*
* @throws IllegalArgumentException if pdu is NULL
* {@hide}
* @throws IllegalArgumentException if pdu is null.
* @hide
*/
@UnsupportedAppUsage
public boolean copyMessageToIcc(byte[] smsc, byte[] pdu,int status) {
@SystemApi
@RequiresPermission(Manifest.permission.ACCESS_MESSAGES_ON_ICC)
public boolean copyMessageToIcc(
@Nullable byte[] smsc, @NonNull byte[] pdu, @StatusOnIcc int status) {
boolean success = false;
if (null == pdu) {
throw new IllegalArgumentException("pdu is NULL");
if (pdu == null) {
throw new IllegalArgumentException("pdu is null");
}
try {
ISms iSms = getISmsService();
@@ -2035,6 +2040,17 @@ public final class SmsManager {
return ret;
}
/** @hide */
@IntDef(prefix = { "STATUS_ON_ICC_" }, value = {
STATUS_ON_ICC_FREE,
STATUS_ON_ICC_READ,
STATUS_ON_ICC_UNREAD,
STATUS_ON_ICC_SENT,
STATUS_ON_ICC_UNSENT
})
@Retention(RetentionPolicy.SOURCE)
public @interface StatusOnIcc {}
// see SmsMessage.getStatusOnIcc
/** Free space (TS 51.011 10.5.3 / 3GPP2 C.S0023 3.4.27). */

View File

@@ -585,13 +585,15 @@ public class SmsMessage {
*/
/**
* Get an SMS-SUBMIT PDU for a destination address and a message.
* Gets an SMS-SUBMIT PDU for a destination address and a message.
* This method will not attempt to use any GSM national language 7 bit encodings.
*
* @param scAddress Service Centre address. Null means use default.
* @return a <code>SubmitPdu</code> containing the encoded SC
* address, if applicable, and the encoded message.
* Returns null on encode error.
* @param scAddress Service Centre address. Null means use default.
* @param destinationAddress the address of the destination for the message.
* @param message string representation of the message payload.
* @param statusReportRequested indicates whether a report is requested for this message.
* @return a <code>SubmitPdu</code> containing the encoded SC address if applicable and the
* encoded message. Returns null on encode error.
*/
public static SubmitPdu getSubmitPdu(String scAddress,
String destinationAddress, String message, boolean statusReportRequested) {
@@ -604,17 +606,16 @@ public class SmsMessage {
}
/**
* Get an SMS-SUBMIT PDU for a destination address and a message.
* Gets an SMS-SUBMIT PDU for a destination address and a message.
* This method will not attempt to use any GSM national language 7 bit encodings.
*
* @param scAddress Service Centre address. Null means use default.
* @param scAddress Service Centre address. Null means use default.
* @param destinationAddress the address of the destination for the message.
* @param message String representation of the message payload.
* @param statusReportRequested Indicates whether a report is requested for this message.
* @param subId Subscription of the message
* @return a <code>SubmitPdu</code> containing the encoded SC
* address, if applicable, and the encoded message.
* Returns null on encode error.
* @param message string representation of the message payload.
* @param statusReportRequested indicates whether a report is requested for this message.
* @param subId subscription of the message.
* @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,
@@ -632,17 +633,16 @@ public class SmsMessage {
}
/**
* Get an SMS-SUBMIT PDU for a data message to a destination address &amp; port.
* Gets an SMS-SUBMIT PDU for a data message to a destination address &amp; port.
* This method will not attempt to use any GSM national language 7 bit encodings.
*
* @param scAddress Service Centre address. null == use default
* @param destinationAddress the address of the destination for the message
* @param destinationPort the port to deliver the message to at the
* destination
* @param data the data for the message
* @return a <code>SubmitPdu</code> containing the encoded SC
* address, if applicable, and the encoded message.
* Returns null on encode error.
* @param scAddress Service Centre address. Null means use default.
* @param destinationAddress the address of the destination for the message.
* @param destinationPort the port to deliver the message to at the destination.
* @param data the data for the message.
* @param statusReportRequested indicates whether a report is requested for this message.
* @return a <code>SubmitPdu</code> containing the encoded SC address if applicable and the
* encoded message. Returns null on encode error.
*/
public static SubmitPdu getSubmitPdu(String scAddress,
String destinationAddress, short destinationPort, byte[] data,
@@ -660,6 +660,55 @@ public class SmsMessage {
return new SubmitPdu(spb);
}
// TODO: SubmitPdu class is used for SMS-DELIVER also now. Refactor for SubmitPdu and new
// DeliverPdu accordingly.
/**
* Gets an SMS PDU to store in the ICC.
*
* @param subId subscription of the message.
* @param status message status. One of these status:
* <code>SmsManager.STATUS_ON_ICC_READ</code>
* <code>SmsManager.STATUS_ON_ICC_UNREAD</code>
* <code>SmsManager.STATUS_ON_ICC_SENT</code>
* <code>SmsManager.STATUS_ON_ICC_UNSENT</code>
* @param scAddress Service Centre address. Null means use default.
* @param address destination or originating address.
* @param message string representation of the message payload.
* @param date the time stamp the message was received.
* @return a <code>SubmitPdu</code> containing the encoded SC address if applicable and the
* encoded message. Returns null on encode error.
* @hide
*/
@SystemApi
@Nullable
public static SubmitPdu getSmsPdu(int subId, @SmsManager.StatusOnIcc int status,
@Nullable String scAddress, @NonNull String address, @NonNull String message,
long date) {
SubmitPduBase spb;
if (isCdmaVoice(subId)) { // 3GPP2 format
if (status == SmsManager.STATUS_ON_ICC_READ
|| status == SmsManager.STATUS_ON_ICC_UNREAD) { // Deliver PDU
spb = com.android.internal.telephony.cdma.SmsMessage.getDeliverPdu(address,
message, date);
} else { // Submit PDU
spb = com.android.internal.telephony.cdma.SmsMessage.getSubmitPdu(scAddress,
address, message, false /* statusReportRequested */, null /* smsHeader */);
}
} else { // 3GPP format
if (status == SmsManager.STATUS_ON_ICC_READ
|| status == SmsManager.STATUS_ON_ICC_UNREAD) { // Deliver PDU
spb = com.android.internal.telephony.gsm.SmsMessage.getDeliverPdu(scAddress,
address, message, date);
} else { // Submit PDU
spb = com.android.internal.telephony.gsm.SmsMessage.getSubmitPdu(scAddress,
address, message, false /* statusReportRequested */, null /* header */);
}
}
return spb != null ? new SubmitPdu(spb) : null;
}
/**
* Get an SMS-SUBMIT PDU's encoded message.
* This is used by Bluetooth MAP profile to handle long non UTF-8 SMS messages.

View File

@@ -201,26 +201,16 @@ public class SmsMessage extends SmsMessageBase {
}
/**
* TODO(cleanup): why do getSubmitPdu methods take an scAddr input
* and do nothing with it? GSM allows us to specify a SC (eg,
* when responding to an SMS that explicitly requests the response
* is sent to a specific SC), or pass null to use the default
* value. Is there no similar notion in CDMA? Or do we just not
* have it hooked up?
*/
/**
* Get an SMS-SUBMIT PDU for a destination address and a message
* Gets an SMS-SUBMIT PDU for a destination address and a message.
*
* @param scAddr Service Centre address. Null means use default.
* @param destAddr Address of the recipient.
* @param message String representation of the message payload.
* @param statusReportRequested Indicates whether a report is requested for this message.
* @param smsHeader Array containing the data for the User Data Header, preceded
* by the Element Identifiers.
* @return a <code>SubmitPdu</code> containing the encoded SC
* address, if applicable, and the encoded message.
* Returns null on encode error.
* @param scAddr Service Centre address. No use for this message.
* @param destAddr the address of the destination for the message.
* @param message string representation of the message payload.
* @param statusReportRequested indicates whether a report is requested for this message.
* @param smsHeader array containing the data for the User Data Header, preceded by the Element
* Identifiers.
* @return a <code>SubmitPdu</code> containing null SC address and the encoded message. Returns
* null on encode error.
* @hide
*/
@UnsupportedAppUsage
@@ -230,18 +220,17 @@ public class SmsMessage extends SmsMessageBase {
}
/**
* Get an SMS-SUBMIT PDU for a destination address and a message
* Gets an SMS-SUBMIT PDU for a destination address and a message.
*
* @param scAddr Service Centre address. Null means use default.
* @param destAddr Address of the recipient.
* @param message String representation of the message payload.
* @param statusReportRequested Indicates whether a report is requested for this message.
* @param smsHeader Array containing the data for the User Data Header, preceded
* by the Element Identifiers.
* @param priority Priority level of the message
* @return a <code>SubmitPdu</code> containing the encoded SC
* address, if applicable, and the encoded message.
* Returns null on encode error.
* @param scAddr Service Centre address. No use for this message.
* @param destAddr the address of the destination for the message.
* @param message string representation of the message payload.
* @param statusReportRequested indicates whether a report is requested for this message.
* @param smsHeader array containing the data for the User Data Header, preceded by the Element
* Identifiers.
* @param priority priority level of the message.
* @return a <code>SubmitPdu</code> containing null SC address and the encoded message. Returns
* null on encode error.
* @hide
*/
@UnsupportedAppUsage
@@ -264,16 +253,15 @@ public class SmsMessage extends SmsMessageBase {
}
/**
* Get an SMS-SUBMIT PDU for a data message to a destination address and port.
* Gets an SMS-SUBMIT PDU for a data message to a destination address &amp; port.
*
* @param scAddr Service Centre address. null == use default
* @param destAddr the address of the destination for the message
* @param destPort the port to deliver the message to at the
* destination
* @param data the data for the message
* @return a <code>SubmitPdu</code> containing the encoded SC
* address, if applicable, and the encoded message.
* Returns null on encode error.
* @param scAddr Service Centre address. No use for this message.
* @param destAddr the address of the destination for the message.
* @param destPort the port to deliver the message to at the destination.
* @param data the data for the message.
* @param statusReportRequested indicates whether a report is requested for this message.
* @return a <code>SubmitPdu</code> containing null SC address and the encoded message. Returns
* null on encode error.
*/
@UnsupportedAppUsage
public static SubmitPdu getSubmitPdu(String scAddr, String destAddr, int destPort,
@@ -304,14 +292,13 @@ public class SmsMessage extends SmsMessageBase {
}
/**
* Get an SMS-SUBMIT PDU for a data message to a destination address &amp; port
* Gets an SMS-SUBMIT PDU for a data message to a destination address &amp; port.
*
* @param destAddr the address of the destination for the message
* @param userData the data for the message
* @param statusReportRequested Indicates whether a report is requested for this message.
* @return a <code>SubmitPdu</code> containing the encoded SC
* address, if applicable, and the encoded message.
* Returns null on encode error.
* @param destAddr the address of the destination for the message.
* @param userData the data for the message.
* @param statusReportRequested indicates whether a report is requested for this message.
* @return a <code>SubmitPdu</code> containing null SC address and the encoded message. Returns
* null on encode error.
*/
@UnsupportedAppUsage
public static SubmitPdu getSubmitPdu(String destAddr, UserData userData,
@@ -320,15 +307,14 @@ public class SmsMessage extends SmsMessageBase {
}
/**
* Get an SMS-SUBMIT PDU for a data message to a destination address &amp; port
* Gets an SMS-SUBMIT PDU for a data message to a destination address &amp; port.
*
* @param destAddr the address of the destination for the message
* @param userData the data for the message
* @param statusReportRequested Indicates whether a report is requested for this message.
* @param priority Priority level of the message
* @return a <code>SubmitPdu</code> containing the encoded SC
* address, if applicable, and the encoded message.
* Returns null on encode error.
* @param destAddr the address of the destination for the message.
* @param userData the data for the message.
* @param statusReportRequested indicates whether a report is requested for this message.
* @param priority Priority level of the message.
* @return a <code>SubmitPdu</code> containing null SC address and the encoded message. Returns
* null on encode error.
*/
@UnsupportedAppUsage
public static SubmitPdu getSubmitPdu(String destAddr, UserData userData,
@@ -1057,6 +1043,72 @@ public class SmsMessage extends SmsMessageBase {
return null;
}
/**
* Gets an SMS-DELIVER PDU for a originating address and a message.
*
* @param origAddr the address of the originating for the message.
* @param message string representation of the message payload.
* @param date the time stamp the message was received.
* @return a <code>SubmitPdu</code> containing null SC address and the encoded message. Returns
* null on encode error.
* @hide
*/
public static SubmitPdu getDeliverPdu(String origAddr, String message, long date) {
if (origAddr == null || message == null) {
return null;
}
CdmaSmsAddress addr = CdmaSmsAddress.parse(origAddr);
if (addr == null) return null;
BearerData bearerData = new BearerData();
bearerData.messageType = BearerData.MESSAGE_TYPE_DELIVER;
bearerData.messageId = 0;
bearerData.deliveryAckReq = false;
bearerData.userAckReq = false;
bearerData.readAckReq = false;
bearerData.reportReq = false;
bearerData.userData = new UserData();
bearerData.userData.payloadStr = message;
bearerData.msgCenterTimeStamp = BearerData.TimeStamp.fromMillis(date);
byte[] encodedBearerData = BearerData.encode(bearerData);
if (encodedBearerData == null) return null;
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream(100);
DataOutputStream dos = new DataOutputStream(baos);
dos.writeInt(SmsEnvelope.TELESERVICE_WMT);
dos.writeInt(0); // servicePresent
dos.writeInt(0); // serviceCategory
dos.write(addr.digitMode);
dos.write(addr.numberMode);
dos.write(addr.ton); // number_type
dos.write(addr.numberPlan);
dos.write(addr.numberOfDigits);
dos.write(addr.origBytes, 0, addr.origBytes.length); // digits
// Subaddress is not supported.
dos.write(0); // subaddressType
dos.write(0); // subaddr_odd
dos.write(0); // subaddr_nbr_of_digits
dos.write(encodedBearerData.length);
dos.write(encodedBearerData, 0, encodedBearerData.length);
dos.close();
SubmitPdu pdu = new SubmitPdu();
pdu.encodedMessage = baos.toByteArray();
pdu.encodedScAddress = null;
return pdu;
} catch (IOException ex) {
Rlog.e(LOG_TAG, "creating Deliver PDU failed: " + ex);
}
return null;
}
/**
* Creates byte array (pseudo pdu) from SMS object.
* Note: Do not call this method more than once per object!

View File

@@ -32,6 +32,7 @@ import com.android.internal.telephony.uicc.IccUtils;
import com.android.internal.util.BitwiseInputStream;
import com.android.internal.util.BitwiseOutputStream;
import java.io.ByteArrayOutputStream;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
@@ -284,6 +285,33 @@ public final class BearerData {
return ts;
}
public static TimeStamp fromMillis(long timeInMillis) {
TimeStamp ts = new TimeStamp();
LocalDateTime localDateTime =
Instant.ofEpochMilli(timeInMillis).atZone(ts.mZoneId).toLocalDateTime();
int year = localDateTime.getYear();
if (year < 1996 || year > 2095) return null;
ts.year = year;
ts.month = localDateTime.getMonthValue();
ts.monthDay = localDateTime.getDayOfMonth();
ts.hour = localDateTime.getHour();
ts.minute = localDateTime.getMinute();
ts.second = localDateTime.getSecond();
return ts;
}
public byte[] toByteArray() {
int year = this.year % 100; // 00 - 99
ByteArrayOutputStream outStream = new ByteArrayOutputStream(6);
outStream.write((((year / 10) & 0x0F) << 4) | ((year % 10) & 0x0F));
outStream.write((((month / 10) << 4) & 0xF0) | ((month % 10) & 0x0F));
outStream.write((((monthDay / 10) << 4) & 0xF0) | ((monthDay % 10) & 0x0F));
outStream.write((((hour / 10) << 4) & 0xF0) | ((hour % 10) & 0x0F));
outStream.write((((minute / 10) << 4) & 0xF0) | ((minute % 10) & 0x0F));
outStream.write((((second / 10) << 4) & 0xF0) | ((second % 10) & 0x0F));
return outStream.toByteArray();
}
public long toMillis() {
LocalDateTime localDateTime =
LocalDateTime.of(year, month + 1, monthDay, hour, minute, second);
@@ -957,6 +985,12 @@ public final class BearerData {
}
}
private static void encodeMsgCenterTimeStamp(BearerData bData, BitwiseOutputStream outStream)
throws BitwiseOutputStream.AccessException {
outStream.write(8, 6);
outStream.writeByteArray(8 * 6, bData.msgCenterTimeStamp.toByteArray());
};
/**
* Create serialized representation for BearerData object.
* (See 3GPP2 C.R1001-F, v1.0, section 4.5 for layout details)
@@ -1021,6 +1055,10 @@ public final class BearerData {
outStream.write(8, SUBPARAM_SERVICE_CATEGORY_PROGRAM_RESULTS);
encodeScpResults(bData, outStream);
}
if (bData.msgCenterTimeStamp != null) {
outStream.write(8, SUBPARAM_MESSAGE_CENTER_TIME_STAMP);
encodeMsgCenterTimeStamp(bData, outStream);
}
return outStream.toByteArray();
} catch (BitwiseOutputStream.AccessException ex) {
Rlog.e(LOG_TAG, "BearerData encode failed: " + ex);

View File

@@ -42,8 +42,11 @@ import com.android.internal.telephony.uicc.IccUtils;
import java.io.ByteArrayOutputStream;
import java.io.UnsupportedEncodingException;
import java.text.ParseException;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
/**
* A Short Message Service message.
@@ -259,12 +262,15 @@ public class SmsMessage extends SmsMessageBase {
}
/**
* Get an SMS-SUBMIT PDU for a destination address and a message
* Gets an SMS-SUBMIT PDU for a destination address and a message.
*
* @param scAddress Service Centre address. Null means use default.
* @return a <code>SubmitPdu</code> containing the encoded SC
* address, if applicable, and the encoded message.
* Returns null on encode error.
* @param scAddress Service Centre address. Null means use default.
* @param destinationAddress the address of the destination for the message.
* @param message string representation of the message payload.
* @param statusReportRequested indicates whether a report is reuested for this message.
* @param header a byte array containing the data for the User Data Header.
* @return a <code>SubmitPdu</code> containing the encoded SC address if applicable and the
* encoded message. Returns null on encode error.
* @hide
*/
@UnsupportedAppUsage
@@ -277,17 +283,19 @@ public class SmsMessage extends SmsMessageBase {
/**
* Get an SMS-SUBMIT PDU for a destination address and a message using the
* specified encoding.
* Gets 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 scAddress Service Centre address. Null means use default.
* @param destinationAddress the address of the destination for the message.
* @param message string representation of the message payload.
* @param statusReportRequested indicates whether a report is reuested for this message.
* @param header a byte array containing the data for the User Data Header.
* @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.
* @return a <code>SubmitPdu</code> containing the encoded SC address if applicable and the
* encoded message. Returns null on encode error.
* @hide
*/
@UnsupportedAppUsage
@@ -300,18 +308,20 @@ public class SmsMessage extends SmsMessageBase {
}
/**
* Get an SMS-SUBMIT PDU for a destination address and a message using the
* specified encoding.
* Gets 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 scAddress Service Centre address. Null means use default.
* @param destinationAddress the address of the destination for the message.
* @param message string representation of the message payload.
* @param statusReportRequested indicates whether a report is reuested for this message.
* @param header a byte array containing the data for the User Data Header.
* @param encoding encoding defined by constants in
* com.android.internal.telephony.SmsConstants.ENCODING_*
* @param languageTable
* @param languageShiftTable
* @param validityPeriod Validity Period of the message in Minutes.
* @return a <code>SubmitPdu</code> containing the encoded SC
* address, if applicable, and the encoded message.
* Returns null on encode error.
* @return a <code>SubmitPdu</code> containing the encoded SC address if applicable and the
* encoded message. Returns null on encode error.
* @hide
*/
@UnsupportedAppUsage
@@ -483,12 +493,14 @@ public class SmsMessage extends SmsMessageBase {
}
/**
* Get an SMS-SUBMIT PDU for a destination address and a message
* Gets an SMS-SUBMIT PDU for a destination address and a message.
*
* @param scAddress Service Centre address. Null means use default.
* @return a <code>SubmitPdu</code> containing the encoded SC
* address, if applicable, and the encoded message.
* Returns null on encode error.
* @param scAddress Service Centre address. Null means use default.
* @param destinationAddress the address of the destination for the message.
* @param message string representation of the message payload.
* @param statusReportRequested indicates whether a report is reuested for this message.
* @return a <code>SubmitPdu</code> containing the encoded SC address if applicable and the
* encoded message. Returns null on encode error.
*/
@UnsupportedAppUsage
public static SubmitPdu getSubmitPdu(String scAddress,
@@ -499,15 +511,15 @@ public class SmsMessage extends SmsMessageBase {
}
/**
* Get an SMS-SUBMIT PDU for a destination address and a message
* Gets an SMS-SUBMIT PDU for a destination address and a message.
*
* @param scAddress Service Centre address. Null means use default.
* @param destinationAddress the address of the destination for the message
* @param statusReportRequested staus report of the message Requested
* @param scAddress Service Centre address. Null means use default.
* @param destinationAddress the address of the destination for the message.
* @param message string representation of the message payload.
* @param statusReportRequested indicates whether a report is reuested for this message.
* @param validityPeriod Validity Period of the message in Minutes.
* @return a <code>SubmitPdu</code> containing the encoded SC
* address, if applicable, and the encoded message.
* Returns null on encode error.
* @return a <code>SubmitPdu</code> containing the encoded SC address if applicable and the
* encoded message. Returns null on encode error.
*/
@UnsupportedAppUsage
public static SubmitPdu getSubmitPdu(String scAddress,
@@ -518,16 +530,15 @@ public class SmsMessage extends SmsMessageBase {
}
/**
* Get an SMS-SUBMIT PDU for a data message to a destination address &amp; port
* Gets an SMS-SUBMIT PDU for a data message to a destination address &amp; port.
*
* @param scAddress Service Centre address. null == use default
* @param destinationAddress the address of the destination for the message
* @param destinationPort the port to deliver the message to at the
* destination
* @param data the data for the message
* @return a <code>SubmitPdu</code> containing the encoded SC
* address, if applicable, and the encoded message.
* Returns null on encode error.
* @param scAddress Service Centre address. Null means use default.
* @param destinationAddress the address of the destination for the message.
* @param destinationPort the port to deliver the message to at the destination.
* @param data the data for the message.
* @param statusReportRequested indicates whether a report is reuested for this message.
* @return a <code>SubmitPdu</code> containing the encoded SC address if applicable and the
* encoded message. Returns null on encode error.
*/
public static SubmitPdu getSubmitPdu(String scAddress,
String destinationAddress, int destinationPort, byte[] data,
@@ -551,8 +562,7 @@ public class SmsMessage extends SmsMessageBase {
SubmitPdu ret = new SubmitPdu();
ByteArrayOutputStream bo = getSubmitPduHead(
scAddress, destinationAddress, (byte) 0x41, // MTI = SMS-SUBMIT,
// TP-UDHI = true
scAddress, destinationAddress, (byte) 0x41, /* TP-MTI=SMS-SUBMIT, TP-UDHI=true */
statusReportRequested, ret);
// Skip encoding pdu if error occurs when create pdu head and the error will be handled
// properly later on encodedMessage sanity check.
@@ -579,16 +589,18 @@ public class SmsMessage extends SmsMessageBase {
}
/**
* 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
* Creates 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 scAddress Service Centre address. Null means 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. Returns null on encode error.
* @param statusReportRequested indicates whether a report is reuested for this message.
* @param ret <code>SubmitPdu</code>.
* @return a byte array of the beginning of a SUBMIT PDU. Null for invalid destinationAddress.
*/
@UnsupportedAppUsage
private static ByteArrayOutputStream getSubmitPduHead(
@@ -636,6 +648,161 @@ public class SmsMessage extends SmsMessageBase {
return bo;
}
/**
* Gets an SMS-DELIVER PDU for an originating address and a message.
*
* @param scAddress Service Centre address. Null means use default.
* @param originatingAddress the address of the originating for the message.
* @param message string representation of the message payload.
* @param date the time stamp the message was received.
* @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 getDeliverPdu(
String scAddress, String originatingAddress, String message, long date) {
if (originatingAddress == null || message == null) {
return null;
}
// Find the best encoding to use
TextEncodingDetails ted = calculateLength(message, false);
int encoding = ted.codeUnitSize;
int languageTable = ted.languageTable;
int languageShiftTable = ted.languageShiftTable;
byte[] header = null;
if (encoding == ENCODING_7BIT && (languageTable != 0 || languageShiftTable != 0)) {
SmsHeader smsHeader = new SmsHeader();
smsHeader.languageTable = languageTable;
smsHeader.languageShiftTable = languageShiftTable;
header = SmsHeader.toByteArray(smsHeader);
}
SubmitPdu ret = new SubmitPdu();
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
bo.write(0); // SMS-DELIVER
byte[] oaBytes;
oaBytes = PhoneNumberUtils.networkPortionToCalledPartyBCD(originatingAddress);
// Return null for invalid originating address
if (oaBytes == null) return null;
// Originating address length in BCD digits, ignoring TON byte and pad
// TODO Should be better.
bo.write((oaBytes.length - 1) * 2 - ((oaBytes[oaBytes.length - 1] & 0xf0) == 0xf0 ? 1 : 0));
// Originating Address
bo.write(oaBytes, 0, oaBytes.length);
// TP-Protocol-Identifier
bo.write(0);
// 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) {
if (ex.getError() == EncodeException.ERROR_EXCEED_SIZE) {
Rlog.e(LOG_TAG, "Exceed size limitation EncodeException", ex);
return null;
} else {
// 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 (EncodeException ex1) {
Rlog.e(LOG_TAG, "Exceed size limitation EncodeException", ex1);
return null;
} 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
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);
}
// TP-Service-Centre-Time-Stamp
byte[] scts = new byte[7];
ZonedDateTime zoneDateTime = Instant.ofEpochMilli(date).atZone(ZoneId.systemDefault());
LocalDateTime localDateTime = zoneDateTime.toLocalDateTime();
// It indicates the difference, expressed in quarters of an hour, between the local time and
// GMT.
int timezoneOffset = zoneDateTime.getOffset().getTotalSeconds() / 60 / 15;
boolean negativeOffset = timezoneOffset < 0;
if (negativeOffset) {
timezoneOffset = -timezoneOffset;
}
int year = localDateTime.getYear();
int month = localDateTime.getMonthValue();
int day = localDateTime.getDayOfMonth();
int hour = localDateTime.getHour();
int minute = localDateTime.getMinute();
int second = localDateTime.getSecond();
year = year > 2000 ? year - 2000 : year - 1900;
scts[0] = (byte) ((((year % 10) & 0x0F) << 4) | ((year / 10) & 0x0F));
scts[1] = (byte) ((((month % 10) & 0x0F) << 4) | ((month / 10) & 0x0F));
scts[2] = (byte) ((((day % 10) & 0x0F) << 4) | ((day / 10) & 0x0F));
scts[3] = (byte) ((((hour % 10) & 0x0F) << 4) | ((hour / 10) & 0x0F));
scts[4] = (byte) ((((minute % 10) & 0x0F) << 4) | ((minute / 10) & 0x0F));
scts[5] = (byte) ((((second % 10) & 0x0F) << 4) | ((second / 10) & 0x0F));
scts[6] = (byte) ((((timezoneOffset % 10) & 0x0F) << 4) | ((timezoneOffset / 10) & 0x0F));
if (negativeOffset) {
scts[0] |= 0x08; // Negative offset
}
bo.write(scts, 0, scts.length);
bo.write(userData, 0, userData.length);
ret.encodedMessage = bo.toByteArray();
return ret;
}
private static class PduParser {
@UnsupportedAppUsage
byte mPdu[];