summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xapi/system-current.txt2
-rw-r--r--telephony/java/android/telephony/SmsManager.java40
-rw-r--r--telephony/java/android/telephony/SmsMessage.java93
-rw-r--r--telephony/java/com/android/internal/telephony/cdma/SmsMessage.java160
-rw-r--r--telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java38
-rw-r--r--telephony/java/com/android/internal/telephony/gsm/SmsMessage.java269
6 files changed, 463 insertions, 139 deletions
diff --git a/api/system-current.txt b/api/system-current.txt
index 327f64268f8f..a9f977ecbbb4 100755
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -11756,6 +11756,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);
@@ -11773,6 +11774,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);
}
diff --git a/telephony/java/android/telephony/SmsManager.java b/telephony/java/android/telephony/SmsManager.java
index a88fb751d9d6..5cd7cf8fae8a 100644
--- a/telephony/java/android/telephony/SmsManager.java
+++ b/telephony/java/android/telephony/SmsManager.java
@@ -1658,7 +1658,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.
*
@@ -1672,21 +1672,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();
@@ -2120,6 +2125,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). */
diff --git a/telephony/java/android/telephony/SmsMessage.java b/telephony/java/android/telephony/SmsMessage.java
index 703bd08d9391..7a30f143a3a4 100644
--- a/telephony/java/android/telephony/SmsMessage.java
+++ b/telephony/java/android/telephony/SmsMessage.java
@@ -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.
diff --git a/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java b/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java
index 7a374fa6ccd2..d0c8024c56fe 100644
--- a/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java
+++ b/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java
@@ -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,
@@ -1058,6 +1044,72 @@ public class SmsMessage extends SmsMessageBase {
}
/**
+ * 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!
* @hide
diff --git a/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java b/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java
index cbf0f5c297e1..6ad6dd119f50 100644
--- a/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java
+++ b/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java
@@ -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);
diff --git a/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java b/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java
index 6874fcdce62c..c91ea696ec29 100644
--- a/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java
+++ b/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java
@@ -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.
@@ -258,12 +261,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
@@ -276,17 +282,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
@@ -299,18 +307,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
@@ -482,12 +492,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,
@@ -498,15 +510,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,
@@ -517,16 +529,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,
@@ -550,8 +561,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.
@@ -578,16 +588,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(
@@ -635,6 +647,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[];