From c38bb60d867c5d61d90b7179a9ed2b2d1848124f Mon Sep 17 00:00:00 2001 From: Wink Saville Date: Wed, 11 Jul 2012 15:41:29 -0700 Subject: Create telephony-common - DO NOT MERGE telephony-common was created by moving some of frameworks/base/telephony to: frameworks/opt/telephony Change-Id: I32cbb5eec1fa239c1587e055c8f7ef4fc48fb62c --- src/java/android/provider/Telephony.java | 1993 ++++++++++++++++++++ .../android/telephony/CellBroadcastMessage.java | 422 +++++ src/java/android/telephony/SmsCbCmasInfo.java | 308 +++ src/java/android/telephony/SmsCbEtwsInfo.java | 206 ++ src/java/android/telephony/SmsCbLocation.java | 202 ++ src/java/android/telephony/SmsCbMessage.java | 382 ++++ src/java/android/telephony/SmsManager.java | 522 +++++ src/java/android/telephony/SmsMessage.java | 688 +++++++ src/java/android/telephony/gsm/SmsManager.java | 261 +++ src/java/android/telephony/gsm/SmsMessage.java | 628 ++++++ 10 files changed, 5612 insertions(+) create mode 100644 src/java/android/provider/Telephony.java create mode 100644 src/java/android/telephony/CellBroadcastMessage.java create mode 100644 src/java/android/telephony/SmsCbCmasInfo.java create mode 100644 src/java/android/telephony/SmsCbEtwsInfo.java create mode 100644 src/java/android/telephony/SmsCbLocation.java create mode 100644 src/java/android/telephony/SmsCbMessage.java create mode 100644 src/java/android/telephony/SmsManager.java create mode 100644 src/java/android/telephony/SmsMessage.java create mode 100644 src/java/android/telephony/gsm/SmsManager.java create mode 100644 src/java/android/telephony/gsm/SmsMessage.java (limited to 'src/java/android') diff --git a/src/java/android/provider/Telephony.java b/src/java/android/provider/Telephony.java new file mode 100644 index 0000000..dd8be66 --- /dev/null +++ b/src/java/android/provider/Telephony.java @@ -0,0 +1,1993 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.provider; + +import android.annotation.SdkConstant; +import android.annotation.SdkConstant.SdkConstantType; +import android.content.ContentResolver; +import android.content.ContentValues; +import android.content.Context; +import android.content.Intent; +import android.database.Cursor; +import android.database.sqlite.SqliteWrapper; +import android.net.Uri; +import android.os.Environment; +import android.telephony.SmsMessage; +import android.text.TextUtils; +import android.util.Log; +import android.util.Patterns; + + +import java.util.HashSet; +import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * The Telephony provider contains data related to phone operation. + * + * @hide + */ +public final class Telephony { + private static final String TAG = "Telephony"; + private static final boolean DEBUG = true; + private static final boolean LOCAL_LOGV = false; + + // Constructor + public Telephony() { + } + + /** + * Base columns for tables that contain text based SMSs. + */ + public interface TextBasedSmsColumns { + /** + * The type of the message + *

Type: INTEGER

+ */ + public static final String TYPE = "type"; + + public static final int MESSAGE_TYPE_ALL = 0; + public static final int MESSAGE_TYPE_INBOX = 1; + public static final int MESSAGE_TYPE_SENT = 2; + public static final int MESSAGE_TYPE_DRAFT = 3; + public static final int MESSAGE_TYPE_OUTBOX = 4; + public static final int MESSAGE_TYPE_FAILED = 5; // for failed outgoing messages + public static final int MESSAGE_TYPE_QUEUED = 6; // for messages to send later + + + /** + * The thread ID of the message + *

Type: INTEGER

+ */ + public static final String THREAD_ID = "thread_id"; + + /** + * The address of the other party + *

Type: TEXT

+ */ + public static final String ADDRESS = "address"; + + /** + * The person ID of the sender + *

Type: INTEGER (long)

+ */ + public static final String PERSON_ID = "person"; + + /** + * The date the message was received + *

Type: INTEGER (long)

+ */ + public static final String DATE = "date"; + + /** + * The date the message was sent + *

Type: INTEGER (long)

+ */ + public static final String DATE_SENT = "date_sent"; + + /** + * Has the message been read + *

Type: INTEGER (boolean)

+ */ + public static final String READ = "read"; + + /** + * Indicates whether this message has been seen by the user. The "seen" flag will be + * used to figure out whether we need to throw up a statusbar notification or not. + */ + public static final String SEEN = "seen"; + + /** + * The TP-Status value for the message, or -1 if no status has + * been received + */ + public static final String STATUS = "status"; + + public static final int STATUS_NONE = -1; + public static final int STATUS_COMPLETE = 0; + public static final int STATUS_PENDING = 32; + public static final int STATUS_FAILED = 64; + + /** + * The subject of the message, if present + *

Type: TEXT

+ */ + public static final String SUBJECT = "subject"; + + /** + * The body of the message + *

Type: TEXT

+ */ + public static final String BODY = "body"; + + /** + * The id of the sender of the conversation, if present + *

Type: INTEGER (reference to item in content://contacts/people)

+ */ + public static final String PERSON = "person"; + + /** + * The protocol identifier code + *

Type: INTEGER

+ */ + public static final String PROTOCOL = "protocol"; + + /** + * Whether the TP-Reply-Path bit was set on this message + *

Type: BOOLEAN

+ */ + public static final String REPLY_PATH_PRESENT = "reply_path_present"; + + /** + * The service center (SC) through which to send the message, if present + *

Type: TEXT

+ */ + public static final String SERVICE_CENTER = "service_center"; + + /** + * Has the message been locked? + *

Type: INTEGER (boolean)

+ */ + public static final String LOCKED = "locked"; + + /** + * Error code associated with sending or receiving this message + *

Type: INTEGER

+ */ + public static final String ERROR_CODE = "error_code"; + + /** + * Meta data used externally. + *

Type: TEXT

+ */ + public static final String META_DATA = "meta_data"; + } + + /** + * Contains all text based SMS messages. + */ + public static final class Sms implements BaseColumns, TextBasedSmsColumns { + public static final Cursor query(ContentResolver cr, String[] projection) { + return cr.query(CONTENT_URI, projection, null, null, DEFAULT_SORT_ORDER); + } + + public static final Cursor query(ContentResolver cr, String[] projection, + String where, String orderBy) { + return cr.query(CONTENT_URI, projection, where, + null, orderBy == null ? DEFAULT_SORT_ORDER : orderBy); + } + + /** + * The content:// style URL for this table + */ + public static final Uri CONTENT_URI = + Uri.parse("content://sms"); + + /** + * The default sort order for this table + */ + public static final String DEFAULT_SORT_ORDER = "date DESC"; + + /** + * Add an SMS to the given URI. + * + * @param resolver the content resolver to use + * @param uri the URI to add the message to + * @param address the address of the sender + * @param body the body of the message + * @param subject the psuedo-subject of the message + * @param date the timestamp for the message + * @param read true if the message has been read, false if not + * @param deliveryReport true if a delivery report was requested, false if not + * @return the URI for the new message + */ + public static Uri addMessageToUri(ContentResolver resolver, + Uri uri, String address, String body, String subject, + Long date, boolean read, boolean deliveryReport) { + return addMessageToUri(resolver, uri, address, body, subject, + date, read, deliveryReport, -1L); + } + + /** + * Add an SMS to the given URI with thread_id specified. + * + * @param resolver the content resolver to use + * @param uri the URI to add the message to + * @param address the address of the sender + * @param body the body of the message + * @param subject the psuedo-subject of the message + * @param date the timestamp for the message + * @param read true if the message has been read, false if not + * @param deliveryReport true if a delivery report was requested, false if not + * @param threadId the thread_id of the message + * @return the URI for the new message + */ + public static Uri addMessageToUri(ContentResolver resolver, + Uri uri, String address, String body, String subject, + Long date, boolean read, boolean deliveryReport, long threadId) { + ContentValues values = new ContentValues(7); + + values.put(ADDRESS, address); + if (date != null) { + values.put(DATE, date); + } + values.put(READ, read ? Integer.valueOf(1) : Integer.valueOf(0)); + values.put(SUBJECT, subject); + values.put(BODY, body); + if (deliveryReport) { + values.put(STATUS, STATUS_PENDING); + } + if (threadId != -1L) { + values.put(THREAD_ID, threadId); + } + return resolver.insert(uri, values); + } + + /** + * Move a message to the given folder. + * + * @param context the context to use + * @param uri the message to move + * @param folder the folder to move to + * @return true if the operation succeeded + */ + public static boolean moveMessageToFolder(Context context, + Uri uri, int folder, int error) { + if (uri == null) { + return false; + } + + boolean markAsUnread = false; + boolean markAsRead = false; + switch(folder) { + case MESSAGE_TYPE_INBOX: + case MESSAGE_TYPE_DRAFT: + break; + case MESSAGE_TYPE_OUTBOX: + case MESSAGE_TYPE_SENT: + markAsRead = true; + break; + case MESSAGE_TYPE_FAILED: + case MESSAGE_TYPE_QUEUED: + markAsUnread = true; + break; + default: + return false; + } + + ContentValues values = new ContentValues(3); + + values.put(TYPE, folder); + if (markAsUnread) { + values.put(READ, Integer.valueOf(0)); + } else if (markAsRead) { + values.put(READ, Integer.valueOf(1)); + } + values.put(ERROR_CODE, error); + + return 1 == SqliteWrapper.update(context, context.getContentResolver(), + uri, values, null, null); + } + + /** + * Returns true iff the folder (message type) identifies an + * outgoing message. + */ + public static boolean isOutgoingFolder(int messageType) { + return (messageType == MESSAGE_TYPE_FAILED) + || (messageType == MESSAGE_TYPE_OUTBOX) + || (messageType == MESSAGE_TYPE_SENT) + || (messageType == MESSAGE_TYPE_QUEUED); + } + + /** + * Contains all text based SMS messages in the SMS app's inbox. + */ + public static final class Inbox implements BaseColumns, TextBasedSmsColumns { + /** + * The content:// style URL for this table + */ + public static final Uri CONTENT_URI = + Uri.parse("content://sms/inbox"); + + /** + * The default sort order for this table + */ + public static final String DEFAULT_SORT_ORDER = "date DESC"; + + /** + * Add an SMS to the Draft box. + * + * @param resolver the content resolver to use + * @param address the address of the sender + * @param body the body of the message + * @param subject the psuedo-subject of the message + * @param date the timestamp for the message + * @param read true if the message has been read, false if not + * @return the URI for the new message + */ + public static Uri addMessage(ContentResolver resolver, + String address, String body, String subject, Long date, + boolean read) { + return addMessageToUri(resolver, CONTENT_URI, address, body, + subject, date, read, false); + } + } + + /** + * Contains all sent text based SMS messages in the SMS app's. + */ + public static final class Sent implements BaseColumns, TextBasedSmsColumns { + /** + * The content:// style URL for this table + */ + public static final Uri CONTENT_URI = + Uri.parse("content://sms/sent"); + + /** + * The default sort order for this table + */ + public static final String DEFAULT_SORT_ORDER = "date DESC"; + + /** + * Add an SMS to the Draft box. + * + * @param resolver the content resolver to use + * @param address the address of the sender + * @param body the body of the message + * @param subject the psuedo-subject of the message + * @param date the timestamp for the message + * @return the URI for the new message + */ + public static Uri addMessage(ContentResolver resolver, + String address, String body, String subject, Long date) { + return addMessageToUri(resolver, CONTENT_URI, address, body, + subject, date, true, false); + } + } + + /** + * Contains all sent text based SMS messages in the SMS app's. + */ + public static final class Draft implements BaseColumns, TextBasedSmsColumns { + /** + * The content:// style URL for this table + */ + public static final Uri CONTENT_URI = + Uri.parse("content://sms/draft"); + + /** + * The default sort order for this table + */ + public static final String DEFAULT_SORT_ORDER = "date DESC"; + + /** + * Add an SMS to the Draft box. + * + * @param resolver the content resolver to use + * @param address the address of the sender + * @param body the body of the message + * @param subject the psuedo-subject of the message + * @param date the timestamp for the message + * @return the URI for the new message + */ + public static Uri addMessage(ContentResolver resolver, + String address, String body, String subject, Long date) { + return addMessageToUri(resolver, CONTENT_URI, address, body, + subject, date, true, false); + } + + /** + * Save over an existing draft message. + * + * @param resolver the content resolver to use + * @param uri of existing message + * @param body the new body for the draft message + * @return true is successful, false otherwise + */ + public static boolean saveMessage(ContentResolver resolver, + Uri uri, String body) { + ContentValues values = new ContentValues(2); + values.put(BODY, body); + values.put(DATE, System.currentTimeMillis()); + return resolver.update(uri, values, null, null) == 1; + } + } + + /** + * Contains all pending outgoing text based SMS messages. + */ + public static final class Outbox implements BaseColumns, TextBasedSmsColumns { + /** + * The content:// style URL for this table + */ + public static final Uri CONTENT_URI = + Uri.parse("content://sms/outbox"); + + /** + * The default sort order for this table + */ + public static final String DEFAULT_SORT_ORDER = "date DESC"; + + /** + * Add an SMS to the Out box. + * + * @param resolver the content resolver to use + * @param address the address of the sender + * @param body the body of the message + * @param subject the psuedo-subject of the message + * @param date the timestamp for the message + * @param deliveryReport whether a delivery report was requested for the message + * @return the URI for the new message + */ + public static Uri addMessage(ContentResolver resolver, + String address, String body, String subject, Long date, + boolean deliveryReport, long threadId) { + return addMessageToUri(resolver, CONTENT_URI, address, body, + subject, date, true, deliveryReport, threadId); + } + } + + /** + * Contains all sent text-based SMS messages in the SMS app's. + */ + public static final class Conversations + implements BaseColumns, TextBasedSmsColumns { + /** + * The content:// style URL for this table + */ + public static final Uri CONTENT_URI = + Uri.parse("content://sms/conversations"); + + /** + * The default sort order for this table + */ + public static final String DEFAULT_SORT_ORDER = "date DESC"; + + /** + * The first 45 characters of the body of the message + *

Type: TEXT

+ */ + public static final String SNIPPET = "snippet"; + + /** + * The number of messages in the conversation + *

Type: INTEGER

+ */ + public static final String MESSAGE_COUNT = "msg_count"; + } + + /** + * Contains info about SMS related Intents that are broadcast. + */ + public static final class Intents { + /** + * Set by BroadcastReceiver. Indicates the message was handled + * successfully. + */ + public static final int RESULT_SMS_HANDLED = 1; + + /** + * Set by BroadcastReceiver. Indicates a generic error while + * processing the message. + */ + public static final int RESULT_SMS_GENERIC_ERROR = 2; + + /** + * Set by BroadcastReceiver. Indicates insufficient memory to store + * the message. + */ + public static final int RESULT_SMS_OUT_OF_MEMORY = 3; + + /** + * Set by BroadcastReceiver. Indicates the message, while + * possibly valid, is of a format or encoding that is not + * supported. + */ + public static final int RESULT_SMS_UNSUPPORTED = 4; + + /** + * Broadcast Action: A new text based SMS message has been received + * by the device. The intent will have the following extra + * values:

+ * + * + * + *

The extra values can be extracted using + * {@link #getMessagesFromIntent(Intent)}.

+ * + *

If a BroadcastReceiver encounters an error while processing + * this intent it should set the result code appropriately.

+ */ + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + public static final String SMS_RECEIVED_ACTION = + "android.provider.Telephony.SMS_RECEIVED"; + + /** + * Broadcast Action: A new data based SMS message has been received + * by the device. The intent will have the following extra + * values:

+ * + * + * + *

The extra values can be extracted using + * {@link #getMessagesFromIntent(Intent)}.

+ * + *

If a BroadcastReceiver encounters an error while processing + * this intent it should set the result code appropriately.

+ */ + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + public static final String DATA_SMS_RECEIVED_ACTION = + "android.intent.action.DATA_SMS_RECEIVED"; + + /** + * Broadcast Action: A new WAP PUSH message has been received by the + * device. The intent will have the following extra + * values:

+ * + * + * + *

If a BroadcastReceiver encounters an error while processing + * this intent it should set the result code appropriately.

+ * + *

The contentTypeParameters extra value is map of content parameters keyed by + * their names.

+ * + *

If any unassigned well-known parameters are encountered, the key of the map will + * be 'unassigned/0x...', where '...' is the hex value of the unassigned parameter. If + * a parameter has No-Value the value in the map will be null.

+ */ + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + public static final String WAP_PUSH_RECEIVED_ACTION = + "android.provider.Telephony.WAP_PUSH_RECEIVED"; + + /** + * Broadcast Action: A new Cell Broadcast message has been received + * by the device. The intent will have the following extra + * values:

+ * + * + * + *

The extra values can be extracted using + * {@link #getMessagesFromIntent(Intent)}.

+ * + *

If a BroadcastReceiver encounters an error while processing + * this intent it should set the result code appropriately.

+ */ + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + public static final String SMS_CB_RECEIVED_ACTION = + "android.provider.Telephony.SMS_CB_RECEIVED"; + + /** + * Broadcast Action: A new Emergency Broadcast message has been received + * by the device. The intent will have the following extra + * values:

+ * + * + * + *

The extra values can be extracted using + * {@link #getMessagesFromIntent(Intent)}.

+ * + *

If a BroadcastReceiver encounters an error while processing + * this intent it should set the result code appropriately.

+ */ + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + public static final String SMS_EMERGENCY_CB_RECEIVED_ACTION = + "android.provider.Telephony.SMS_EMERGENCY_CB_RECEIVED"; + + /** + * Broadcast Action: A new CDMA SMS has been received containing Service Category + * Program Data (updates the list of enabled broadcast channels). The intent will + * have the following extra values:

+ * + * + * + *

The extra values can be extracted using + * {@link #getMessagesFromIntent(Intent)}.

+ * + *

If a BroadcastReceiver encounters an error while processing + * this intent it should set the result code appropriately.

+ */ + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + public static final String SMS_SERVICE_CATEGORY_PROGRAM_DATA_RECEIVED_ACTION = + "android.provider.Telephony.SMS_SERVICE_CATEGORY_PROGRAM_DATA_RECEIVED"; + + /** + * Broadcast Action: The SIM storage for SMS messages is full. If + * space is not freed, messages targeted for the SIM (class 2) may + * not be saved. + */ + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + public static final String SIM_FULL_ACTION = + "android.provider.Telephony.SIM_FULL"; + + /** + * Broadcast Action: An incoming SMS has been rejected by the + * telephony framework. This intent is sent in lieu of any + * of the RECEIVED_ACTION intents. The intent will have the + * following extra value:

+ * + * + + */ + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + public static final String SMS_REJECTED_ACTION = + "android.provider.Telephony.SMS_REJECTED"; + + /** + * Read the PDUs out of an {@link #SMS_RECEIVED_ACTION} or a + * {@link #DATA_SMS_RECEIVED_ACTION} intent. + * + * @param intent the intent to read from + * @return an array of SmsMessages for the PDUs + */ + public static SmsMessage[] getMessagesFromIntent( + Intent intent) { + Object[] messages = (Object[]) intent.getSerializableExtra("pdus"); + String format = intent.getStringExtra("format"); + byte[][] pduObjs = new byte[messages.length][]; + + for (int i = 0; i < messages.length; i++) { + pduObjs[i] = (byte[]) messages[i]; + } + byte[][] pdus = new byte[pduObjs.length][]; + int pduCount = pdus.length; + SmsMessage[] msgs = new SmsMessage[pduCount]; + for (int i = 0; i < pduCount; i++) { + pdus[i] = pduObjs[i]; + msgs[i] = SmsMessage.createFromPdu(pdus[i], format); + } + return msgs; + } + } + } + + /** + * Base columns for tables that contain MMSs. + */ + public interface BaseMmsColumns extends BaseColumns { + + public static final int MESSAGE_BOX_ALL = 0; + public static final int MESSAGE_BOX_INBOX = 1; + public static final int MESSAGE_BOX_SENT = 2; + public static final int MESSAGE_BOX_DRAFTS = 3; + public static final int MESSAGE_BOX_OUTBOX = 4; + + /** + * The date the message was received. + *

Type: INTEGER (long)

+ */ + public static final String DATE = "date"; + + /** + * The date the message was sent. + *

Type: INTEGER (long)

+ */ + public static final String DATE_SENT = "date_sent"; + + /** + * The box which the message belong to, for example, MESSAGE_BOX_INBOX. + *

Type: INTEGER

+ */ + public static final String MESSAGE_BOX = "msg_box"; + + /** + * Has the message been read. + *

Type: INTEGER (boolean)

+ */ + public static final String READ = "read"; + + /** + * Indicates whether this message has been seen by the user. The "seen" flag will be + * used to figure out whether we need to throw up a statusbar notification or not. + */ + public static final String SEEN = "seen"; + + /** + * The Message-ID of the message. + *

Type: TEXT

+ */ + public static final String MESSAGE_ID = "m_id"; + + /** + * The subject of the message, if present. + *

Type: TEXT

+ */ + public static final String SUBJECT = "sub"; + + /** + * The character set of the subject, if present. + *

Type: INTEGER

+ */ + public static final String SUBJECT_CHARSET = "sub_cs"; + + /** + * The Content-Type of the message. + *

Type: TEXT

+ */ + public static final String CONTENT_TYPE = "ct_t"; + + /** + * The Content-Location of the message. + *

Type: TEXT

+ */ + public static final String CONTENT_LOCATION = "ct_l"; + + /** + * The address of the sender. + *

Type: TEXT

+ */ + public static final String FROM = "from"; + + /** + * The address of the recipients. + *

Type: TEXT

+ */ + public static final String TO = "to"; + + /** + * The address of the cc. recipients. + *

Type: TEXT

+ */ + public static final String CC = "cc"; + + /** + * The address of the bcc. recipients. + *

Type: TEXT

+ */ + public static final String BCC = "bcc"; + + /** + * The expiry time of the message. + *

Type: INTEGER

+ */ + public static final String EXPIRY = "exp"; + + /** + * The class of the message. + *

Type: TEXT

+ */ + public static final String MESSAGE_CLASS = "m_cls"; + + /** + * The type of the message defined by MMS spec. + *

Type: INTEGER

+ */ + public static final String MESSAGE_TYPE = "m_type"; + + /** + * The version of specification that this message conform. + *

Type: INTEGER

+ */ + public static final String MMS_VERSION = "v"; + + /** + * The size of the message. + *

Type: INTEGER

+ */ + public static final String MESSAGE_SIZE = "m_size"; + + /** + * The priority of the message. + *

Type: TEXT

+ */ + public static final String PRIORITY = "pri"; + + /** + * The read-report of the message. + *

Type: TEXT

+ */ + public static final String READ_REPORT = "rr"; + + /** + * Whether the report is allowed. + *

Type: TEXT

+ */ + public static final String REPORT_ALLOWED = "rpt_a"; + + /** + * The response-status of the message. + *

Type: INTEGER

+ */ + public static final String RESPONSE_STATUS = "resp_st"; + + /** + * The status of the message. + *

Type: INTEGER

+ */ + public static final String STATUS = "st"; + + /** + * The transaction-id of the message. + *

Type: TEXT

+ */ + public static final String TRANSACTION_ID = "tr_id"; + + /** + * The retrieve-status of the message. + *

Type: INTEGER

+ */ + public static final String RETRIEVE_STATUS = "retr_st"; + + /** + * The retrieve-text of the message. + *

Type: TEXT

+ */ + public static final String RETRIEVE_TEXT = "retr_txt"; + + /** + * The character set of the retrieve-text. + *

Type: TEXT

+ */ + public static final String RETRIEVE_TEXT_CHARSET = "retr_txt_cs"; + + /** + * The read-status of the message. + *

Type: INTEGER

+ */ + public static final String READ_STATUS = "read_status"; + + /** + * The content-class of the message. + *

Type: INTEGER

+ */ + public static final String CONTENT_CLASS = "ct_cls"; + + /** + * The delivery-report of the message. + *

Type: INTEGER

+ */ + public static final String DELIVERY_REPORT = "d_rpt"; + + /** + * The delivery-time-token of the message. + *

Type: INTEGER

+ */ + public static final String DELIVERY_TIME_TOKEN = "d_tm_tok"; + + /** + * The delivery-time of the message. + *

Type: INTEGER

+ */ + public static final String DELIVERY_TIME = "d_tm"; + + /** + * The response-text of the message. + *

Type: TEXT

+ */ + public static final String RESPONSE_TEXT = "resp_txt"; + + /** + * The sender-visibility of the message. + *

Type: TEXT

+ */ + public static final String SENDER_VISIBILITY = "s_vis"; + + /** + * The reply-charging of the message. + *

Type: INTEGER

+ */ + public static final String REPLY_CHARGING = "r_chg"; + + /** + * The reply-charging-deadline-token of the message. + *

Type: INTEGER

+ */ + public static final String REPLY_CHARGING_DEADLINE_TOKEN = "r_chg_dl_tok"; + + /** + * The reply-charging-deadline of the message. + *

Type: INTEGER

+ */ + public static final String REPLY_CHARGING_DEADLINE = "r_chg_dl"; + + /** + * The reply-charging-id of the message. + *

Type: TEXT

+ */ + public static final String REPLY_CHARGING_ID = "r_chg_id"; + + /** + * The reply-charging-size of the message. + *

Type: INTEGER

+ */ + public static final String REPLY_CHARGING_SIZE = "r_chg_sz"; + + /** + * The previously-sent-by of the message. + *

Type: TEXT

+ */ + public static final String PREVIOUSLY_SENT_BY = "p_s_by"; + + /** + * The previously-sent-date of the message. + *

Type: INTEGER

+ */ + public static final String PREVIOUSLY_SENT_DATE = "p_s_d"; + + /** + * The store of the message. + *

Type: TEXT

+ */ + public static final String STORE = "store"; + + /** + * The mm-state of the message. + *

Type: INTEGER

+ */ + public static final String MM_STATE = "mm_st"; + + /** + * The mm-flags-token of the message. + *

Type: INTEGER

+ */ + public static final String MM_FLAGS_TOKEN = "mm_flg_tok"; + + /** + * The mm-flags of the message. + *

Type: TEXT

+ */ + public static final String MM_FLAGS = "mm_flg"; + + /** + * The store-status of the message. + *

Type: TEXT

+ */ + public static final String STORE_STATUS = "store_st"; + + /** + * The store-status-text of the message. + *

Type: TEXT

+ */ + public static final String STORE_STATUS_TEXT = "store_st_txt"; + + /** + * The stored of the message. + *

Type: TEXT

+ */ + public static final String STORED = "stored"; + + /** + * The totals of the message. + *

Type: TEXT

+ */ + public static final String TOTALS = "totals"; + + /** + * The mbox-totals of the message. + *

Type: TEXT

+ */ + public static final String MBOX_TOTALS = "mb_t"; + + /** + * The mbox-totals-token of the message. + *

Type: INTEGER

+ */ + public static final String MBOX_TOTALS_TOKEN = "mb_t_tok"; + + /** + * The quotas of the message. + *

Type: TEXT

+ */ + public static final String QUOTAS = "qt"; + + /** + * The mbox-quotas of the message. + *

Type: TEXT

+ */ + public static final String MBOX_QUOTAS = "mb_qt"; + + /** + * The mbox-quotas-token of the message. + *

Type: INTEGER

+ */ + public static final String MBOX_QUOTAS_TOKEN = "mb_qt_tok"; + + /** + * The message-count of the message. + *

Type: INTEGER

+ */ + public static final String MESSAGE_COUNT = "m_cnt"; + + /** + * The start of the message. + *

Type: INTEGER

+ */ + public static final String START = "start"; + + /** + * The distribution-indicator of the message. + *

Type: TEXT

+ */ + public static final String DISTRIBUTION_INDICATOR = "d_ind"; + + /** + * The element-descriptor of the message. + *

Type: TEXT

+ */ + public static final String ELEMENT_DESCRIPTOR = "e_des"; + + /** + * The limit of the message. + *

Type: INTEGER

+ */ + public static final String LIMIT = "limit"; + + /** + * The recommended-retrieval-mode of the message. + *

Type: INTEGER

+ */ + public static final String RECOMMENDED_RETRIEVAL_MODE = "r_r_mod"; + + /** + * The recommended-retrieval-mode-text of the message. + *

Type: TEXT

+ */ + public static final String RECOMMENDED_RETRIEVAL_MODE_TEXT = "r_r_mod_txt"; + + /** + * The status-text of the message. + *

Type: TEXT

+ */ + public static final String STATUS_TEXT = "st_txt"; + + /** + * The applic-id of the message. + *

Type: TEXT

+ */ + public static final String APPLIC_ID = "apl_id"; + + /** + * The reply-applic-id of the message. + *

Type: TEXT

+ */ + public static final String REPLY_APPLIC_ID = "r_apl_id"; + + /** + * The aux-applic-id of the message. + *

Type: TEXT

+ */ + public static final String AUX_APPLIC_ID = "aux_apl_id"; + + /** + * The drm-content of the message. + *

Type: TEXT

+ */ + public static final String DRM_CONTENT = "drm_c"; + + /** + * The adaptation-allowed of the message. + *

Type: TEXT

+ */ + public static final String ADAPTATION_ALLOWED = "adp_a"; + + /** + * The replace-id of the message. + *

Type: TEXT

+ */ + public static final String REPLACE_ID = "repl_id"; + + /** + * The cancel-id of the message. + *

Type: TEXT

+ */ + public static final String CANCEL_ID = "cl_id"; + + /** + * The cancel-status of the message. + *

Type: INTEGER

+ */ + public static final String CANCEL_STATUS = "cl_st"; + + /** + * The thread ID of the message + *

Type: INTEGER

+ */ + public static final String THREAD_ID = "thread_id"; + + /** + * Has the message been locked? + *

Type: INTEGER (boolean)

+ */ + public static final String LOCKED = "locked"; + + /** + * Meta data used externally. + *

Type: TEXT

+ */ + public static final String META_DATA = "meta_data"; + } + + /** + * Columns for the "canonical_addresses" table used by MMS and + * SMS." + */ + public interface CanonicalAddressesColumns extends BaseColumns { + /** + * An address used in MMS or SMS. Email addresses are + * converted to lower case and are compared by string + * equality. Other addresses are compared using + * PHONE_NUMBERS_EQUAL. + *

Type: TEXT

+ */ + public static final String ADDRESS = "address"; + } + + /** + * Columns for the "threads" table used by MMS and SMS. + */ + public interface ThreadsColumns extends BaseColumns { + /** + * The date at which the thread was created. + * + *

Type: INTEGER (long)

+ */ + public static final String DATE = "date"; + + /** + * A string encoding of the recipient IDs of the recipients of + * the message, in numerical order and separated by spaces. + *

Type: TEXT

+ */ + public static final String RECIPIENT_IDS = "recipient_ids"; + + /** + * The message count of the thread. + *

Type: INTEGER

+ */ + public static final String MESSAGE_COUNT = "message_count"; + /** + * Indicates whether all messages of the thread have been read. + *

Type: INTEGER

+ */ + public static final String READ = "read"; + + /** + * The snippet of the latest message in the thread. + *

Type: TEXT

+ */ + public static final String SNIPPET = "snippet"; + /** + * The charset of the snippet. + *

Type: INTEGER

+ */ + public static final String SNIPPET_CHARSET = "snippet_cs"; + /** + * Type of the thread, either Threads.COMMON_THREAD or + * Threads.BROADCAST_THREAD. + *

Type: INTEGER

+ */ + public static final String TYPE = "type"; + /** + * Indicates whether there is a transmission error in the thread. + *

Type: INTEGER

+ */ + public static final String ERROR = "error"; + /** + * Indicates whether this thread contains any attachments. + *

Type: INTEGER

+ */ + public static final String HAS_ATTACHMENT = "has_attachment"; + } + + /** + * Helper functions for the "threads" table used by MMS and SMS. + */ + public static final class Threads implements ThreadsColumns { + private static final String[] ID_PROJECTION = { BaseColumns._ID }; + private static final String STANDARD_ENCODING = "UTF-8"; + private static final Uri THREAD_ID_CONTENT_URI = Uri.parse( + "content://mms-sms/threadID"); + public static final Uri CONTENT_URI = Uri.withAppendedPath( + MmsSms.CONTENT_URI, "conversations"); + public static final Uri OBSOLETE_THREADS_URI = Uri.withAppendedPath( + CONTENT_URI, "obsolete"); + + public static final int COMMON_THREAD = 0; + public static final int BROADCAST_THREAD = 1; + + // No one should construct an instance of this class. + private Threads() { + } + + /** + * This is a single-recipient version of + * getOrCreateThreadId. It's convenient for use with SMS + * messages. + */ + public static long getOrCreateThreadId(Context context, String recipient) { + Set recipients = new HashSet(); + + recipients.add(recipient); + return getOrCreateThreadId(context, recipients); + } + + /** + * Given the recipients list and subject of an unsaved message, + * return its thread ID. If the message starts a new thread, + * allocate a new thread ID. Otherwise, use the appropriate + * existing thread ID. + * + * Find the thread ID of the same set of recipients (in + * any order, without any additions). If one + * is found, return it. Otherwise, return a unique thread ID. + */ + public static long getOrCreateThreadId( + Context context, Set recipients) { + Uri.Builder uriBuilder = THREAD_ID_CONTENT_URI.buildUpon(); + + for (String recipient : recipients) { + if (Mms.isEmailAddress(recipient)) { + recipient = Mms.extractAddrSpec(recipient); + } + + uriBuilder.appendQueryParameter("recipient", recipient); + } + + Uri uri = uriBuilder.build(); + //if (DEBUG) Log.v(TAG, "getOrCreateThreadId uri: " + uri); + + Cursor cursor = SqliteWrapper.query(context, context.getContentResolver(), + uri, ID_PROJECTION, null, null, null); + if (cursor != null) { + try { + if (cursor.moveToFirst()) { + return cursor.getLong(0); + } else { + Log.e(TAG, "getOrCreateThreadId returned no rows!"); + } + } finally { + cursor.close(); + } + } + + Log.e(TAG, "getOrCreateThreadId failed with uri " + uri.toString()); + throw new IllegalArgumentException("Unable to find or allocate a thread ID."); + } + } + + /** + * Contains all MMS messages. + */ + public static final class Mms implements BaseMmsColumns { + /** + * The content:// style URL for this table + */ + public static final Uri CONTENT_URI = Uri.parse("content://mms"); + + public static final Uri REPORT_REQUEST_URI = Uri.withAppendedPath( + CONTENT_URI, "report-request"); + + public static final Uri REPORT_STATUS_URI = Uri.withAppendedPath( + CONTENT_URI, "report-status"); + + /** + * The default sort order for this table + */ + public static final String DEFAULT_SORT_ORDER = "date DESC"; + + /** + * mailbox = name-addr + * name-addr = [display-name] angle-addr + * angle-addr = [CFWS] "<" addr-spec ">" [CFWS] + */ + public static final Pattern NAME_ADDR_EMAIL_PATTERN = + Pattern.compile("\\s*(\"[^\"]*\"|[^<>\"]+)\\s*<([^<>]+)>\\s*"); + + /** + * quoted-string = [CFWS] + * DQUOTE *([FWS] qcontent) [FWS] DQUOTE + * [CFWS] + */ + public static final Pattern QUOTED_STRING_PATTERN = + Pattern.compile("\\s*\"([^\"]*)\"\\s*"); + + public static final Cursor query( + ContentResolver cr, String[] projection) { + return cr.query(CONTENT_URI, projection, null, null, DEFAULT_SORT_ORDER); + } + + public static final Cursor query( + ContentResolver cr, String[] projection, + String where, String orderBy) { + return cr.query(CONTENT_URI, projection, + where, null, orderBy == null ? DEFAULT_SORT_ORDER : orderBy); + } + + public static final String getMessageBoxName(int msgBox) { + switch (msgBox) { + case MESSAGE_BOX_ALL: + return "all"; + case MESSAGE_BOX_INBOX: + return "inbox"; + case MESSAGE_BOX_SENT: + return "sent"; + case MESSAGE_BOX_DRAFTS: + return "drafts"; + case MESSAGE_BOX_OUTBOX: + return "outbox"; + default: + throw new IllegalArgumentException("Invalid message box: " + msgBox); + } + } + + public static String extractAddrSpec(String address) { + Matcher match = NAME_ADDR_EMAIL_PATTERN.matcher(address); + + if (match.matches()) { + return match.group(2); + } + return address; + } + + /** + * Returns true if the address is an email address + * + * @param address the input address to be tested + * @return true if address is an email address + */ + public static boolean isEmailAddress(String address) { + if (TextUtils.isEmpty(address)) { + return false; + } + + String s = extractAddrSpec(address); + Matcher match = Patterns.EMAIL_ADDRESS.matcher(s); + return match.matches(); + } + + /** + * Returns true if the number is a Phone number + * + * @param number the input number to be tested + * @return true if number is a Phone number + */ + public static boolean isPhoneNumber(String number) { + if (TextUtils.isEmpty(number)) { + return false; + } + + Matcher match = Patterns.PHONE.matcher(number); + return match.matches(); + } + + /** + * Contains all MMS messages in the MMS app's inbox. + */ + public static final class Inbox implements BaseMmsColumns { + /** + * The content:// style URL for this table + */ + public static final Uri + CONTENT_URI = Uri.parse("content://mms/inbox"); + + /** + * The default sort order for this table + */ + public static final String DEFAULT_SORT_ORDER = "date DESC"; + } + + /** + * Contains all MMS messages in the MMS app's sent box. + */ + public static final class Sent implements BaseMmsColumns { + /** + * The content:// style URL for this table + */ + public static final Uri + CONTENT_URI = Uri.parse("content://mms/sent"); + + /** + * The default sort order for this table + */ + public static final String DEFAULT_SORT_ORDER = "date DESC"; + } + + /** + * Contains all MMS messages in the MMS app's drafts box. + */ + public static final class Draft implements BaseMmsColumns { + /** + * The content:// style URL for this table + */ + public static final Uri + CONTENT_URI = Uri.parse("content://mms/drafts"); + + /** + * The default sort order for this table + */ + public static final String DEFAULT_SORT_ORDER = "date DESC"; + } + + /** + * Contains all MMS messages in the MMS app's outbox. + */ + public static final class Outbox implements BaseMmsColumns { + /** + * The content:// style URL for this table + */ + public static final Uri + CONTENT_URI = Uri.parse("content://mms/outbox"); + + /** + * The default sort order for this table + */ + public static final String DEFAULT_SORT_ORDER = "date DESC"; + } + + public static final class Addr implements BaseColumns { + /** + * The ID of MM which this address entry belongs to. + */ + public static final String MSG_ID = "msg_id"; + + /** + * The ID of contact entry in Phone Book. + */ + public static final String CONTACT_ID = "contact_id"; + + /** + * The address text. + */ + public static final String ADDRESS = "address"; + + /** + * Type of address, must be one of PduHeaders.BCC, + * PduHeaders.CC, PduHeaders.FROM, PduHeaders.TO. + */ + public static final String TYPE = "type"; + + /** + * Character set of this entry. + */ + public static final String CHARSET = "charset"; + } + + public static final class Part implements BaseColumns { + /** + * The identifier of the message which this part belongs to. + *

Type: INTEGER

+ */ + public static final String MSG_ID = "mid"; + + /** + * The order of the part. + *

Type: INTEGER

+ */ + public static final String SEQ = "seq"; + + /** + * The content type of the part. + *

Type: TEXT

+ */ + public static final String CONTENT_TYPE = "ct"; + + /** + * The name of the part. + *

Type: TEXT

+ */ + public static final String NAME = "name"; + + /** + * The charset of the part. + *

Type: TEXT

+ */ + public static final String CHARSET = "chset"; + + /** + * The file name of the part. + *

Type: TEXT

+ */ + public static final String FILENAME = "fn"; + + /** + * The content disposition of the part. + *

Type: TEXT

+ */ + public static final String CONTENT_DISPOSITION = "cd"; + + /** + * The content ID of the part. + *

Type: INTEGER

+ */ + public static final String CONTENT_ID = "cid"; + + /** + * The content location of the part. + *

Type: INTEGER

+ */ + public static final String CONTENT_LOCATION = "cl"; + + /** + * The start of content-type of the message. + *

Type: INTEGER

+ */ + public static final String CT_START = "ctt_s"; + + /** + * The type of content-type of the message. + *

Type: TEXT

+ */ + public static final String CT_TYPE = "ctt_t"; + + /** + * The location(on filesystem) of the binary data of the part. + *

Type: INTEGER

+ */ + public static final String _DATA = "_data"; + + public static final String TEXT = "text"; + + } + + public static final class Rate { + public static final Uri CONTENT_URI = Uri.withAppendedPath( + Mms.CONTENT_URI, "rate"); + /** + * When a message was successfully sent. + *

Type: INTEGER

+ */ + public static final String SENT_TIME = "sent_time"; + } + + public static final class Intents { + private Intents() { + // Non-instantiatable. + } + + /** + * The extra field to store the contents of the Intent, + * which should be an array of Uri. + */ + public static final String EXTRA_CONTENTS = "contents"; + /** + * The extra field to store the type of the contents, + * which should be an array of String. + */ + public static final String EXTRA_TYPES = "types"; + /** + * The extra field to store the 'Cc' addresses. + */ + public static final String EXTRA_CC = "cc"; + /** + * The extra field to store the 'Bcc' addresses; + */ + public static final String EXTRA_BCC = "bcc"; + /** + * The extra field to store the 'Subject'. + */ + public static final String EXTRA_SUBJECT = "subject"; + /** + * Indicates that the contents of specified URIs were changed. + * The application which is showing or caching these contents + * should be updated. + */ + public static final String + CONTENT_CHANGED_ACTION = "android.intent.action.CONTENT_CHANGED"; + /** + * An extra field which stores the URI of deleted contents. + */ + public static final String DELETED_CONTENTS = "deleted_contents"; + } + } + + /** + * Contains all MMS and SMS messages. + */ + public static final class MmsSms implements BaseColumns { + /** + * The column to distinguish SMS & MMS messages in query results. + */ + public static final String TYPE_DISCRIMINATOR_COLUMN = + "transport_type"; + + public static final Uri CONTENT_URI = Uri.parse("content://mms-sms/"); + + public static final Uri CONTENT_CONVERSATIONS_URI = Uri.parse( + "content://mms-sms/conversations"); + + public static final Uri CONTENT_FILTER_BYPHONE_URI = Uri.parse( + "content://mms-sms/messages/byphone"); + + public static final Uri CONTENT_UNDELIVERED_URI = Uri.parse( + "content://mms-sms/undelivered"); + + public static final Uri CONTENT_DRAFT_URI = Uri.parse( + "content://mms-sms/draft"); + + public static final Uri CONTENT_LOCKED_URI = Uri.parse( + "content://mms-sms/locked"); + + /*** + * Pass in a query parameter called "pattern" which is the text + * to search for. + * The sort order is fixed to be thread_id ASC,date DESC. + */ + public static final Uri SEARCH_URI = Uri.parse( + "content://mms-sms/search"); + + // Constants for message protocol types. + public static final int SMS_PROTO = 0; + public static final int MMS_PROTO = 1; + + // Constants for error types of pending messages. + public static final int NO_ERROR = 0; + public static final int ERR_TYPE_GENERIC = 1; + public static final int ERR_TYPE_SMS_PROTO_TRANSIENT = 2; + public static final int ERR_TYPE_MMS_PROTO_TRANSIENT = 3; + public static final int ERR_TYPE_TRANSPORT_FAILURE = 4; + public static final int ERR_TYPE_GENERIC_PERMANENT = 10; + public static final int ERR_TYPE_SMS_PROTO_PERMANENT = 11; + public static final int ERR_TYPE_MMS_PROTO_PERMANENT = 12; + + public static final class PendingMessages implements BaseColumns { + public static final Uri CONTENT_URI = Uri.withAppendedPath( + MmsSms.CONTENT_URI, "pending"); + /** + * The type of transport protocol(MMS or SMS). + *

Type: INTEGER

+ */ + public static final String PROTO_TYPE = "proto_type"; + /** + * The ID of the message to be sent or downloaded. + *

Type: INTEGER

+ */ + public static final String MSG_ID = "msg_id"; + /** + * The type of the message to be sent or downloaded. + * This field is only valid for MM. For SM, its value is always + * set to 0. + */ + public static final String MSG_TYPE = "msg_type"; + /** + * The type of the error code. + *

Type: INTEGER

+ */ + public static final String ERROR_TYPE = "err_type"; + /** + * The error code of sending/retrieving process. + *

Type: INTEGER

+ */ + public static final String ERROR_CODE = "err_code"; + /** + * How many times we tried to send or download the message. + *

Type: INTEGER

+ */ + public static final String RETRY_INDEX = "retry_index"; + /** + * The time to do next retry. + */ + public static final String DUE_TIME = "due_time"; + /** + * The time we last tried to send or download the message. + */ + public static final String LAST_TRY = "last_try"; + } + + public static final class WordsTable { + public static final String ID = "_id"; + public static final String SOURCE_ROW_ID = "source_id"; + public static final String TABLE_ID = "table_to_use"; + public static final String INDEXED_TEXT = "index_text"; + } + } + + public static final class Carriers implements BaseColumns { + /** + * The content:// style URL for this table + */ + public static final Uri CONTENT_URI = + Uri.parse("content://telephony/carriers"); + + /** + * The default sort order for this table + */ + public static final String DEFAULT_SORT_ORDER = "name ASC"; + + public static final String NAME = "name"; + + public static final String APN = "apn"; + + public static final String PROXY = "proxy"; + + public static final String PORT = "port"; + + public static final String MMSPROXY = "mmsproxy"; + + public static final String MMSPORT = "mmsport"; + + public static final String SERVER = "server"; + + public static final String USER = "user"; + + public static final String PASSWORD = "password"; + + public static final String MMSC = "mmsc"; + + public static final String MCC = "mcc"; + + public static final String MNC = "mnc"; + + public static final String NUMERIC = "numeric"; + + public static final String AUTH_TYPE = "authtype"; + + public static final String TYPE = "type"; + + public static final String INACTIVE_TIMER = "inactivetimer"; + + // Only if enabled try Data Connection. + public static final String ENABLED = "enabled"; + + // Rules apply based on class. + public static final String CLASS = "class"; + + /** + * The protocol to be used to connect to this APN. + * + * One of the PDP_type values in TS 27.007 section 10.1.1. + * For example, "IP", "IPV6", "IPV4V6", or "PPP". + */ + public static final String PROTOCOL = "protocol"; + + /** + * The protocol to be used to connect to this APN when roaming. + * + * The syntax is the same as protocol. + */ + public static final String ROAMING_PROTOCOL = "roaming_protocol"; + + public static final String CURRENT = "current"; + + /** + * Current status of APN + * true : enabled APN, false : disabled APN. + */ + public static final String CARRIER_ENABLED = "carrier_enabled"; + + /** + * Radio Access Technology info + * To check what values can hold, refer to ServiceState.java. + * This should be spread to other technologies, + * but currently only used for LTE(14) and EHRPD(13). + */ + public static final String BEARER = "bearer"; + } + + /** + * Contains received SMS cell broadcast messages. + */ + public static final class CellBroadcasts implements BaseColumns { + + /** Not instantiable. */ + private CellBroadcasts() {} + + /** + * The content:// style URL for this table + */ + public static final Uri CONTENT_URI = + Uri.parse("content://cellbroadcasts"); + + /** + * Message geographical scope. + *

Type: INTEGER

+ */ + public static final String GEOGRAPHICAL_SCOPE = "geo_scope"; + + /** + * Message serial number. + *

Type: INTEGER

+ */ + public static final String SERIAL_NUMBER = "serial_number"; + + /** + * PLMN of broadcast sender. (SERIAL_NUMBER + PLMN + LAC + CID) uniquely identifies a + * broadcast for duplicate detection purposes. + *

Type: TEXT

+ */ + public static final String PLMN = "plmn"; + + /** + * Location Area (GSM) or Service Area (UMTS) of broadcast sender. Unused for CDMA. + * Only included if Geographical Scope of message is not PLMN wide (01). + *

Type: INTEGER

+ */ + public static final String LAC = "lac"; + + /** + * Cell ID of message sender (GSM/UMTS). Unused for CDMA. Only included when the + * Geographical Scope of message is cell wide (00 or 11). + *

Type: INTEGER

+ */ + public static final String CID = "cid"; + + /** + * Message code (OBSOLETE: merged into SERIAL_NUMBER). + *

Type: INTEGER

+ */ + public static final String V1_MESSAGE_CODE = "message_code"; + + /** + * Message identifier (OBSOLETE: renamed to SERVICE_CATEGORY). + *

Type: INTEGER

+ */ + public static final String V1_MESSAGE_IDENTIFIER = "message_id"; + + /** + * Service category (GSM/UMTS message identifier, CDMA service category). + *

Type: INTEGER

+ */ + public static final String SERVICE_CATEGORY = "service_category"; + + /** + * Message language code. + *

Type: TEXT

+ */ + public static final String LANGUAGE_CODE = "language"; + + /** + * Message body. + *

Type: TEXT

+ */ + public static final String MESSAGE_BODY = "body"; + + /** + * Message delivery time. + *

Type: INTEGER (long)

+ */ + public static final String DELIVERY_TIME = "date"; + + /** + * Has the message been viewed? + *

Type: INTEGER (boolean)

+ */ + public static final String MESSAGE_READ = "read"; + + /** + * Message format (3GPP or 3GPP2). + *

Type: INTEGER

+ */ + public static final String MESSAGE_FORMAT = "format"; + + /** + * Message priority (including emergency). + *

Type: INTEGER

+ */ + public static final String MESSAGE_PRIORITY = "priority"; + + /** + * ETWS warning type (ETWS alerts only). + *

Type: INTEGER

+ */ + public static final String ETWS_WARNING_TYPE = "etws_warning_type"; + + /** + * CMAS message class (CMAS alerts only). + *

Type: INTEGER

+ */ + public static final String CMAS_MESSAGE_CLASS = "cmas_message_class"; + + /** + * CMAS category (CMAS alerts only). + *

Type: INTEGER

+ */ + public static final String CMAS_CATEGORY = "cmas_category"; + + /** + * CMAS response type (CMAS alerts only). + *

Type: INTEGER

+ */ + public static final String CMAS_RESPONSE_TYPE = "cmas_response_type"; + + /** + * CMAS severity (CMAS alerts only). + *

Type: INTEGER

+ */ + public static final String CMAS_SEVERITY = "cmas_severity"; + + /** + * CMAS urgency (CMAS alerts only). + *

Type: INTEGER

+ */ + public static final String CMAS_URGENCY = "cmas_urgency"; + + /** + * CMAS certainty (CMAS alerts only). + *

Type: INTEGER

+ */ + public static final String CMAS_CERTAINTY = "cmas_certainty"; + + /** + * The default sort order for this table + */ + public static final String DEFAULT_SORT_ORDER = DELIVERY_TIME + " DESC"; + + /** + * Query columns for instantiating {@link android.telephony.CellBroadcastMessage} objects. + */ + public static final String[] QUERY_COLUMNS = { + _ID, + GEOGRAPHICAL_SCOPE, + PLMN, + LAC, + CID, + SERIAL_NUMBER, + SERVICE_CATEGORY, + LANGUAGE_CODE, + MESSAGE_BODY, + DELIVERY_TIME, + MESSAGE_READ, + MESSAGE_FORMAT, + MESSAGE_PRIORITY, + ETWS_WARNING_TYPE, + CMAS_MESSAGE_CLASS, + CMAS_CATEGORY, + CMAS_RESPONSE_TYPE, + CMAS_SEVERITY, + CMAS_URGENCY, + CMAS_CERTAINTY + }; + } +} diff --git a/src/java/android/telephony/CellBroadcastMessage.java b/src/java/android/telephony/CellBroadcastMessage.java new file mode 100644 index 0000000..36c238d --- /dev/null +++ b/src/java/android/telephony/CellBroadcastMessage.java @@ -0,0 +1,422 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package android.telephony; + +import android.content.ContentValues; +import android.content.Context; +import android.database.Cursor; +import android.graphics.Typeface; +import android.os.Parcel; +import android.os.Parcelable; +import android.provider.Telephony; +import android.telephony.SmsCbCmasInfo; +import android.telephony.SmsCbEtwsInfo; +import android.telephony.SmsCbLocation; +import android.telephony.SmsCbMessage; +import android.text.Spannable; +import android.text.SpannableStringBuilder; +import android.text.format.DateUtils; +import android.text.style.StyleSpan; + +/** + * Application wrapper for {@link SmsCbMessage}. This is Parcelable so that + * decoded broadcast message objects can be passed between running Services. + * New broadcasts are received by the CellBroadcastReceiver app, which exports + * the database of previously received broadcasts at "content://cellbroadcasts/". + * The "android.permission.READ_CELL_BROADCASTS" permission is required to read + * from the ContentProvider, and writes to the database are not allowed.

+ * + * Use {@link #createFromCursor} to create CellBroadcastMessage objects from rows + * in the database cursor returned by the ContentProvider. + * + * {@hide} + */ +public class CellBroadcastMessage implements Parcelable { + + /** Identifier for getExtra() when adding this object to an Intent. */ + public static final String SMS_CB_MESSAGE_EXTRA = + "com.android.cellbroadcastreceiver.SMS_CB_MESSAGE"; + + /** SmsCbMessage. */ + private final SmsCbMessage mSmsCbMessage; + + private final long mDeliveryTime; + private boolean mIsRead; + + public CellBroadcastMessage(SmsCbMessage message) { + mSmsCbMessage = message; + mDeliveryTime = System.currentTimeMillis(); + mIsRead = false; + } + + private CellBroadcastMessage(SmsCbMessage message, long deliveryTime, boolean isRead) { + mSmsCbMessage = message; + mDeliveryTime = deliveryTime; + mIsRead = isRead; + } + + private CellBroadcastMessage(Parcel in) { + mSmsCbMessage = new SmsCbMessage(in); + mDeliveryTime = in.readLong(); + mIsRead = (in.readInt() != 0); + } + + /** Parcelable: no special flags. */ + public int describeContents() { + return 0; + } + + public void writeToParcel(Parcel out, int flags) { + mSmsCbMessage.writeToParcel(out, flags); + out.writeLong(mDeliveryTime); + out.writeInt(mIsRead ? 1 : 0); + } + + public static final Parcelable.Creator CREATOR + = new Parcelable.Creator() { + public CellBroadcastMessage createFromParcel(Parcel in) { + return new CellBroadcastMessage(in); + } + + public CellBroadcastMessage[] newArray(int size) { + return new CellBroadcastMessage[size]; + } + }; + + /** + * Create a CellBroadcastMessage from a row in the database. + * @param cursor an open SQLite cursor pointing to the row to read + * @return the new CellBroadcastMessage + * @throws IllegalArgumentException if one of the required columns is missing + */ + public static CellBroadcastMessage createFromCursor(Cursor cursor) { + int geoScope = cursor.getInt( + cursor.getColumnIndexOrThrow(Telephony.CellBroadcasts.GEOGRAPHICAL_SCOPE)); + int serialNum = cursor.getInt( + cursor.getColumnIndexOrThrow(Telephony.CellBroadcasts.SERIAL_NUMBER)); + int category = cursor.getInt( + cursor.getColumnIndexOrThrow(Telephony.CellBroadcasts.SERVICE_CATEGORY)); + String language = cursor.getString( + cursor.getColumnIndexOrThrow(Telephony.CellBroadcasts.LANGUAGE_CODE)); + String body = cursor.getString( + cursor.getColumnIndexOrThrow(Telephony.CellBroadcasts.MESSAGE_BODY)); + int format = cursor.getInt( + cursor.getColumnIndexOrThrow(Telephony.CellBroadcasts.MESSAGE_FORMAT)); + int priority = cursor.getInt( + cursor.getColumnIndexOrThrow(Telephony.CellBroadcasts.MESSAGE_PRIORITY)); + + String plmn; + int plmnColumn = cursor.getColumnIndex(Telephony.CellBroadcasts.PLMN); + if (plmnColumn != -1 && !cursor.isNull(plmnColumn)) { + plmn = cursor.getString(plmnColumn); + } else { + plmn = null; + } + + int lac; + int lacColumn = cursor.getColumnIndex(Telephony.CellBroadcasts.LAC); + if (lacColumn != -1 && !cursor.isNull(lacColumn)) { + lac = cursor.getInt(lacColumn); + } else { + lac = -1; + } + + int cid; + int cidColumn = cursor.getColumnIndex(Telephony.CellBroadcasts.CID); + if (cidColumn != -1 && !cursor.isNull(cidColumn)) { + cid = cursor.getInt(cidColumn); + } else { + cid = -1; + } + + SmsCbLocation location = new SmsCbLocation(plmn, lac, cid); + + SmsCbEtwsInfo etwsInfo; + int etwsWarningTypeColumn = cursor.getColumnIndex( + Telephony.CellBroadcasts.ETWS_WARNING_TYPE); + if (etwsWarningTypeColumn != -1 && !cursor.isNull(etwsWarningTypeColumn)) { + int warningType = cursor.getInt(etwsWarningTypeColumn); + etwsInfo = new SmsCbEtwsInfo(warningType, false, false, null); + } else { + etwsInfo = null; + } + + SmsCbCmasInfo cmasInfo; + int cmasMessageClassColumn = cursor.getColumnIndex( + Telephony.CellBroadcasts.CMAS_MESSAGE_CLASS); + if (cmasMessageClassColumn != -1 && !cursor.isNull(cmasMessageClassColumn)) { + int messageClass = cursor.getInt(cmasMessageClassColumn); + + int cmasCategory; + int cmasCategoryColumn = cursor.getColumnIndex( + Telephony.CellBroadcasts.CMAS_CATEGORY); + if (cmasCategoryColumn != -1 && !cursor.isNull(cmasCategoryColumn)) { + cmasCategory = cursor.getInt(cmasCategoryColumn); + } else { + cmasCategory = SmsCbCmasInfo.CMAS_CATEGORY_UNKNOWN; + } + + int responseType; + int cmasResponseTypeColumn = cursor.getColumnIndex( + Telephony.CellBroadcasts.CMAS_RESPONSE_TYPE); + if (cmasResponseTypeColumn != -1 && !cursor.isNull(cmasResponseTypeColumn)) { + responseType = cursor.getInt(cmasResponseTypeColumn); + } else { + responseType = SmsCbCmasInfo.CMAS_RESPONSE_TYPE_UNKNOWN; + } + + int severity; + int cmasSeverityColumn = cursor.getColumnIndex( + Telephony.CellBroadcasts.CMAS_SEVERITY); + if (cmasSeverityColumn != -1 && !cursor.isNull(cmasSeverityColumn)) { + severity = cursor.getInt(cmasSeverityColumn); + } else { + severity = SmsCbCmasInfo.CMAS_SEVERITY_UNKNOWN; + } + + int urgency; + int cmasUrgencyColumn = cursor.getColumnIndex( + Telephony.CellBroadcasts.CMAS_URGENCY); + if (cmasUrgencyColumn != -1 && !cursor.isNull(cmasUrgencyColumn)) { + urgency = cursor.getInt(cmasUrgencyColumn); + } else { + urgency = SmsCbCmasInfo.CMAS_URGENCY_UNKNOWN; + } + + int certainty; + int cmasCertaintyColumn = cursor.getColumnIndex( + Telephony.CellBroadcasts.CMAS_CERTAINTY); + if (cmasCertaintyColumn != -1 && !cursor.isNull(cmasCertaintyColumn)) { + certainty = cursor.getInt(cmasCertaintyColumn); + } else { + certainty = SmsCbCmasInfo.CMAS_CERTAINTY_UNKNOWN; + } + + cmasInfo = new SmsCbCmasInfo(messageClass, cmasCategory, responseType, severity, + urgency, certainty); + } else { + cmasInfo = null; + } + + SmsCbMessage msg = new SmsCbMessage(format, geoScope, serialNum, location, category, + language, body, priority, etwsInfo, cmasInfo); + + long deliveryTime = cursor.getLong(cursor.getColumnIndexOrThrow( + Telephony.CellBroadcasts.DELIVERY_TIME)); + boolean isRead = (cursor.getInt(cursor.getColumnIndexOrThrow( + Telephony.CellBroadcasts.MESSAGE_READ)) != 0); + + return new CellBroadcastMessage(msg, deliveryTime, isRead); + } + + /** + * Return a ContentValues object for insertion into the database. + * @return a new ContentValues object containing this object's data + */ + public ContentValues getContentValues() { + ContentValues cv = new ContentValues(16); + SmsCbMessage msg = mSmsCbMessage; + cv.put(Telephony.CellBroadcasts.GEOGRAPHICAL_SCOPE, msg.getGeographicalScope()); + SmsCbLocation location = msg.getLocation(); + if (location.getPlmn() != null) { + cv.put(Telephony.CellBroadcasts.PLMN, location.getPlmn()); + } + if (location.getLac() != -1) { + cv.put(Telephony.CellBroadcasts.LAC, location.getLac()); + } + if (location.getCid() != -1) { + cv.put(Telephony.CellBroadcasts.CID, location.getCid()); + } + cv.put(Telephony.CellBroadcasts.SERIAL_NUMBER, msg.getSerialNumber()); + cv.put(Telephony.CellBroadcasts.SERVICE_CATEGORY, msg.getServiceCategory()); + cv.put(Telephony.CellBroadcasts.LANGUAGE_CODE, msg.getLanguageCode()); + cv.put(Telephony.CellBroadcasts.MESSAGE_BODY, msg.getMessageBody()); + cv.put(Telephony.CellBroadcasts.DELIVERY_TIME, mDeliveryTime); + cv.put(Telephony.CellBroadcasts.MESSAGE_READ, mIsRead); + cv.put(Telephony.CellBroadcasts.MESSAGE_FORMAT, msg.getMessageFormat()); + cv.put(Telephony.CellBroadcasts.MESSAGE_PRIORITY, msg.getMessagePriority()); + + SmsCbEtwsInfo etwsInfo = mSmsCbMessage.getEtwsWarningInfo(); + if (etwsInfo != null) { + cv.put(Telephony.CellBroadcasts.ETWS_WARNING_TYPE, etwsInfo.getWarningType()); + } + + SmsCbCmasInfo cmasInfo = mSmsCbMessage.getCmasWarningInfo(); + if (cmasInfo != null) { + cv.put(Telephony.CellBroadcasts.CMAS_MESSAGE_CLASS, cmasInfo.getMessageClass()); + cv.put(Telephony.CellBroadcasts.CMAS_CATEGORY, cmasInfo.getCategory()); + cv.put(Telephony.CellBroadcasts.CMAS_RESPONSE_TYPE, cmasInfo.getResponseType()); + cv.put(Telephony.CellBroadcasts.CMAS_SEVERITY, cmasInfo.getSeverity()); + cv.put(Telephony.CellBroadcasts.CMAS_URGENCY, cmasInfo.getUrgency()); + cv.put(Telephony.CellBroadcasts.CMAS_CERTAINTY, cmasInfo.getCertainty()); + } + + return cv; + } + + /** + * Set or clear the "read message" flag. + * @param isRead true if the message has been read; false if not + */ + public void setIsRead(boolean isRead) { + mIsRead = isRead; + } + + public String getLanguageCode() { + return mSmsCbMessage.getLanguageCode(); + } + + public int getServiceCategory() { + return mSmsCbMessage.getServiceCategory(); + } + + public long getDeliveryTime() { + return mDeliveryTime; + } + + public String getMessageBody() { + return mSmsCbMessage.getMessageBody(); + } + + public boolean isRead() { + return mIsRead; + } + + public int getSerialNumber() { + return mSmsCbMessage.getSerialNumber(); + } + + public SmsCbCmasInfo getCmasWarningInfo() { + return mSmsCbMessage.getCmasWarningInfo(); + } + + public SmsCbEtwsInfo getEtwsWarningInfo() { + return mSmsCbMessage.getEtwsWarningInfo(); + } + + /** + * Return whether the broadcast is an emergency (PWS) message type. + * This includes lower priority test messages and Amber alerts. + * + * All public alerts show the flashing warning icon in the dialog, + * but only emergency alerts play the alert sound and speak the message. + * + * @return true if the message is PWS type; false otherwise + */ + public boolean isPublicAlertMessage() { + return mSmsCbMessage.isEmergencyMessage(); + } + + /** + * Returns whether the broadcast is an emergency (PWS) message type, + * including test messages, but excluding lower priority Amber alert broadcasts. + * + * @return true if the message is PWS type, excluding Amber alerts + */ + public boolean isEmergencyAlertMessage() { + if (!mSmsCbMessage.isEmergencyMessage()) { + return false; + } + SmsCbCmasInfo cmasInfo = mSmsCbMessage.getCmasWarningInfo(); + if (cmasInfo != null && + cmasInfo.getMessageClass() == SmsCbCmasInfo.CMAS_CLASS_CHILD_ABDUCTION_EMERGENCY) { + return false; + } + return true; + } + + /** + * Return whether the broadcast is an ETWS emergency message type. + * @return true if the message is ETWS emergency type; false otherwise + */ + public boolean isEtwsMessage() { + return mSmsCbMessage.isEtwsMessage(); + } + + /** + * Return whether the broadcast is a CMAS emergency message type. + * @return true if the message is CMAS emergency type; false otherwise + */ + public boolean isCmasMessage() { + return mSmsCbMessage.isCmasMessage(); + } + + /** + * Return the CMAS message class. + * @return the CMAS message class, e.g. {@link SmsCbCmasInfo#CMAS_CLASS_SEVERE_THREAT}, or + * {@link SmsCbCmasInfo#CMAS_CLASS_UNKNOWN} if this is not a CMAS alert + */ + public int getCmasMessageClass() { + if (mSmsCbMessage.isCmasMessage()) { + return mSmsCbMessage.getCmasWarningInfo().getMessageClass(); + } else { + return SmsCbCmasInfo.CMAS_CLASS_UNKNOWN; + } + } + + /** + * Return whether the broadcast is an ETWS popup alert. + * This method checks the message ID and the message code. + * @return true if the message indicates an ETWS popup alert + */ + public boolean isEtwsPopupAlert() { + SmsCbEtwsInfo etwsInfo = mSmsCbMessage.getEtwsWarningInfo(); + return etwsInfo != null && etwsInfo.isPopupAlert(); + } + + /** + * Return whether the broadcast is an ETWS emergency user alert. + * This method checks the message ID and the message code. + * @return true if the message indicates an ETWS emergency user alert + */ + public boolean isEtwsEmergencyUserAlert() { + SmsCbEtwsInfo etwsInfo = mSmsCbMessage.getEtwsWarningInfo(); + return etwsInfo != null && etwsInfo.isEmergencyUserAlert(); + } + + /** + * Return whether the broadcast is an ETWS test message. + * @return true if the message is an ETWS test message; false otherwise + */ + public boolean isEtwsTestMessage() { + SmsCbEtwsInfo etwsInfo = mSmsCbMessage.getEtwsWarningInfo(); + return etwsInfo != null && + etwsInfo.getWarningType() == SmsCbEtwsInfo.ETWS_WARNING_TYPE_TEST_MESSAGE; + } + + /** + * Return the abbreviated date string for the message delivery time. + * @param context the context object + * @return a String to use in the broadcast list UI + */ + public String getDateString(Context context) { + int flags = DateUtils.FORMAT_NO_NOON_MIDNIGHT | DateUtils.FORMAT_SHOW_TIME | + DateUtils.FORMAT_ABBREV_ALL | DateUtils.FORMAT_SHOW_DATE | + DateUtils.FORMAT_CAP_AMPM; + return DateUtils.formatDateTime(context, mDeliveryTime, flags); + } + + /** + * Return the date string for the message delivery time, suitable for text-to-speech. + * @param context the context object + * @return a String for populating the list item AccessibilityEvent for TTS + */ + public String getSpokenDateString(Context context) { + int flags = DateUtils.FORMAT_SHOW_TIME | DateUtils.FORMAT_SHOW_DATE; + return DateUtils.formatDateTime(context, mDeliveryTime, flags); + } +} diff --git a/src/java/android/telephony/SmsCbCmasInfo.java b/src/java/android/telephony/SmsCbCmasInfo.java new file mode 100644 index 0000000..7a89d94 --- /dev/null +++ b/src/java/android/telephony/SmsCbCmasInfo.java @@ -0,0 +1,308 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.telephony; + +import android.os.Parcel; +import android.os.Parcelable; + +/** + * Contains CMAS warning notification Type 1 elements for a {@link SmsCbMessage}. + * Supported values for each element are defined in TIA-1149-0-1 (CMAS over CDMA) and + * 3GPP TS 23.041 (for GSM/UMTS). + * + * {@hide} + */ +public class SmsCbCmasInfo implements Parcelable { + + // CMAS message class (in GSM/UMTS message identifier or CDMA service category). + + /** Presidential-level alert (Korean Public Alert System Class 0 message). */ + public static final int CMAS_CLASS_PRESIDENTIAL_LEVEL_ALERT = 0x00; + + /** Extreme threat to life and property (Korean Public Alert System Class 1 message). */ + public static final int CMAS_CLASS_EXTREME_THREAT = 0x01; + + /** Severe threat to life and property (Korean Public Alert System Class 1 message). */ + public static final int CMAS_CLASS_SEVERE_THREAT = 0x02; + + /** Child abduction emergency (AMBER Alert). */ + public static final int CMAS_CLASS_CHILD_ABDUCTION_EMERGENCY = 0x03; + + /** CMAS test message. */ + public static final int CMAS_CLASS_REQUIRED_MONTHLY_TEST = 0x04; + + /** CMAS exercise. */ + public static final int CMAS_CLASS_CMAS_EXERCISE = 0x05; + + /** CMAS category for operator defined use. */ + public static final int CMAS_CLASS_OPERATOR_DEFINED_USE = 0x06; + + /** CMAS category for warning types that are reserved for future extension. */ + public static final int CMAS_CLASS_UNKNOWN = -1; + + // CMAS alert category (in CDMA type 1 elements record). + + /** CMAS alert category: Geophysical including landslide. */ + public static final int CMAS_CATEGORY_GEO = 0x00; + + /** CMAS alert category: Meteorological including flood. */ + public static final int CMAS_CATEGORY_MET = 0x01; + + /** CMAS alert category: General emergency and public safety. */ + public static final int CMAS_CATEGORY_SAFETY = 0x02; + + /** CMAS alert category: Law enforcement, military, homeland/local/private security. */ + public static final int CMAS_CATEGORY_SECURITY = 0x03; + + /** CMAS alert category: Rescue and recovery. */ + public static final int CMAS_CATEGORY_RESCUE = 0x04; + + /** CMAS alert category: Fire suppression and rescue. */ + public static final int CMAS_CATEGORY_FIRE = 0x05; + + /** CMAS alert category: Medical and public health. */ + public static final int CMAS_CATEGORY_HEALTH = 0x06; + + /** CMAS alert category: Pollution and other environmental. */ + public static final int CMAS_CATEGORY_ENV = 0x07; + + /** CMAS alert category: Public and private transportation. */ + public static final int CMAS_CATEGORY_TRANSPORT = 0x08; + + /** CMAS alert category: Utility, telecom, other non-transport infrastructure. */ + public static final int CMAS_CATEGORY_INFRA = 0x09; + + /** CMAS alert category: Chem, bio, radiological, nuclear, high explosive threat or attack. */ + public static final int CMAS_CATEGORY_CBRNE = 0x0a; + + /** CMAS alert category: Other events. */ + public static final int CMAS_CATEGORY_OTHER = 0x0b; + + /** + * CMAS alert category is unknown. The category is only available for CDMA broadcasts + * containing a type 1 elements record, so GSM and UMTS broadcasts always return unknown. + */ + public static final int CMAS_CATEGORY_UNKNOWN = -1; + + // CMAS response type (in CDMA type 1 elements record). + + /** CMAS response type: Take shelter in place. */ + public static final int CMAS_RESPONSE_TYPE_SHELTER = 0x00; + + /** CMAS response type: Evacuate (Relocate). */ + public static final int CMAS_RESPONSE_TYPE_EVACUATE = 0x01; + + /** CMAS response type: Make preparations. */ + public static final int CMAS_RESPONSE_TYPE_PREPARE = 0x02; + + /** CMAS response type: Execute a pre-planned activity. */ + public static final int CMAS_RESPONSE_TYPE_EXECUTE = 0x03; + + /** CMAS response type: Attend to information sources. */ + public static final int CMAS_RESPONSE_TYPE_MONITOR = 0x04; + + /** CMAS response type: Avoid hazard. */ + public static final int CMAS_RESPONSE_TYPE_AVOID = 0x05; + + /** CMAS response type: Evaluate the information in this message (not for public warnings). */ + public static final int CMAS_RESPONSE_TYPE_ASSESS = 0x06; + + /** CMAS response type: No action recommended. */ + public static final int CMAS_RESPONSE_TYPE_NONE = 0x07; + + /** + * CMAS response type is unknown. The response type is only available for CDMA broadcasts + * containing a type 1 elements record, so GSM and UMTS broadcasts always return unknown. + */ + public static final int CMAS_RESPONSE_TYPE_UNKNOWN = -1; + + // 4-bit CMAS severity (in GSM/UMTS message identifier or CDMA type 1 elements record). + + /** CMAS severity type: Extraordinary threat to life or property. */ + public static final int CMAS_SEVERITY_EXTREME = 0x0; + + /** CMAS severity type: Significant threat to life or property. */ + public static final int CMAS_SEVERITY_SEVERE = 0x1; + + /** + * CMAS alert severity is unknown. The severity is available for CDMA warning alerts + * containing a type 1 elements record and for all GSM and UMTS alerts except for the + * Presidential-level alert class (Korean Public Alert System Class 0). + */ + public static final int CMAS_SEVERITY_UNKNOWN = -1; + + // CMAS urgency (in GSM/UMTS message identifier or CDMA type 1 elements record). + + /** CMAS urgency type: Responsive action should be taken immediately. */ + public static final int CMAS_URGENCY_IMMEDIATE = 0x0; + + /** CMAS urgency type: Responsive action should be taken within the next hour. */ + public static final int CMAS_URGENCY_EXPECTED = 0x1; + + /** + * CMAS alert urgency is unknown. The urgency is available for CDMA warning alerts + * containing a type 1 elements record and for all GSM and UMTS alerts except for the + * Presidential-level alert class (Korean Public Alert System Class 0). + */ + public static final int CMAS_URGENCY_UNKNOWN = -1; + + // CMAS certainty (in GSM/UMTS message identifier or CDMA type 1 elements record). + + /** CMAS certainty type: Determined to have occurred or to be ongoing. */ + public static final int CMAS_CERTAINTY_OBSERVED = 0x0; + + /** CMAS certainty type: Likely (probability > ~50%). */ + public static final int CMAS_CERTAINTY_LIKELY = 0x1; + + /** + * CMAS alert certainty is unknown. The certainty is available for CDMA warning alerts + * containing a type 1 elements record and for all GSM and UMTS alerts except for the + * Presidential-level alert class (Korean Public Alert System Class 0). + */ + public static final int CMAS_CERTAINTY_UNKNOWN = -1; + + /** CMAS message class. */ + private final int mMessageClass; + + /** CMAS category. */ + private final int mCategory; + + /** CMAS response type. */ + private final int mResponseType; + + /** CMAS severity. */ + private final int mSeverity; + + /** CMAS urgency. */ + private final int mUrgency; + + /** CMAS certainty. */ + private final int mCertainty; + + /** Create a new SmsCbCmasInfo object with the specified values. */ + public SmsCbCmasInfo(int messageClass, int category, int responseType, int severity, + int urgency, int certainty) { + mMessageClass = messageClass; + mCategory = category; + mResponseType = responseType; + mSeverity = severity; + mUrgency = urgency; + mCertainty = certainty; + } + + /** Create a new SmsCbCmasInfo object from a Parcel. */ + SmsCbCmasInfo(Parcel in) { + mMessageClass = in.readInt(); + mCategory = in.readInt(); + mResponseType = in.readInt(); + mSeverity = in.readInt(); + mUrgency = in.readInt(); + mCertainty = in.readInt(); + } + + /** + * Flatten this object into a Parcel. + * + * @param dest The Parcel in which the object should be written. + * @param flags Additional flags about how the object should be written (ignored). + */ + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(mMessageClass); + dest.writeInt(mCategory); + dest.writeInt(mResponseType); + dest.writeInt(mSeverity); + dest.writeInt(mUrgency); + dest.writeInt(mCertainty); + } + + /** + * Returns the CMAS message class, e.g. {@link #CMAS_CLASS_PRESIDENTIAL_LEVEL_ALERT}. + * @return one of the {@code CMAS_CLASS} values + */ + public int getMessageClass() { + return mMessageClass; + } + + /** + * Returns the CMAS category, e.g. {@link #CMAS_CATEGORY_GEO}. + * @return one of the {@code CMAS_CATEGORY} values + */ + public int getCategory() { + return mCategory; + } + + /** + * Returns the CMAS response type, e.g. {@link #CMAS_RESPONSE_TYPE_SHELTER}. + * @return one of the {@code CMAS_RESPONSE_TYPE} values + */ + public int getResponseType() { + return mResponseType; + } + + /** + * Returns the CMAS severity, e.g. {@link #CMAS_SEVERITY_EXTREME}. + * @return one of the {@code CMAS_SEVERITY} values + */ + public int getSeverity() { + return mSeverity; + } + + /** + * Returns the CMAS urgency, e.g. {@link #CMAS_URGENCY_IMMEDIATE}. + * @return one of the {@code CMAS_URGENCY} values + */ + public int getUrgency() { + return mUrgency; + } + + /** + * Returns the CMAS certainty, e.g. {@link #CMAS_CERTAINTY_OBSERVED}. + * @return one of the {@code CMAS_CERTAINTY} values + */ + public int getCertainty() { + return mCertainty; + } + + @Override + public String toString() { + return "SmsCbCmasInfo{messageClass=" + mMessageClass + ", category=" + mCategory + + ", responseType=" + mResponseType + ", severity=" + mSeverity + + ", urgency=" + mUrgency + ", certainty=" + mCertainty + '}'; + } + + /** + * Describe the kinds of special objects contained in the marshalled representation. + * @return a bitmask indicating this Parcelable contains no special objects + */ + @Override + public int describeContents() { + return 0; + } + + /** Creator for unparcelling objects. */ + public static final Parcelable.Creator + CREATOR = new Parcelable.Creator() { + public SmsCbCmasInfo createFromParcel(Parcel in) { + return new SmsCbCmasInfo(in); + } + + public SmsCbCmasInfo[] newArray(int size) { + return new SmsCbCmasInfo[size]; + } + }; +} diff --git a/src/java/android/telephony/SmsCbEtwsInfo.java b/src/java/android/telephony/SmsCbEtwsInfo.java new file mode 100644 index 0000000..0890d52 --- /dev/null +++ b/src/java/android/telephony/SmsCbEtwsInfo.java @@ -0,0 +1,206 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.telephony; + +import android.os.Parcel; +import android.os.Parcelable; +import android.text.format.Time; + +import com.android.internal.telephony.IccUtils; + +import java.util.Arrays; + +/** + * Contains information elements for a GSM or UMTS ETWS warning notification. + * Supported values for each element are defined in 3GPP TS 23.041. + * + * {@hide} + */ +public class SmsCbEtwsInfo implements Parcelable { + + /** ETWS warning type for earthquake. */ + public static final int ETWS_WARNING_TYPE_EARTHQUAKE = 0x00; + + /** ETWS warning type for tsunami. */ + public static final int ETWS_WARNING_TYPE_TSUNAMI = 0x01; + + /** ETWS warning type for earthquake and tsunami. */ + public static final int ETWS_WARNING_TYPE_EARTHQUAKE_AND_TSUNAMI = 0x02; + + /** ETWS warning type for test messages. */ + public static final int ETWS_WARNING_TYPE_TEST_MESSAGE = 0x03; + + /** ETWS warning type for other emergency types. */ + public static final int ETWS_WARNING_TYPE_OTHER_EMERGENCY = 0x04; + + /** Unknown ETWS warning type. */ + public static final int ETWS_WARNING_TYPE_UNKNOWN = -1; + + /** One of the ETWS warning type constants defined in this class. */ + private final int mWarningType; + + /** Whether or not to activate the emergency user alert tone and vibration. */ + private final boolean mEmergencyUserAlert; + + /** Whether or not to activate a popup alert. */ + private final boolean mActivatePopup; + + /** + * 50-byte security information (ETWS primary notification for GSM only). As of Release 10, + * 3GPP TS 23.041 states that the UE shall ignore the ETWS primary notification timestamp + * and digital signature if received. Therefore it is treated as a raw byte array and + * parceled with the broadcast intent if present, but the timestamp is only computed if an + * application asks for the individual components. + */ + private final byte[] mWarningSecurityInformation; + + /** Create a new SmsCbEtwsInfo object with the specified values. */ + public SmsCbEtwsInfo(int warningType, boolean emergencyUserAlert, boolean activatePopup, + byte[] warningSecurityInformation) { + mWarningType = warningType; + mEmergencyUserAlert = emergencyUserAlert; + mActivatePopup = activatePopup; + mWarningSecurityInformation = warningSecurityInformation; + } + + /** Create a new SmsCbEtwsInfo object from a Parcel. */ + SmsCbEtwsInfo(Parcel in) { + mWarningType = in.readInt(); + mEmergencyUserAlert = (in.readInt() != 0); + mActivatePopup = (in.readInt() != 0); + mWarningSecurityInformation = in.createByteArray(); + } + + /** + * Flatten this object into a Parcel. + * + * @param dest The Parcel in which the object should be written. + * @param flags Additional flags about how the object should be written (ignored). + */ + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(mWarningType); + dest.writeInt(mEmergencyUserAlert ? 1 : 0); + dest.writeInt(mActivatePopup ? 1 : 0); + dest.writeByteArray(mWarningSecurityInformation); + } + + /** + * Returns the ETWS warning type. + * @return a warning type such as {@link #ETWS_WARNING_TYPE_EARTHQUAKE} + */ + public int getWarningType() { + return mWarningType; + } + + /** + * Returns the ETWS emergency user alert flag. + * @return true to notify terminal to activate emergency user alert; false otherwise + */ + public boolean isEmergencyUserAlert() { + return mEmergencyUserAlert; + } + + /** + * Returns the ETWS activate popup flag. + * @return true to notify terminal to activate display popup; false otherwise + */ + public boolean isPopupAlert() { + return mActivatePopup; + } + + /** + * Returns the Warning-Security-Information timestamp (GSM primary notifications only). + * As of Release 10, 3GPP TS 23.041 states that the UE shall ignore this value if received. + * @return a UTC timestamp in System.currentTimeMillis() format, or 0 if not present + */ + public long getPrimaryNotificationTimestamp() { + if (mWarningSecurityInformation == null || mWarningSecurityInformation.length < 7) { + return 0; + } + + int year = IccUtils.gsmBcdByteToInt(mWarningSecurityInformation[0]); + int month = IccUtils.gsmBcdByteToInt(mWarningSecurityInformation[1]); + int day = IccUtils.gsmBcdByteToInt(mWarningSecurityInformation[2]); + int hour = IccUtils.gsmBcdByteToInt(mWarningSecurityInformation[3]); + int minute = IccUtils.gsmBcdByteToInt(mWarningSecurityInformation[4]); + int second = IccUtils.gsmBcdByteToInt(mWarningSecurityInformation[5]); + + // 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 = mWarningSecurityInformation[6]; + + // Mask out sign bit. + int timezoneOffset = IccUtils.gsmBcdByteToInt((byte) (tzByte & (~0x08))); + + timezoneOffset = ((tzByte & 0x08) == 0) ? timezoneOffset : -timezoneOffset; + + Time time = new Time(Time.TIMEZONE_UTC); + + // We only need to support years above 2000. + time.year = 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) - (long) (timezoneOffset * 15 * 60 * 1000); + } + + /** + * Returns the digital signature (GSM primary notifications only). As of Release 10, + * 3GPP TS 23.041 states that the UE shall ignore this value if received. + * @return a byte array containing a copy of the primary notification digital signature + */ + public byte[] getPrimaryNotificationSignature() { + if (mWarningSecurityInformation == null || mWarningSecurityInformation.length < 50) { + return null; + } + return Arrays.copyOfRange(mWarningSecurityInformation, 7, 50); + } + + @Override + public String toString() { + return "SmsCbEtwsInfo{warningType=" + mWarningType + ", emergencyUserAlert=" + + mEmergencyUserAlert + ", activatePopup=" + mActivatePopup + '}'; + } + + /** + * Describe the kinds of special objects contained in the marshalled representation. + * @return a bitmask indicating this Parcelable contains no special objects + */ + @Override + public int describeContents() { + return 0; + } + + /** Creator for unparcelling objects. */ + public static final Creator CREATOR = new Creator() { + public SmsCbEtwsInfo createFromParcel(Parcel in) { + return new SmsCbEtwsInfo(in); + } + + public SmsCbEtwsInfo[] newArray(int size) { + return new SmsCbEtwsInfo[size]; + } + }; +} diff --git a/src/java/android/telephony/SmsCbLocation.java b/src/java/android/telephony/SmsCbLocation.java new file mode 100644 index 0000000..7b5bd0d --- /dev/null +++ b/src/java/android/telephony/SmsCbLocation.java @@ -0,0 +1,202 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.telephony; + +import android.os.Bundle; +import android.os.Parcel; +import android.os.Parcelable; +import android.telephony.gsm.GsmCellLocation; + +/** + * Represents the location and geographical scope of a cell broadcast message. + * For GSM/UMTS, the Location Area and Cell ID are set when the broadcast + * geographical scope is cell wide or Location Area wide. For CDMA, the + * broadcast geographical scope is always PLMN wide. + * + * @hide + */ +public class SmsCbLocation implements Parcelable { + + /** The PLMN. Note that this field may be an empty string, but isn't allowed to be null. */ + private final String mPlmn; + + private final int mLac; + private final int mCid; + + /** + * Construct an empty location object. This is used for some test cases, and for + * cell broadcasts saved in older versions of the database without location info. + */ + public SmsCbLocation() { + mPlmn = ""; + mLac = -1; + mCid = -1; + } + + /** + * Construct a location object for the PLMN. This class is immutable, so + * the same object can be reused for multiple broadcasts. + */ + public SmsCbLocation(String plmn) { + mPlmn = plmn; + mLac = -1; + mCid = -1; + } + + /** + * Construct a location object for the PLMN, LAC, and Cell ID. This class is immutable, so + * the same object can be reused for multiple broadcasts. + */ + public SmsCbLocation(String plmn, int lac, int cid) { + mPlmn = plmn; + mLac = lac; + mCid = cid; + } + + /** + * Initialize the object from a Parcel. + */ + public SmsCbLocation(Parcel in) { + mPlmn = in.readString(); + mLac = in.readInt(); + mCid = in.readInt(); + } + + /** + * Returns the MCC/MNC of the network as a String. + * @return the PLMN identifier (MCC+MNC) as a String + */ + public String getPlmn() { + return mPlmn; + } + + /** + * Returns the GSM location area code, or UMTS service area code. + * @return location area code, -1 if unknown, 0xffff max legal value + */ + public int getLac() { + return mLac; + } + + /** + * Returns the GSM or UMTS cell ID. + * @return gsm cell id, -1 if unknown, 0xffff max legal value + */ + public int getCid() { + return mCid; + } + + @Override + public int hashCode() { + int hash = mPlmn.hashCode(); + hash = hash * 31 + mLac; + hash = hash * 31 + mCid; + return hash; + } + + @Override + public boolean equals(Object o) { + if (o == this) { + return true; + } + if (o == null || !(o instanceof SmsCbLocation)) { + return false; + } + SmsCbLocation other = (SmsCbLocation) o; + return mPlmn.equals(other.mPlmn) && mLac == other.mLac && mCid == other.mCid; + } + + @Override + public String toString() { + return '[' + mPlmn + ',' + mLac + ',' + mCid + ']'; + } + + /** + * Test whether this location is within the location area of the specified object. + * + * @param area the location area to compare with this location + * @return true if this location is contained within the specified location area + */ + public boolean isInLocationArea(SmsCbLocation area) { + if (mCid != -1 && mCid != area.mCid) { + return false; + } + if (mLac != -1 && mLac != area.mLac) { + return false; + } + return mPlmn.equals(area.mPlmn); + } + + /** + * Test whether this location is within the location area of the CellLocation. + * + * @param plmn the PLMN to use for comparison + * @param lac the Location Area (GSM) or Service Area (UMTS) to compare with + * @param cid the Cell ID to compare with + * @return true if this location is contained within the specified PLMN, LAC, and Cell ID + */ + public boolean isInLocationArea(String plmn, int lac, int cid) { + if (!mPlmn.equals(plmn)) { + return false; + } + + if (mLac != -1 && mLac != lac) { + return false; + } + + if (mCid != -1 && mCid != cid) { + return false; + } + + return true; + } + + /** + * Flatten this object into a Parcel. + * + * @param dest The Parcel in which the object should be written. + * @param flags Additional flags about how the object should be written (ignored). + */ + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeString(mPlmn); + dest.writeInt(mLac); + dest.writeInt(mCid); + } + + public static final Parcelable.Creator CREATOR + = new Parcelable.Creator() { + @Override + public SmsCbLocation createFromParcel(Parcel in) { + return new SmsCbLocation(in); + } + + @Override + public SmsCbLocation[] newArray(int size) { + return new SmsCbLocation[size]; + } + }; + + /** + * Describe the kinds of special objects contained in the marshalled representation. + * @return a bitmask indicating this Parcelable contains no special objects + */ + @Override + public int describeContents() { + return 0; + } +} diff --git a/src/java/android/telephony/SmsCbMessage.java b/src/java/android/telephony/SmsCbMessage.java new file mode 100644 index 0000000..046bf8c --- /dev/null +++ b/src/java/android/telephony/SmsCbMessage.java @@ -0,0 +1,382 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.telephony; + +import android.os.Parcel; +import android.os.Parcelable; + +/** + * Parcelable object containing a received cell broadcast message. There are four different types + * of Cell Broadcast messages: + * + *

    + *
  • opt-in informational broadcasts, e.g. news, weather, stock quotes, sports scores
  • + *
  • cell information messages, broadcast on channel 50, indicating the current cell name for + * roaming purposes (required to display on the idle screen in Brazil)
  • + *
  • emergency broadcasts for the Japanese Earthquake and Tsunami Warning System (ETWS)
  • + *
  • emergency broadcasts for the American Commercial Mobile Alert Service (CMAS)
  • + *
+ * + *

There are also four different CB message formats: GSM, ETWS Primary Notification (GSM only), + * UMTS, and CDMA. Some fields are only applicable for some message formats. Other fields were + * unified under a common name, avoiding some names, such as "Message Identifier", that refer to + * two completely different concepts in 3GPP and CDMA. + * + *

The GSM/UMTS Message Identifier field is available via {@link #getServiceCategory}, the name + * of the equivalent field in CDMA. In both cases the service category is a 16-bit value, but 3GPP + * and 3GPP2 have completely different meanings for the respective values. For ETWS and CMAS, the + * application should + * + *

The CDMA Message Identifier field is available via {@link #getSerialNumber}, which is used + * to detect the receipt of a duplicate message to be discarded. In CDMA, the message ID is + * unique to the current PLMN. In GSM/UMTS, there is a 16-bit serial number containing a 2-bit + * Geographical Scope field which indicates whether the 10-bit message code and 4-bit update number + * are considered unique to the PLMN, to the current cell, or to the current Location Area (or + * Service Area in UMTS). The relevant values are concatenated into a single String which will be + * unique if the messages are not duplicates. + * + *

The SMS dispatcher does not detect duplicate messages. However, it does concatenate the + * pages of a GSM multi-page cell broadcast into a single SmsCbMessage object. + * + *

Interested applications with {@code RECEIVE_SMS_PERMISSION} can register to receive + * {@code SMS_CB_RECEIVED_ACTION} broadcast intents for incoming non-emergency broadcasts. + * Only system applications such as the CellBroadcastReceiver may receive notifications for + * emergency broadcasts (ETWS and CMAS). This is intended to prevent any potential for delays or + * interference with the immediate display of the alert message and playing of the alert sound and + * vibration pattern, which could be caused by poorly written or malicious non-system code. + * + * @hide + */ +public class SmsCbMessage implements Parcelable { + + protected static final String LOG_TAG = "SMSCB"; + + /** Cell wide geographical scope with immediate display (GSM/UMTS only). */ + public static final int GEOGRAPHICAL_SCOPE_CELL_WIDE_IMMEDIATE = 0; + + /** PLMN wide geographical scope (GSM/UMTS and all CDMA broadcasts). */ + public static final int GEOGRAPHICAL_SCOPE_PLMN_WIDE = 1; + + /** Location / service area wide geographical scope (GSM/UMTS only). */ + public static final int GEOGRAPHICAL_SCOPE_LA_WIDE = 2; + + /** Cell wide geographical scope (GSM/UMTS only). */ + public static final int GEOGRAPHICAL_SCOPE_CELL_WIDE = 3; + + /** GSM or UMTS format cell broadcast. */ + public static final int MESSAGE_FORMAT_3GPP = 1; + + /** CDMA format cell broadcast. */ + public static final int MESSAGE_FORMAT_3GPP2 = 2; + + /** Normal message priority. */ + public static final int MESSAGE_PRIORITY_NORMAL = 0; + + /** Interactive message priority. */ + public static final int MESSAGE_PRIORITY_INTERACTIVE = 1; + + /** Urgent message priority. */ + public static final int MESSAGE_PRIORITY_URGENT = 2; + + /** Emergency message priority. */ + public static final int MESSAGE_PRIORITY_EMERGENCY = 3; + + /** Format of this message (for interpretation of service category values). */ + private final int mMessageFormat; + + /** Geographical scope of broadcast. */ + private final int mGeographicalScope; + + /** + * Serial number of broadcast (message identifier for CDMA, geographical scope + message code + + * update number for GSM/UMTS). The serial number plus the location code uniquely identify + * a cell broadcast for duplicate detection. + */ + private final int mSerialNumber; + + /** + * Location identifier for this message. It consists of the current operator MCC/MNC as a + * 5 or 6-digit decimal string. In addition, for GSM/UMTS, if the Geographical Scope of the + * message is not binary 01, the Location Area is included for comparison. If the GS is + * 00 or 11, the Cell ID is also included. LAC and Cell ID are -1 if not specified. + */ + private final SmsCbLocation mLocation; + + /** + * 16-bit CDMA service category or GSM/UMTS message identifier. For ETWS and CMAS warnings, + * the information provided by the category is also available via {@link #getEtwsWarningInfo()} + * or {@link #getCmasWarningInfo()}. + */ + private final int mServiceCategory; + + /** Message language, as a two-character string, e.g. "en". */ + private final String mLanguage; + + /** Message body, as a String. */ + private final String mBody; + + /** Message priority (including emergency priority). */ + private final int mPriority; + + /** ETWS warning notification information (ETWS warnings only). */ + private final SmsCbEtwsInfo mEtwsWarningInfo; + + /** CMAS warning notification information (CMAS warnings only). */ + private final SmsCbCmasInfo mCmasWarningInfo; + + /** + * Create a new SmsCbMessage with the specified data. + */ + public SmsCbMessage(int messageFormat, int geographicalScope, int serialNumber, + SmsCbLocation location, int serviceCategory, String language, String body, + int priority, SmsCbEtwsInfo etwsWarningInfo, SmsCbCmasInfo cmasWarningInfo) { + mMessageFormat = messageFormat; + mGeographicalScope = geographicalScope; + mSerialNumber = serialNumber; + mLocation = location; + mServiceCategory = serviceCategory; + mLanguage = language; + mBody = body; + mPriority = priority; + mEtwsWarningInfo = etwsWarningInfo; + mCmasWarningInfo = cmasWarningInfo; + } + + /** Create a new SmsCbMessage object from a Parcel. */ + public SmsCbMessage(Parcel in) { + mMessageFormat = in.readInt(); + mGeographicalScope = in.readInt(); + mSerialNumber = in.readInt(); + mLocation = new SmsCbLocation(in); + mServiceCategory = in.readInt(); + mLanguage = in.readString(); + mBody = in.readString(); + mPriority = in.readInt(); + int type = in.readInt(); + switch (type) { + case 'E': + // unparcel ETWS warning information + mEtwsWarningInfo = new SmsCbEtwsInfo(in); + mCmasWarningInfo = null; + break; + + case 'C': + // unparcel CMAS warning information + mEtwsWarningInfo = null; + mCmasWarningInfo = new SmsCbCmasInfo(in); + break; + + default: + mEtwsWarningInfo = null; + mCmasWarningInfo = null; + } + } + + /** + * Flatten this object into a Parcel. + * + * @param dest The Parcel in which the object should be written. + * @param flags Additional flags about how the object should be written (ignored). + */ + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(mMessageFormat); + dest.writeInt(mGeographicalScope); + dest.writeInt(mSerialNumber); + mLocation.writeToParcel(dest, flags); + dest.writeInt(mServiceCategory); + dest.writeString(mLanguage); + dest.writeString(mBody); + dest.writeInt(mPriority); + if (mEtwsWarningInfo != null) { + // parcel ETWS warning information + dest.writeInt('E'); + mEtwsWarningInfo.writeToParcel(dest, flags); + } else if (mCmasWarningInfo != null) { + // parcel CMAS warning information + dest.writeInt('C'); + mCmasWarningInfo.writeToParcel(dest, flags); + } else { + // no ETWS or CMAS warning information + dest.writeInt('0'); + } + } + + public static final Parcelable.Creator CREATOR + = new Parcelable.Creator() { + @Override + public SmsCbMessage createFromParcel(Parcel in) { + return new SmsCbMessage(in); + } + + @Override + public SmsCbMessage[] newArray(int size) { + return new SmsCbMessage[size]; + } + }; + + /** + * Return the geographical scope of this message (GSM/UMTS only). + * + * @return Geographical scope + */ + public int getGeographicalScope() { + return mGeographicalScope; + } + + /** + * Return the broadcast serial number of broadcast (message identifier for CDMA, or + * geographical scope + message code + update number for GSM/UMTS). The serial number plus + * the location code uniquely identify a cell broadcast for duplicate detection. + * + * @return the 16-bit CDMA message identifier or GSM/UMTS serial number + */ + public int getSerialNumber() { + return mSerialNumber; + } + + /** + * Return the location identifier for this message, consisting of the MCC/MNC as a + * 5 or 6-digit decimal string. In addition, for GSM/UMTS, if the Geographical Scope of the + * message is not binary 01, the Location Area is included. If the GS is 00 or 11, the + * cell ID is also included. The {@link SmsCbLocation} object includes a method to test + * if the location is included within another location area or within a PLMN and CellLocation. + * + * @return the geographical location code for duplicate message detection + */ + public SmsCbLocation getLocation() { + return mLocation; + } + + /** + * Return the 16-bit CDMA service category or GSM/UMTS message identifier. The interpretation + * of the category is radio technology specific. For ETWS and CMAS warnings, the information + * provided by the category is available via {@link #getEtwsWarningInfo()} or + * {@link #getCmasWarningInfo()} in a radio technology independent format. + * + * @return the radio technology specific service category + */ + public int getServiceCategory() { + return mServiceCategory; + } + + /** + * Get the ISO-639-1 language code for this message, or null if unspecified + * + * @return Language code + */ + public String getLanguageCode() { + return mLanguage; + } + + /** + * Get the body of this message, or null if no body available + * + * @return Body, or null + */ + public String getMessageBody() { + return mBody; + } + + /** + * Get the message format ({@link #MESSAGE_FORMAT_3GPP} or {@link #MESSAGE_FORMAT_3GPP2}). + * @return an integer representing 3GPP or 3GPP2 message format + */ + public int getMessageFormat() { + return mMessageFormat; + } + + /** + * Get the message priority. Normal broadcasts return {@link #MESSAGE_PRIORITY_NORMAL} + * and emergency broadcasts return {@link #MESSAGE_PRIORITY_EMERGENCY}. CDMA also may return + * {@link #MESSAGE_PRIORITY_INTERACTIVE} or {@link #MESSAGE_PRIORITY_URGENT}. + * @return an integer representing the message priority + */ + public int getMessagePriority() { + return mPriority; + } + + /** + * If this is an ETWS warning notification then this method will return an object containing + * the ETWS warning type, the emergency user alert flag, and the popup flag. If this is an + * ETWS primary notification (GSM only), there will also be a 7-byte timestamp and 43-byte + * digital signature. As of Release 10, 3GPP TS 23.041 states that the UE shall ignore the + * ETWS primary notification timestamp and digital signature if received. + * + * @return an SmsCbEtwsInfo object, or null if this is not an ETWS warning notification + */ + public SmsCbEtwsInfo getEtwsWarningInfo() { + return mEtwsWarningInfo; + } + + /** + * If this is a CMAS warning notification then this method will return an object containing + * the CMAS message class, category, response type, severity, urgency and certainty. + * The message class is always present. Severity, urgency and certainty are present for CDMA + * warning notifications containing a type 1 elements record and for GSM and UMTS warnings + * except for the Presidential-level alert category. Category and response type are only + * available for CDMA notifications containing a type 1 elements record. + * + * @return an SmsCbCmasInfo object, or null if this is not a CMAS warning notification + */ + public SmsCbCmasInfo getCmasWarningInfo() { + return mCmasWarningInfo; + } + + /** + * Return whether this message is an emergency (PWS) message type. + * @return true if the message is a public warning notification; false otherwise + */ + public boolean isEmergencyMessage() { + return mPriority == MESSAGE_PRIORITY_EMERGENCY; + } + + /** + * Return whether this message is an ETWS warning alert. + * @return true if the message is an ETWS warning notification; false otherwise + */ + public boolean isEtwsMessage() { + return mEtwsWarningInfo != null; + } + + /** + * Return whether this message is a CMAS warning alert. + * @return true if the message is a CMAS warning notification; false otherwise + */ + public boolean isCmasMessage() { + return mCmasWarningInfo != null; + } + + @Override + public String toString() { + return "SmsCbMessage{geographicalScope=" + mGeographicalScope + ", serialNumber=" + + mSerialNumber + ", location=" + mLocation + ", serviceCategory=" + + mServiceCategory + ", language=" + mLanguage + ", body=" + mBody + + ", priority=" + mPriority + + (mEtwsWarningInfo != null ? (", " + mEtwsWarningInfo.toString()) : "") + + (mCmasWarningInfo != null ? (", " + mCmasWarningInfo.toString()) : "") + '}'; + } + + /** + * Describe the kinds of special objects contained in the marshalled representation. + * @return a bitmask indicating this Parcelable contains no special objects + */ + @Override + public int describeContents() { + return 0; + } +} diff --git a/src/java/android/telephony/SmsManager.java b/src/java/android/telephony/SmsManager.java new file mode 100644 index 0000000..44bdaeb --- /dev/null +++ b/src/java/android/telephony/SmsManager.java @@ -0,0 +1,522 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.telephony; + +import android.app.PendingIntent; +import android.os.RemoteException; +import android.os.ServiceManager; +import android.text.TextUtils; + +import com.android.internal.telephony.ISms; +import com.android.internal.telephony.IccConstants; +import com.android.internal.telephony.SmsRawData; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/* + * TODO(code review): Curious question... Why are a lot of these + * methods not declared as static, since they do not seem to require + * any local object state? Presumably this cannot be changed without + * interfering with the API... + */ + +/** + * Manages SMS operations such as sending data, text, and pdu SMS messages. + * Get this object by calling the static method SmsManager.getDefault(). + */ +public final class SmsManager { + /** Singleton object constructed during class initialization. */ + private static final SmsManager sInstance = new SmsManager(); + + /** + * Send a text based SMS. + * + * @param destinationAddress the address to send the message to + * @param scAddress is the service center address or null to use + * the current default SMSC + * @param text the body of the message to send + * @param sentIntent if not NULL this PendingIntent is + * broadcast when the message is successfully sent, or failed. + * The result code will be Activity.RESULT_OK for success, + * or one of these errors:
+ * RESULT_ERROR_GENERIC_FAILURE
+ * RESULT_ERROR_RADIO_OFF
+ * RESULT_ERROR_NULL_PDU
+ * For RESULT_ERROR_GENERIC_FAILURE the sentIntent may include + * the extra "errorCode" containing a radio technology specific value, + * generally only useful for troubleshooting.
+ * The per-application based SMS control checks sentIntent. If sentIntent + * is NULL the caller will be checked against all unknown applications, + * which cause smaller number of SMS to be sent in checking period. + * @param deliveryIntent if not NULL this PendingIntent is + * broadcast when the message is delivered to the recipient. The + * raw pdu of the status report is in the extended data ("pdu"). + * + * @throws IllegalArgumentException if destinationAddress or text are empty + */ + public void sendTextMessage( + String destinationAddress, String scAddress, String text, + PendingIntent sentIntent, PendingIntent deliveryIntent) { + if (TextUtils.isEmpty(destinationAddress)) { + throw new IllegalArgumentException("Invalid destinationAddress"); + } + + if (TextUtils.isEmpty(text)) { + throw new IllegalArgumentException("Invalid message body"); + } + + try { + ISms iccISms = ISms.Stub.asInterface(ServiceManager.getService("isms")); + if (iccISms != null) { + iccISms.sendText(destinationAddress, scAddress, text, sentIntent, deliveryIntent); + } + } catch (RemoteException ex) { + // ignore it + } + } + + /** + * Divide a message text into several fragments, none bigger than + * the maximum SMS message size. + * + * @param text the original message. Must not be null. + * @return an ArrayList of strings that, in order, + * comprise the original message + */ + public ArrayList divideMessage(String text) { + return SmsMessage.fragmentText(text); + } + + /** + * Send a multi-part text based SMS. The callee should have already + * divided the message into correctly sized parts by calling + * divideMessage. + * + * @param destinationAddress the address to send the message to + * @param scAddress is the service center address or null to use + * the current default SMSC + * @param parts an ArrayList of strings that, in order, + * comprise the original message + * @param sentIntents if not null, an ArrayList of + * PendingIntents (one for each message part) that is + * broadcast when the corresponding message part has been sent. + * The result code will be Activity.RESULT_OK for success, + * or one of these errors:
+ * RESULT_ERROR_GENERIC_FAILURE
+ * RESULT_ERROR_RADIO_OFF
+ * RESULT_ERROR_NULL_PDU
+ * For RESULT_ERROR_GENERIC_FAILURE each sentIntent may include + * the extra "errorCode" containing a radio technology specific value, + * generally only useful for troubleshooting.
+ * The per-application based SMS control checks sentIntent. If sentIntent + * is NULL the caller will be checked against all unknown applications, + * which cause smaller number of SMS to be sent in checking period. + * @param deliveryIntents if not null, an ArrayList of + * PendingIntents (one for each message part) that is + * broadcast when the corresponding message part has been delivered + * to the recipient. The raw pdu of the status report is in the + * extended data ("pdu"). + * + * @throws IllegalArgumentException if destinationAddress or data are empty + */ + public void sendMultipartTextMessage( + String destinationAddress, String scAddress, ArrayList parts, + ArrayList sentIntents, ArrayList deliveryIntents) { + if (TextUtils.isEmpty(destinationAddress)) { + throw new IllegalArgumentException("Invalid destinationAddress"); + } + if (parts == null || parts.size() < 1) { + throw new IllegalArgumentException("Invalid message body"); + } + + if (parts.size() > 1) { + try { + ISms iccISms = ISms.Stub.asInterface(ServiceManager.getService("isms")); + if (iccISms != null) { + iccISms.sendMultipartText(destinationAddress, scAddress, parts, + sentIntents, deliveryIntents); + } + } catch (RemoteException ex) { + // ignore it + } + } else { + PendingIntent sentIntent = null; + PendingIntent deliveryIntent = null; + if (sentIntents != null && sentIntents.size() > 0) { + sentIntent = sentIntents.get(0); + } + if (deliveryIntents != null && deliveryIntents.size() > 0) { + deliveryIntent = deliveryIntents.get(0); + } + sendTextMessage(destinationAddress, scAddress, parts.get(0), + sentIntent, deliveryIntent); + } + } + + /** + * Send a data based SMS to a specific application port. + * + * @param destinationAddress the address to send the message to + * @param scAddress is the service center address or null to use + * the current default SMSC + * @param destinationPort the port to deliver the message to + * @param data the body of the message to send + * @param sentIntent if not NULL this PendingIntent is + * broadcast when the message is successfully sent, or failed. + * The result code will be Activity.RESULT_OK for success, + * or one of these errors:
+ * RESULT_ERROR_GENERIC_FAILURE
+ * RESULT_ERROR_RADIO_OFF
+ * RESULT_ERROR_NULL_PDU
+ * For RESULT_ERROR_GENERIC_FAILURE the sentIntent may include + * the extra "errorCode" containing a radio technology specific value, + * generally only useful for troubleshooting.
+ * The per-application based SMS control checks sentIntent. If sentIntent + * is NULL the caller will be checked against all unknown applications, + * which cause smaller number of SMS to be sent in checking period. + * @param deliveryIntent if not NULL this PendingIntent is + * broadcast when the message is delivered to the recipient. The + * raw pdu of the status report is in the extended data ("pdu"). + * + * @throws IllegalArgumentException if destinationAddress or data are empty + */ + public void sendDataMessage( + String destinationAddress, String scAddress, short destinationPort, + byte[] data, PendingIntent sentIntent, PendingIntent deliveryIntent) { + if (TextUtils.isEmpty(destinationAddress)) { + throw new IllegalArgumentException("Invalid destinationAddress"); + } + + if (data == null || data.length == 0) { + throw new IllegalArgumentException("Invalid message data"); + } + + try { + ISms iccISms = ISms.Stub.asInterface(ServiceManager.getService("isms")); + if (iccISms != null) { + iccISms.sendData(destinationAddress, scAddress, destinationPort & 0xFFFF, + data, sentIntent, deliveryIntent); + } + } catch (RemoteException ex) { + // ignore it + } + } + + /** + * Get the default instance of the SmsManager + * + * @return the default instance of the SmsManager + */ + public static SmsManager getDefault() { + return sInstance; + } + + private SmsManager() { + //nothing + } + + /** + * Copy 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. + * + * @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 + * + * {@hide} + */ + public boolean copyMessageToIcc(byte[] smsc, byte[] pdu, int status) { + boolean success = false; + + try { + ISms iccISms = ISms.Stub.asInterface(ServiceManager.getService("isms")); + if (iccISms != null) { + success = iccISms.copyMessageToIccEf(status, pdu, smsc); + } + } catch (RemoteException ex) { + // ignore it + } + + return success; + } + + /** + * Delete the specified message from the ICC. + * ICC (Integrated Circuit Card) is the card of the device. + * For example, this can be the SIM or USIM for GSM. + * + * @param messageIndex is the record index of the message on ICC + * @return true for success + * + * {@hide} + */ + public boolean + deleteMessageFromIcc(int messageIndex) { + boolean success = false; + byte[] pdu = new byte[IccConstants.SMS_RECORD_LENGTH-1]; + Arrays.fill(pdu, (byte)0xff); + + try { + ISms iccISms = ISms.Stub.asInterface(ServiceManager.getService("isms")); + if (iccISms != null) { + success = iccISms.updateMessageOnIccEf(messageIndex, STATUS_ON_ICC_FREE, pdu); + } + } catch (RemoteException ex) { + // ignore it + } + + return success; + } + + /** + * Update the specified message on the ICC. + * ICC (Integrated Circuit Card) is the card of the device. + * For example, this can be the SIM or USIM for GSM. + * + * @param messageIndex record index of message to update + * @param newStatus new message status (STATUS_ON_ICC_READ, + * STATUS_ON_ICC_UNREAD, STATUS_ON_ICC_SENT, + * STATUS_ON_ICC_UNSENT, STATUS_ON_ICC_FREE) + * @param pdu the raw PDU to store + * @return true for success + * + * {@hide} + */ + public boolean updateMessageOnIcc(int messageIndex, int newStatus, byte[] pdu) { + boolean success = false; + + try { + ISms iccISms = ISms.Stub.asInterface(ServiceManager.getService("isms")); + if (iccISms != null) { + success = iccISms.updateMessageOnIccEf(messageIndex, newStatus, pdu); + } + } catch (RemoteException ex) { + // ignore it + } + + return success; + } + + /** + * Retrieves all messages currently stored on ICC. + * ICC (Integrated Circuit Card) is the card of the device. + * For example, this can be the SIM or USIM for GSM. + * + * @return ArrayList of SmsMessage objects + * + * {@hide} + */ + public static ArrayList getAllMessagesFromIcc() { + List records = null; + + try { + ISms iccISms = ISms.Stub.asInterface(ServiceManager.getService("isms")); + if (iccISms != null) { + records = iccISms.getAllMessagesFromIccEf(); + } + } catch (RemoteException ex) { + // ignore it + } + + return createMessageListFromRawRecords(records); + } + + /** + * Enable reception of cell broadcast (SMS-CB) messages with the given + * message identifier. Note that if two different clients enable the same + * message identifier, they must both disable it for the device to stop + * receiving those messages. All received messages will be broadcast in an + * intent with the action "android.provider.Telephony.SMS_CB_RECEIVED". + * Note: This call is blocking, callers may want to avoid calling it from + * the main thread of an application. + * + * @param messageIdentifier Message identifier as specified in TS 23.041 + * @return true if successful, false otherwise + * @see #disableCellBroadcast(int) + * + * {@hide} + */ + public boolean enableCellBroadcast(int messageIdentifier) { + boolean success = false; + + try { + ISms iccISms = ISms.Stub.asInterface(ServiceManager.getService("isms")); + if (iccISms != null) { + success = iccISms.enableCellBroadcast(messageIdentifier); + } + } catch (RemoteException ex) { + // ignore it + } + + return success; + } + + /** + * Disable reception of cell broadcast (SMS-CB) messages with the given + * message identifier. Note that if two different clients enable the same + * message identifier, they must both disable it for the device to stop + * receiving those messages. + * Note: This call is blocking, callers may want to avoid calling it from + * the main thread of an application. + * + * @param messageIdentifier Message identifier as specified in TS 23.041 + * @return true if successful, false otherwise + * + * @see #enableCellBroadcast(int) + * + * {@hide} + */ + public boolean disableCellBroadcast(int messageIdentifier) { + boolean success = false; + + try { + ISms iccISms = ISms.Stub.asInterface(ServiceManager.getService("isms")); + if (iccISms != null) { + success = iccISms.disableCellBroadcast(messageIdentifier); + } + } catch (RemoteException ex) { + // ignore it + } + + return success; + } + + /** + * Enable reception of cell broadcast (SMS-CB) messages with the given + * message identifier range. Note that if two different clients enable the same + * message identifier, they must both disable it for the device to stop + * receiving those messages. All received messages will be broadcast in an + * intent with the action "android.provider.Telephony.SMS_CB_RECEIVED". + * Note: This call is blocking, callers may want to avoid calling it from + * the main thread of an application. + * + * @param startMessageId first message identifier as specified in TS 23.041 + * @param endMessageId last message identifier as specified in TS 23.041 + * @return true if successful, false otherwise + * @see #disableCellBroadcastRange(int, int) + * + * {@hide} + */ + public boolean enableCellBroadcastRange(int startMessageId, int endMessageId) { + boolean success = false; + + try { + ISms iccISms = ISms.Stub.asInterface(ServiceManager.getService("isms")); + if (iccISms != null) { + success = iccISms.enableCellBroadcastRange(startMessageId, endMessageId); + } + } catch (RemoteException ex) { + // ignore it + } + + return success; + } + + /** + * Disable reception of cell broadcast (SMS-CB) messages with the given + * message identifier range. Note that if two different clients enable the same + * message identifier, they must both disable it for the device to stop + * receiving those messages. + * Note: This call is blocking, callers may want to avoid calling it from + * the main thread of an application. + * + * @param startMessageId first message identifier as specified in TS 23.041 + * @param endMessageId last message identifier as specified in TS 23.041 + * @return true if successful, false otherwise + * + * @see #enableCellBroadcastRange(int, int) + * + * {@hide} + */ + public boolean disableCellBroadcastRange(int startMessageId, int endMessageId) { + boolean success = false; + + try { + ISms iccISms = ISms.Stub.asInterface(ServiceManager.getService("isms")); + if (iccISms != null) { + success = iccISms.disableCellBroadcastRange(startMessageId, endMessageId); + } + } catch (RemoteException ex) { + // ignore it + } + + return success; + } + + /** + * Create a list of SmsMessages from a list of RawSmsData + * records returned by getAllMessagesFromIcc() + * + * @param records SMS EF records, returned by + * getAllMessagesFromIcc + * @return ArrayList of SmsMessage objects. + */ + private static ArrayList createMessageListFromRawRecords(List records) { + ArrayList messages = new ArrayList(); + if (records != null) { + int count = records.size(); + for (int i = 0; i < count; i++) { + SmsRawData data = records.get(i); + // List contains all records, including "free" records (null) + if (data != null) { + SmsMessage sms = SmsMessage.createFromEfRecord(i+1, data.getBytes()); + if (sms != null) { + messages.add(sms); + } + } + } + } + return messages; + } + + // see SmsMessage.getStatusOnIcc + + /** Free space (TS 51.011 10.5.3 / 3GPP2 C.S0023 3.4.27). */ + static public final int STATUS_ON_ICC_FREE = 0; + + /** Received and read (TS 51.011 10.5.3 / 3GPP2 C.S0023 3.4.27). */ + static public final int STATUS_ON_ICC_READ = 1; + + /** Received and unread (TS 51.011 10.5.3 / 3GPP2 C.S0023 3.4.27). */ + static public final int STATUS_ON_ICC_UNREAD = 3; + + /** Stored and sent (TS 51.011 10.5.3 / 3GPP2 C.S0023 3.4.27). */ + static public final int STATUS_ON_ICC_SENT = 5; + + /** Stored and unsent (TS 51.011 10.5.3 / 3GPP2 C.S0023 3.4.27). */ + static public final int STATUS_ON_ICC_UNSENT = 7; + + // SMS send failure result codes + + /** Generic failure cause */ + static public final int RESULT_ERROR_GENERIC_FAILURE = 1; + /** Failed because radio was explicitly turned off */ + static public final int RESULT_ERROR_RADIO_OFF = 2; + /** Failed because no pdu provided */ + static public final int RESULT_ERROR_NULL_PDU = 3; + /** Failed because service is currently unavailable */ + static public final int RESULT_ERROR_NO_SERVICE = 4; + /** Failed because we reached the sending queue limit. {@hide} */ + static public final int RESULT_ERROR_LIMIT_EXCEEDED = 5; + /** Failed because FDN is enabled. {@hide} */ + static public final int RESULT_ERROR_FDN_CHECK_FAILURE = 6; +} diff --git a/src/java/android/telephony/SmsMessage.java b/src/java/android/telephony/SmsMessage.java new file mode 100644 index 0000000..b94609e --- /dev/null +++ b/src/java/android/telephony/SmsMessage.java @@ -0,0 +1,688 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.telephony; + +import android.os.Parcel; +import android.util.Log; + +import com.android.internal.telephony.GsmAlphabet; +import com.android.internal.telephony.GsmAlphabet.TextEncodingDetails; +import com.android.internal.telephony.SmsConstants; +import com.android.internal.telephony.SmsHeader; +import com.android.internal.telephony.SmsMessageBase; +import com.android.internal.telephony.SmsMessageBase.SubmitPduBase; + +import java.lang.Math; +import java.util.ArrayList; +import java.util.Arrays; + +import static android.telephony.TelephonyManager.PHONE_TYPE_CDMA; + + +/** + * A Short Message Service message. + */ +public class SmsMessage { + private static final String LOG_TAG = "SMS"; + + /** + * SMS Class enumeration. + * See TS 23.038. + * + */ + public enum MessageClass{ + UNKNOWN, CLASS_0, CLASS_1, CLASS_2, CLASS_3; + } + + /** User data text encoding code unit size */ + public static final int ENCODING_UNKNOWN = 0; + public static final int ENCODING_7BIT = 1; + public static final int ENCODING_8BIT = 2; + public static final int ENCODING_16BIT = 3; + /** + * @hide This value is not defined in global standard. Only in Korea, this is used. + */ + public static final int ENCODING_KSC5601 = 4; + + /** The maximum number of payload bytes per message */ + public static final int MAX_USER_DATA_BYTES = 140; + + /** + * The maximum number of payload bytes per message if a user data header + * is present. This assumes the header only contains the + * CONCATENATED_8_BIT_REFERENCE element. + */ + public static final int MAX_USER_DATA_BYTES_WITH_HEADER = 134; + + /** The maximum number of payload septets per message */ + public static final int MAX_USER_DATA_SEPTETS = 160; + + /** + * The maximum number of payload septets per message if a user data header + * is present. This assumes the header only contains the + * CONCATENATED_8_BIT_REFERENCE element. + */ + public static final int MAX_USER_DATA_SEPTETS_WITH_HEADER = 153; + + /** + * Indicates a 3GPP format SMS message. + * @hide pending API council approval + */ + public static final String FORMAT_3GPP = "3gpp"; + + /** + * Indicates a 3GPP2 format SMS message. + * @hide pending API council approval + */ + public static final String FORMAT_3GPP2 = "3gpp2"; + + /** Contains actual SmsMessage. Only public for debugging and for framework layer. + * + * @hide + */ + public SmsMessageBase mWrappedSmsMessage; + + public static class SubmitPdu { + + public byte[] encodedScAddress; // Null if not applicable. + public byte[] encodedMessage; + + public String toString() { + return "SubmitPdu: encodedScAddress = " + + Arrays.toString(encodedScAddress) + + ", encodedMessage = " + + Arrays.toString(encodedMessage); + } + + /** + * @hide + */ + protected SubmitPdu(SubmitPduBase spb) { + this.encodedMessage = spb.encodedMessage; + this.encodedScAddress = spb.encodedScAddress; + } + + } + + private SmsMessage(SmsMessageBase smb) { + mWrappedSmsMessage = smb; + } + + /** + * Create an SmsMessage from a raw PDU. + * + *

This method will soon be deprecated and all applications which handle + * incoming SMS messages by processing the {@code SMS_RECEIVED_ACTION} broadcast + * intent must now pass the new {@code format} String extra from the intent + * into the new method {@code createFromPdu(byte[], String)} which takes an + * extra format parameter. This is required in order to correctly decode the PDU on + * devices that require support for both 3GPP and 3GPP2 formats at the same time, + * such as dual-mode GSM/CDMA and CDMA/LTE phones. + */ + public static SmsMessage createFromPdu(byte[] pdu) { + int activePhone = TelephonyManager.getDefault().getCurrentPhoneType(); + String format = (PHONE_TYPE_CDMA == activePhone) ? + SmsConstants.FORMAT_3GPP2 : SmsConstants.FORMAT_3GPP; + return createFromPdu(pdu, format); + } + + /** + * Create an SmsMessage from a raw PDU with the specified message format. The + * message format is passed in the {@code SMS_RECEIVED_ACTION} as the {@code format} + * String extra, and will be either "3gpp" for GSM/UMTS/LTE messages in 3GPP format + * or "3gpp2" for CDMA/LTE messages in 3GPP2 format. + * + * @param pdu the message PDU from the SMS_RECEIVED_ACTION intent + * @param format the format extra from the SMS_RECEIVED_ACTION intent + * @hide pending API council approval + */ + public static SmsMessage createFromPdu(byte[] pdu, String format) { + SmsMessageBase wrappedMessage; + + if (SmsConstants.FORMAT_3GPP2.equals(format)) { + wrappedMessage = com.android.internal.telephony.cdma.SmsMessage.createFromPdu(pdu); + } else if (SmsConstants.FORMAT_3GPP.equals(format)) { + wrappedMessage = com.android.internal.telephony.gsm.SmsMessage.createFromPdu(pdu); + } else { + Log.e(LOG_TAG, "createFromPdu(): unsupported message format " + format); + return null; + } + + return new SmsMessage(wrappedMessage); + } + + /** + * TS 27.005 3.4.1 lines[0] and lines[1] are the two lines read from the + * +CMT unsolicited response (PDU mode, of course) + * +CMT: [<alpha>], + * + * Only public for debugging and for RIL + * + * {@hide} + */ + public static SmsMessage newFromCMT(String[] lines) { + // received SMS in 3GPP format + SmsMessageBase wrappedMessage = + com.android.internal.telephony.gsm.SmsMessage.newFromCMT(lines); + + return new SmsMessage(wrappedMessage); + } + + /** @hide */ + public static SmsMessage newFromParcel(Parcel p) { + // received SMS in 3GPP2 format + SmsMessageBase wrappedMessage = + com.android.internal.telephony.cdma.SmsMessage.newFromParcel(p); + + return new SmsMessage(wrappedMessage); + } + + /** + * 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) { + SmsMessageBase wrappedMessage; + int activePhone = TelephonyManager.getDefault().getCurrentPhoneType(); + + if (PHONE_TYPE_CDMA == activePhone) { + wrappedMessage = com.android.internal.telephony.cdma.SmsMessage.createFromEfRecord( + index, data); + } else { + wrappedMessage = com.android.internal.telephony.gsm.SmsMessage.createFromEfRecord( + index, data); + } + + return wrappedMessage != null ? new SmsMessage(wrappedMessage) : null; + } + + /** + * Get the TP-Layer-Length for the given SMS-SUBMIT PDU Basically, the + * length in bytes (not hex chars) less the SMSC header + * + * FIXME: This method is only used by a CTS test case that isn't run on CDMA devices. + * We should probably deprecate it and remove the obsolete test case. + */ + public static int getTPLayerLengthForPDU(String pdu) { + int activePhone = TelephonyManager.getDefault().getCurrentPhoneType(); + + if (PHONE_TYPE_CDMA == activePhone) { + return com.android.internal.telephony.cdma.SmsMessage.getTPLayerLengthForPDU(pdu); + } else { + return com.android.internal.telephony.gsm.SmsMessage.getTPLayerLengthForPDU(pdu); + } + } + + /* + * TODO(cleanup): It would make some sense if the result of + * preprocessing a message to determine the proper encoding (i.e. + * the resulting data structure from calculateLength) could be + * passed as an argument to the actual final encoding function. + * This would better ensure that the logic behind size calculation + * actually matched the encoding. + */ + + /** + * Calculates the number of SMS's required to encode the message body and + * the number of characters remaining until the next message. + * + * @param msgBody the message to encode + * @param use7bitOnly if true, characters that are not part of the + * radio-specific 7-bit encoding are counted as single + * space chars. If false, and if the messageBody contains + * non-7-bit encodable characters, length is calculated + * using a 16-bit encoding. + * @return an int[4] with int[0] being the number of SMS's + * required, int[1] the number of code units used, and + * int[2] is the number of code units remaining until the + * next message. int[3] is an indicator of the encoding + * code unit size (see the ENCODING_* definitions in SmsConstants) + */ + public static int[] calculateLength(CharSequence msgBody, boolean use7bitOnly) { + int activePhone = TelephonyManager.getDefault().getCurrentPhoneType(); + TextEncodingDetails ted = (PHONE_TYPE_CDMA == activePhone) ? + com.android.internal.telephony.cdma.SmsMessage.calculateLength(msgBody, use7bitOnly) : + com.android.internal.telephony.gsm.SmsMessage.calculateLength(msgBody, use7bitOnly); + int ret[] = new int[4]; + ret[0] = ted.msgCount; + ret[1] = ted.codeUnitCount; + ret[2] = ted.codeUnitsRemaining; + ret[3] = ted.codeUnitSize; + return ret; + } + + /** + * Divide a message text into several fragments, none bigger than + * the maximum SMS message text size. + * + * @param text text, must not be null. + * @return an ArrayList of strings that, in order, + * comprise the original msg text + * + * @hide + */ + public static ArrayList fragmentText(String text) { + int activePhone = TelephonyManager.getDefault().getCurrentPhoneType(); + TextEncodingDetails ted = (PHONE_TYPE_CDMA == activePhone) ? + com.android.internal.telephony.cdma.SmsMessage.calculateLength(text, false) : + com.android.internal.telephony.gsm.SmsMessage.calculateLength(text, false); + + // TODO(cleanup): The code here could be rolled into the logic + // below cleanly if these MAX_* constants were defined more + // flexibly... + + int limit; + if (ted.codeUnitSize == SmsConstants.ENCODING_7BIT) { + int udhLength; + if (ted.languageTable != 0 && ted.languageShiftTable != 0) { + udhLength = GsmAlphabet.UDH_SEPTET_COST_TWO_SHIFT_TABLES; + } else if (ted.languageTable != 0 || ted.languageShiftTable != 0) { + udhLength = GsmAlphabet.UDH_SEPTET_COST_ONE_SHIFT_TABLE; + } else { + udhLength = 0; + } + + if (ted.msgCount > 1) { + udhLength += GsmAlphabet.UDH_SEPTET_COST_CONCATENATED_MESSAGE; + } + + if (udhLength != 0) { + udhLength += GsmAlphabet.UDH_SEPTET_COST_LENGTH; + } + + limit = SmsConstants.MAX_USER_DATA_SEPTETS - udhLength; + } else { + if (ted.msgCount > 1) { + limit = SmsConstants.MAX_USER_DATA_BYTES_WITH_HEADER; + } else { + limit = SmsConstants.MAX_USER_DATA_BYTES; + } + } + + int pos = 0; // Index in code units. + int textLen = text.length(); + ArrayList result = new ArrayList(ted.msgCount); + while (pos < textLen) { + int nextPos = 0; // Counts code units. + if (ted.codeUnitSize == SmsConstants.ENCODING_7BIT) { + if (activePhone == PHONE_TYPE_CDMA && ted.msgCount == 1) { + // For a singleton CDMA message, the encoding must be ASCII... + nextPos = pos + Math.min(limit, textLen - pos); + } else { + // For multi-segment messages, CDMA 7bit equals GSM 7bit encoding (EMS mode). + nextPos = GsmAlphabet.findGsmSeptetLimitIndex(text, pos, limit, + ted.languageTable, ted.languageShiftTable); + } + } else { // Assume unicode. + nextPos = pos + Math.min(limit / 2, textLen - pos); + } + if ((nextPos <= pos) || (nextPos > textLen)) { + Log.e(LOG_TAG, "fragmentText failed (" + pos + " >= " + nextPos + " or " + + nextPos + " >= " + textLen + ")"); + break; + } + result.add(text.substring(pos, nextPos)); + pos = nextPos; + } + return result; + } + + /** + * Calculates the number of SMS's required to encode the message body and + * the number of characters remaining until the next message, given the + * current encoding. + * + * @param messageBody the message to encode + * @param use7bitOnly if true, characters that are not part of the radio + * specific (GSM / CDMA) alphabet encoding are converted to as a + * single space characters. If false, a messageBody containing + * non-GSM or non-CDMA alphabet characters are encoded using + * 16-bit encoding. + * @return an int[4] with int[0] being the number of SMS's required, int[1] + * the number of code units used, and int[2] is the number of code + * units remaining until the next message. int[3] is the encoding + * type that should be used for the message. + */ + public static int[] calculateLength(String messageBody, boolean use7bitOnly) { + return calculateLength((CharSequence)messageBody, use7bitOnly); + } + + /* + * TODO(cleanup): It looks like there is now no useful reason why + * apps should generate pdus themselves using these routines, + * instead of handing the raw data to SMSDispatcher (and thereby + * have the phone process do the encoding). Moreover, CDMA now + * has shared state (in the form of the msgId system property) + * which can only be modified by the phone process, and hence + * makes the output of these routines incorrect. Since they now + * serve no purpose, they should probably just return null + * directly, and be deprecated. Going further in that direction, + * the above parsers of serialized pdu data should probably also + * be gotten rid of, hiding all but the necessarily visible + * structured data from client apps. A possible concern with + * doing this is that apps may be using these routines to generate + * pdus that are then sent elsewhere, some network server, for + * example, and that always returning null would thereby break + * otherwise useful apps. + */ + + /** + * Get 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 SubmitPdu 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) { + SubmitPduBase spb; + int activePhone = TelephonyManager.getDefault().getCurrentPhoneType(); + + if (PHONE_TYPE_CDMA == activePhone) { + spb = com.android.internal.telephony.cdma.SmsMessage.getSubmitPdu(scAddress, + destinationAddress, message, statusReportRequested, null); + } else { + spb = com.android.internal.telephony.gsm.SmsMessage.getSubmitPdu(scAddress, + destinationAddress, message, statusReportRequested); + } + + return new SubmitPdu(spb); + } + + /** + * Get an SMS-SUBMIT PDU for a data message to a destination address & 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 SubmitPdu 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, + boolean statusReportRequested) { + SubmitPduBase spb; + int activePhone = TelephonyManager.getDefault().getCurrentPhoneType(); + + if (PHONE_TYPE_CDMA == activePhone) { + spb = com.android.internal.telephony.cdma.SmsMessage.getSubmitPdu(scAddress, + destinationAddress, destinationPort, data, statusReportRequested); + } else { + spb = com.android.internal.telephony.gsm.SmsMessage.getSubmitPdu(scAddress, + destinationAddress, destinationPort, data, statusReportRequested); + } + + return new SubmitPdu(spb); + } + + /** + * Returns the address of the SMS service center that relayed this message + * or null if there is none. + */ + public String getServiceCenterAddress() { + return mWrappedSmsMessage.getServiceCenterAddress(); + } + + /** + * Returns the originating address (sender) of this SMS message in String + * form or null if unavailable + */ + public String getOriginatingAddress() { + return mWrappedSmsMessage.getOriginatingAddress(); + } + + /** + * Returns the originating address, or email from address if this message + * was from an email gateway. Returns null if originating address + * unavailable. + */ + public String getDisplayOriginatingAddress() { + return mWrappedSmsMessage.getDisplayOriginatingAddress(); + } + + /** + * Returns the message body as a String, if it exists and is text based. + * @return message body is there is one, otherwise null + */ + public String getMessageBody() { + return mWrappedSmsMessage.getMessageBody(); + } + + /** + * Returns the class of this message. + */ + public MessageClass getMessageClass() { + switch(mWrappedSmsMessage.getMessageClass()) { + case CLASS_0: return MessageClass.CLASS_0; + case CLASS_1: return MessageClass.CLASS_1; + case CLASS_2: return MessageClass.CLASS_2; + case CLASS_3: return MessageClass.CLASS_3; + default: return MessageClass.UNKNOWN; + + } + } + + /** + * Returns the message body, or email message body if this message was from + * an email gateway. Returns null if message body unavailable. + */ + public String getDisplayMessageBody() { + return mWrappedSmsMessage.getDisplayMessageBody(); + } + + /** + * Unofficial convention of a subject line enclosed in parens empty string + * if not present + */ + public String getPseudoSubject() { + return mWrappedSmsMessage.getPseudoSubject(); + } + + /** + * Returns the service centre timestamp in currentTimeMillis() format + */ + public long getTimestampMillis() { + return mWrappedSmsMessage.getTimestampMillis(); + } + + /** + * Returns true if message is an email. + * + * @return true if this message came through an email gateway and email + * sender / subject / parsed body are available + */ + public boolean isEmail() { + return mWrappedSmsMessage.isEmail(); + } + + /** + * @return if isEmail() is true, body of the email sent through the gateway. + * null otherwise + */ + public String getEmailBody() { + return mWrappedSmsMessage.getEmailBody(); + } + + /** + * @return if isEmail() is true, email from address of email sent through + * the gateway. null otherwise + */ + public String getEmailFrom() { + return mWrappedSmsMessage.getEmailFrom(); + } + + /** + * Get protocol identifier. + */ + public int getProtocolIdentifier() { + return mWrappedSmsMessage.getProtocolIdentifier(); + } + + /** + * See TS 23.040 9.2.3.9 returns true if this is a "replace short message" + * SMS + */ + public boolean isReplace() { + return mWrappedSmsMessage.isReplace(); + } + + /** + * Returns true for CPHS MWI toggle message. + * + * @return true if this is a CPHS MWI toggle message See CPHS 4.2 section + * B.4.2 + */ + public boolean isCphsMwiMessage() { + return mWrappedSmsMessage.isCphsMwiMessage(); + } + + /** + * returns true if this message is a CPHS voicemail / message waiting + * indicator (MWI) clear message + */ + public boolean isMWIClearMessage() { + return mWrappedSmsMessage.isMWIClearMessage(); + } + + /** + * returns true if this message is a CPHS voicemail / message waiting + * indicator (MWI) set message + */ + public boolean isMWISetMessage() { + return mWrappedSmsMessage.isMWISetMessage(); + } + + /** + * returns true if this message is a "Message Waiting Indication Group: + * Discard Message" notification and should not be stored. + */ + public boolean isMwiDontStore() { + return mWrappedSmsMessage.isMwiDontStore(); + } + + /** + * returns the user data section minus the user data header if one was + * present. + */ + public byte[] getUserData() { + return mWrappedSmsMessage.getUserData(); + } + + /** + * Returns the raw PDU for the message. + * + * @return the raw PDU for the message. + */ + public byte[] getPdu() { + return mWrappedSmsMessage.getPdu(); + } + + /** + * Returns the status of the message on the SIM (read, unread, sent, unsent). + * + * @return the status of the message on the SIM. These are: + * SmsManager.STATUS_ON_SIM_FREE + * SmsManager.STATUS_ON_SIM_READ + * SmsManager.STATUS_ON_SIM_UNREAD + * SmsManager.STATUS_ON_SIM_SEND + * SmsManager.STATUS_ON_SIM_UNSENT + * @deprecated Use getStatusOnIcc instead. + */ + @Deprecated public int getStatusOnSim() { + return mWrappedSmsMessage.getStatusOnIcc(); + } + + /** + * Returns the status of the message on the ICC (read, unread, sent, unsent). + * + * @return the status of the message on the ICC. These are: + * SmsManager.STATUS_ON_ICC_FREE + * SmsManager.STATUS_ON_ICC_READ + * SmsManager.STATUS_ON_ICC_UNREAD + * SmsManager.STATUS_ON_ICC_SEND + * SmsManager.STATUS_ON_ICC_UNSENT + */ + public int getStatusOnIcc() { + return mWrappedSmsMessage.getStatusOnIcc(); + } + + /** + * Returns the record index of the message on the SIM (1-based index). + * @return the record index of the message on the SIM, or -1 if this + * SmsMessage was not created from a SIM SMS EF record. + * @deprecated Use getIndexOnIcc instead. + */ + @Deprecated public int getIndexOnSim() { + return mWrappedSmsMessage.getIndexOnIcc(); + } + + /** + * Returns the record index of the message on the ICC (1-based index). + * @return the record index of the message on the ICC, or -1 if this + * SmsMessage was not created from a ICC SMS EF record. + */ + public int getIndexOnIcc() { + return mWrappedSmsMessage.getIndexOnIcc(); + } + + /** + * GSM: + * For an SMS-STATUS-REPORT message, this returns the status field from + * the status report. This field indicates the status of a previously + * submitted SMS, if requested. See TS 23.040, 9.2.3.15 TP-Status for a + * description of values. + * CDMA: + * For not interfering with status codes from GSM, the value is + * shifted to the bits 31-16. + * The value is composed of an error class (bits 25-24) and a status code (bits 23-16). + * Possible codes are described in C.S0015-B, v2.0, 4.5.21. + * + * @return 0 indicates the previously sent message was received. + * See TS 23.040, 9.9.2.3.15 and C.S0015-B, v2.0, 4.5.21 + * for a description of other possible values. + */ + public int getStatus() { + return mWrappedSmsMessage.getStatus(); + } + + /** + * Return true iff the message is a SMS-STATUS-REPORT message. + */ + public boolean isStatusReportMessage() { + return mWrappedSmsMessage.isStatusReportMessage(); + } + + /** + * Returns true iff the TP-Reply-Path bit is set in + * this message. + */ + public boolean isReplyPathPresent() { + return mWrappedSmsMessage.isReplyPathPresent(); + } +} diff --git a/src/java/android/telephony/gsm/SmsManager.java b/src/java/android/telephony/gsm/SmsManager.java new file mode 100644 index 0000000..3b75298 --- /dev/null +++ b/src/java/android/telephony/gsm/SmsManager.java @@ -0,0 +1,261 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.telephony.gsm; + +import android.app.PendingIntent; + +import java.util.ArrayList; + + +/** + * Manages SMS operations such as sending data, text, and pdu SMS messages. + * Get this object by calling the static method SmsManager.getDefault(). + * @deprecated Replaced by android.telephony.SmsManager that supports both GSM and CDMA. + */ +@Deprecated public final class SmsManager { + private static SmsManager sInstance; + private android.telephony.SmsManager mSmsMgrProxy; + + /** Get the default instance of the SmsManager + * + * @return the default instance of the SmsManager + * @deprecated Use android.telephony.SmsManager. + */ + @Deprecated + public static final SmsManager getDefault() { + if (sInstance == null) { + sInstance = new SmsManager(); + } + return sInstance; + } + + @Deprecated + private SmsManager() { + mSmsMgrProxy = android.telephony.SmsManager.getDefault(); + } + + /** + * Send a text based SMS. + * + * @param destinationAddress the address to send the message to + * @param scAddress is the service center address or null to use + * the current default SMSC + * @param text the body of the message to send + * @param sentIntent if not NULL this PendingIntent is + * broadcast when the message is successfully sent, or failed. + * The result code will be Activity.RESULT_OK for success, + * or one of these errors: + * RESULT_ERROR_GENERIC_FAILURE + * RESULT_ERROR_RADIO_OFF + * RESULT_ERROR_NULL_PDU. + * The per-application based SMS control checks sentIntent. If sentIntent + * is NULL the caller will be checked against all unknown applications, + * which cause smaller number of SMS to be sent in checking period. + * @param deliveryIntent if not NULL this PendingIntent is + * broadcast when the message is delivered to the recipient. The + * raw pdu of the status report is in the extended data ("pdu"). + * + * @throws IllegalArgumentException if destinationAddress or text are empty + * @deprecated Use android.telephony.SmsManager. + */ + @Deprecated + public final void sendTextMessage( + String destinationAddress, String scAddress, String text, + PendingIntent sentIntent, PendingIntent deliveryIntent) { + mSmsMgrProxy.sendTextMessage(destinationAddress, scAddress, text, + sentIntent, deliveryIntent); + } + + /** + * Divide a text message into several messages, none bigger than + * the maximum SMS message size. + * + * @param text the original message. Must not be null. + * @return an ArrayList of strings that, in order, + * comprise the original message + * @deprecated Use android.telephony.SmsManager. + */ + @Deprecated + public final ArrayList divideMessage(String text) { + return mSmsMgrProxy.divideMessage(text); + } + + /** + * Send a multi-part text based SMS. The callee should have already + * divided the message into correctly sized parts by calling + * divideMessage. + * + * @param destinationAddress the address to send the message to + * @param scAddress is the service center address or null to use + * the current default SMSC + * @param parts an ArrayList of strings that, in order, + * comprise the original message + * @param sentIntents if not null, an ArrayList of + * PendingIntents (one for each message part) that is + * broadcast when the corresponding message part has been sent. + * The result code will be Activity.RESULT_OK for success, + * or one of these errors: + * RESULT_ERROR_GENERIC_FAILURE + * RESULT_ERROR_RADIO_OFF + * RESULT_ERROR_NULL_PDU. + * The per-application based SMS control checks sentIntent. If sentIntent + * is NULL the caller will be checked against all unknown applicaitons, + * which cause smaller number of SMS to be sent in checking period. + * @param deliveryIntents if not null, an ArrayList of + * PendingIntents (one for each message part) that is + * broadcast when the corresponding message part has been delivered + * to the recipient. The raw pdu of the status report is in the + * extended data ("pdu"). + * + * @throws IllegalArgumentException if destinationAddress or data are empty + * @deprecated Use android.telephony.SmsManager. + */ + @Deprecated + public final void sendMultipartTextMessage( + String destinationAddress, String scAddress, ArrayList parts, + ArrayList sentIntents, ArrayList deliveryIntents) { + mSmsMgrProxy.sendMultipartTextMessage(destinationAddress, scAddress, parts, + sentIntents, deliveryIntents); + } + + /** + * Send a data based SMS to a specific application port. + * + * @param destinationAddress the address to send the message to + * @param scAddress is the service center address or null to use + * the current default SMSC + * @param destinationPort the port to deliver the message to + * @param data the body of the message to send + * @param sentIntent if not NULL this PendingIntent is + * broadcast when the message is sucessfully sent, or failed. + * The result code will be Activity.RESULT_OK for success, + * or one of these errors: + * RESULT_ERROR_GENERIC_FAILURE + * RESULT_ERROR_RADIO_OFF + * RESULT_ERROR_NULL_PDU. + * The per-application based SMS control checks sentIntent. If sentIntent + * is NULL the caller will be checked against all unknown applicaitons, + * which cause smaller number of SMS to be sent in checking period. + * @param deliveryIntent if not NULL this PendingIntent is + * broadcast when the message is delivered to the recipient. The + * raw pdu of the status report is in the extended data ("pdu"). + * + * @throws IllegalArgumentException if destinationAddress or data are empty + * @deprecated Use android.telephony.SmsManager. + */ + @Deprecated + public final void sendDataMessage( + String destinationAddress, String scAddress, short destinationPort, + byte[] data, PendingIntent sentIntent, PendingIntent deliveryIntent) { + mSmsMgrProxy.sendDataMessage(destinationAddress, scAddress, destinationPort, + data, sentIntent, deliveryIntent); + } + + /** + * Copy a raw SMS PDU to the SIM. + * + * @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_SIM_READ, STATUS_ON_SIM_UNREAD, + * STATUS_ON_SIM_SENT, STATUS_ON_SIM_UNSENT) + * @return true for success + * @deprecated Use android.telephony.SmsManager. + * {@hide} + */ + @Deprecated + public final boolean copyMessageToSim(byte[] smsc, byte[] pdu, int status) { + return mSmsMgrProxy.copyMessageToIcc(smsc, pdu, status); + } + + /** + * Delete the specified message from the SIM. + * + * @param messageIndex is the record index of the message on SIM + * @return true for success + * @deprecated Use android.telephony.SmsManager. + * {@hide} + */ + @Deprecated + public final boolean deleteMessageFromSim(int messageIndex) { + return mSmsMgrProxy.deleteMessageFromIcc(messageIndex); + } + + /** + * Update the specified message on the SIM. + * + * @param messageIndex record index of message to update + * @param newStatus new message status (STATUS_ON_SIM_READ, + * STATUS_ON_SIM_UNREAD, STATUS_ON_SIM_SENT, + * STATUS_ON_SIM_UNSENT, STATUS_ON_SIM_FREE) + * @param pdu the raw PDU to store + * @return true for success + * @deprecated Use android.telephony.SmsManager. + * {@hide} + */ + @Deprecated + public final boolean updateMessageOnSim(int messageIndex, int newStatus, byte[] pdu) { + return mSmsMgrProxy.updateMessageOnIcc(messageIndex, newStatus, pdu); + } + + /** + * Retrieves all messages currently stored on SIM. + * @return ArrayList of SmsMessage objects + * @deprecated Use android.telephony.SmsManager. + * {@hide} + */ + @Deprecated + public final ArrayList getAllMessagesFromSim() { + return mSmsMgrProxy.getAllMessagesFromIcc(); + } + + /** Free space (TS 51.011 10.5.3). + * @deprecated Use android.telephony.SmsManager. */ + @Deprecated static public final int STATUS_ON_SIM_FREE = 0; + + /** Received and read (TS 51.011 10.5.3). + * @deprecated Use android.telephony.SmsManager. */ + @Deprecated static public final int STATUS_ON_SIM_READ = 1; + + /** Received and unread (TS 51.011 10.5.3). + * @deprecated Use android.telephony.SmsManager. */ + @Deprecated static public final int STATUS_ON_SIM_UNREAD = 3; + + /** Stored and sent (TS 51.011 10.5.3). + * @deprecated Use android.telephony.SmsManager. */ + @Deprecated static public final int STATUS_ON_SIM_SENT = 5; + + /** Stored and unsent (TS 51.011 10.5.3). + * @deprecated Use android.telephony.SmsManager. */ + @Deprecated static public final int STATUS_ON_SIM_UNSENT = 7; + + /** Generic failure cause + * @deprecated Use android.telephony.SmsManager. */ + @Deprecated static public final int RESULT_ERROR_GENERIC_FAILURE = 1; + + /** Failed because radio was explicitly turned off + * @deprecated Use android.telephony.SmsManager. */ + @Deprecated static public final int RESULT_ERROR_RADIO_OFF = 2; + + /** Failed because no pdu provided + * @deprecated Use android.telephony.SmsManager. */ + @Deprecated static public final int RESULT_ERROR_NULL_PDU = 3; + + /** Failed because service is currently unavailable + * @deprecated Use android.telephony.SmsManager. */ + @Deprecated static public final int RESULT_ERROR_NO_SERVICE = 4; + +} diff --git a/src/java/android/telephony/gsm/SmsMessage.java b/src/java/android/telephony/gsm/SmsMessage.java new file mode 100644 index 0000000..7a814c3 --- /dev/null +++ b/src/java/android/telephony/gsm/SmsMessage.java @@ -0,0 +1,628 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.telephony.gsm; + +import android.os.Parcel; +import android.telephony.TelephonyManager; + +import com.android.internal.telephony.GsmAlphabet; +import com.android.internal.telephony.EncodeException; +import com.android.internal.telephony.SmsHeader; +import com.android.internal.telephony.SmsMessageBase; +import com.android.internal.telephony.SmsMessageBase.SubmitPduBase; + +import java.util.Arrays; + +import static android.telephony.TelephonyManager.PHONE_TYPE_CDMA; + + +/** + * A Short Message Service message. + * @deprecated Replaced by android.telephony.SmsMessage that supports both GSM and CDMA. + */ +@Deprecated +public class SmsMessage { + private static final boolean LOCAL_DEBUG = true; + private static final String LOG_TAG = "SMS"; + + /** + * SMS Class enumeration. + * See TS 23.038. + * @deprecated Use android.telephony.SmsMessage. + */ + @Deprecated + public enum MessageClass{ + UNKNOWN, CLASS_0, CLASS_1, CLASS_2, CLASS_3; + } + + /** Unknown encoding scheme (see TS 23.038) + * @deprecated Use android.telephony.SmsMessage. + */ + @Deprecated public static final int ENCODING_UNKNOWN = 0; + + /** 7-bit encoding scheme (see TS 23.038) + * @deprecated Use android.telephony.SmsMessage. + */ + @Deprecated public static final int ENCODING_7BIT = 1; + + /** 8-bit encoding scheme (see TS 23.038) + * @deprecated Use android.telephony.SmsMessage. + */ + @Deprecated public static final int ENCODING_8BIT = 2; + + /** 16-bit encoding scheme (see TS 23.038) + * @deprecated Use android.telephony.SmsMessage. + */ + @Deprecated public static final int ENCODING_16BIT = 3; + + /** The maximum number of payload bytes per message + * @deprecated Use android.telephony.SmsMessage. + */ + @Deprecated public static final int MAX_USER_DATA_BYTES = 140; + + /** + * The maximum number of payload bytes per message if a user data header + * is present. This assumes the header only contains the + * CONCATENATED_8_BIT_REFERENCE element. + * + * @deprecated Use android.telephony.SmsMessage. + * @hide pending API Council approval to extend the public API + */ + @Deprecated public static final int MAX_USER_DATA_BYTES_WITH_HEADER = 134; + + /** The maximum number of payload septets per message + * @deprecated Use android.telephony.SmsMessage. + */ + @Deprecated public static final int MAX_USER_DATA_SEPTETS = 160; + + /** + * The maximum number of payload septets per message if a user data header + * is present. This assumes the header only contains the + * CONCATENATED_8_BIT_REFERENCE element. + * @deprecated Use android.telephony.SmsMessage. + */ + @Deprecated public static final int MAX_USER_DATA_SEPTETS_WITH_HEADER = 153; + + /** Contains actual SmsMessage. Only public for debugging and for framework layer. + * @deprecated Use android.telephony.SmsMessage. + * {@hide} + */ + @Deprecated public SmsMessageBase mWrappedSmsMessage; + + /** @deprecated Use android.telephony.SmsMessage. */ + @Deprecated + public static class SubmitPdu { + /** @deprecated Use android.telephony.SmsMessage. */ + @Deprecated public byte[] encodedScAddress; // Null if not applicable. + /** @deprecated Use android.telephony.SmsMessage. */ + @Deprecated public byte[] encodedMessage; + + //Constructor + /** @deprecated Use android.telephony.SmsMessage. */ + @Deprecated + public SubmitPdu() { + } + + /** @deprecated Use android.telephony.SmsMessage. + * {@hide} + */ + @Deprecated + protected SubmitPdu(SubmitPduBase spb) { + this.encodedMessage = spb.encodedMessage; + this.encodedScAddress = spb.encodedScAddress; + } + + /** @deprecated Use android.telephony.SmsMessage. */ + @Deprecated + public String toString() { + return "SubmitPdu: encodedScAddress = " + + Arrays.toString(encodedScAddress) + + ", encodedMessage = " + + Arrays.toString(encodedMessage); + } + } + + // Constructor + /** @deprecated Use android.telephony.SmsMessage. */ + @Deprecated + public SmsMessage() { + this(getSmsFacility()); + } + + private SmsMessage(SmsMessageBase smb) { + mWrappedSmsMessage = smb; + } + + /** + * Create an SmsMessage from a raw PDU. + * @deprecated Use android.telephony.SmsMessage. + */ + @Deprecated + public static SmsMessage createFromPdu(byte[] pdu) { + SmsMessageBase wrappedMessage; + int activePhone = TelephonyManager.getDefault().getCurrentPhoneType(); + + if (PHONE_TYPE_CDMA == activePhone) { + wrappedMessage = com.android.internal.telephony.cdma.SmsMessage.createFromPdu(pdu); + } else { + wrappedMessage = com.android.internal.telephony.gsm.SmsMessage.createFromPdu(pdu); + } + + return new SmsMessage(wrappedMessage); + } + + /** + * Get the TP-Layer-Length for the given SMS-SUBMIT PDU Basically, the + * length in bytes (not hex chars) less the SMSC header + * @deprecated Use android.telephony.SmsMessage. + */ + @Deprecated + public static int getTPLayerLengthForPDU(String pdu) { + int activePhone = TelephonyManager.getDefault().getCurrentPhoneType(); + + if (PHONE_TYPE_CDMA == activePhone) { + return com.android.internal.telephony.cdma.SmsMessage.getTPLayerLengthForPDU(pdu); + } else { + return com.android.internal.telephony.gsm.SmsMessage.getTPLayerLengthForPDU(pdu); + } + } + + /** + * Calculates the number of SMS's required to encode the message body and + * the number of characters remaining until the next message, given the + * current encoding. + * + * @param messageBody the message to encode + * @param use7bitOnly if true, characters that are not part of the GSM + * alphabet are counted as a single space char. If false, a + * messageBody containing non-GSM alphabet characters is calculated + * for 16-bit encoding. + * @return an int[4] with int[0] being the number of SMS's required, int[1] + * the number of code units used, and int[2] is the number of code + * units remaining until the next message. int[3] is the encoding + * type that should be used for the message. + * @deprecated Use android.telephony.SmsMessage. + */ + @Deprecated + public static int[] calculateLength(CharSequence messageBody, boolean use7bitOnly) { + GsmAlphabet.TextEncodingDetails ted = + com.android.internal.telephony.gsm.SmsMessage + .calculateLength(messageBody, use7bitOnly); + int ret[] = new int[4]; + ret[0] = ted.msgCount; + ret[1] = ted.codeUnitCount; + ret[2] = ted.codeUnitsRemaining; + ret[3] = ted.codeUnitSize; + return ret; + } + + /** + * Calculates the number of SMS's required to encode the message body and + * the number of characters remaining until the next message, given the + * current encoding. + * + * @param messageBody the message to encode + * @param use7bitOnly if true, characters that are not part of the GSM + * alphabet are counted as a single space char. If false, a + * messageBody containing non-GSM alphabet characters is calculated + * for 16-bit encoding. + * @return an int[4] with int[0] being the number of SMS's required, int[1] + * the number of code units used, and int[2] is the number of code + * units remaining until the next message. int[3] is the encoding + * type that should be used for the message. + * @deprecated Use android.telephony.SmsMessage. + */ + @Deprecated + public static int[] calculateLength(String messageBody, boolean use7bitOnly) { + return calculateLength((CharSequence)messageBody, use7bitOnly); + } + + /** + * Get an SMS-SUBMIT PDU for a destination address and a message + * + * @param scAddress Service Centre address. Null means use default. + * @return a SubmitPdu containing the encoded SC + * address, if applicable, and the encoded message. + * Returns null on encode error. + * @deprecated Use android.telephony.SmsMessage. + * @hide + */ + @Deprecated + public static SubmitPdu getSubmitPdu(String scAddress, + String destinationAddress, String message, + boolean statusReportRequested, byte[] header) { + SubmitPduBase spb; + int activePhone = TelephonyManager.getDefault().getCurrentPhoneType(); + + if (PHONE_TYPE_CDMA == activePhone) { + spb = com.android.internal.telephony.cdma.SmsMessage.getSubmitPdu(scAddress, + destinationAddress, message, statusReportRequested, + SmsHeader.fromByteArray(header)); + } else { + spb = com.android.internal.telephony.gsm.SmsMessage.getSubmitPdu(scAddress, + destinationAddress, message, statusReportRequested, header); + } + + return new SubmitPdu(spb); + } + + /** + * Get an SMS-SUBMIT PDU for a destination address and a message + * + * @param scAddress Service Centre address. Null means use default. + * @return a SubmitPdu containing the encoded SC + * address, if applicable, and the encoded message. + * Returns null on encode error. + * @deprecated Use android.telephony.SmsMessage. + */ + @Deprecated + public static SubmitPdu getSubmitPdu(String scAddress, + String destinationAddress, String message, boolean statusReportRequested) { + SubmitPduBase spb; + int activePhone = TelephonyManager.getDefault().getCurrentPhoneType(); + + if (PHONE_TYPE_CDMA == activePhone) { + spb = com.android.internal.telephony.cdma.SmsMessage.getSubmitPdu(scAddress, + destinationAddress, message, statusReportRequested, null); + } else { + spb = com.android.internal.telephony.gsm.SmsMessage.getSubmitPdu(scAddress, + destinationAddress, message, statusReportRequested); + } + + return new SubmitPdu(spb); + } + + /** + * Get an SMS-SUBMIT PDU for a data message to a destination address & 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 dat for the message + * @return a SubmitPdu containing the encoded SC + * address, if applicable, and the encoded message. + * Returns null on encode error. + * @deprecated Use android.telephony.SmsMessage. + */ + @Deprecated + public static SubmitPdu getSubmitPdu(String scAddress, + String destinationAddress, short destinationPort, byte[] data, + boolean statusReportRequested) { + SubmitPduBase spb; + int activePhone = TelephonyManager.getDefault().getCurrentPhoneType(); + + if (PHONE_TYPE_CDMA == activePhone) { + spb = com.android.internal.telephony.cdma.SmsMessage.getSubmitPdu(scAddress, + destinationAddress, destinationPort, data, statusReportRequested); + } else { + spb = com.android.internal.telephony.gsm.SmsMessage.getSubmitPdu(scAddress, + destinationAddress, destinationPort, data, statusReportRequested); + } + + return new SubmitPdu(spb); + } + + /** + * Returns the address of the SMS service center that relayed this message + * or null if there is none. + * @deprecated Use android.telephony.SmsMessage. + */ + @Deprecated + public String getServiceCenterAddress() { + return mWrappedSmsMessage.getServiceCenterAddress(); + } + + /** + * Returns the originating address (sender) of this SMS message in String + * form or null if unavailable + * @deprecated Use android.telephony.SmsMessage. + */ + @Deprecated + public String getOriginatingAddress() { + return mWrappedSmsMessage.getOriginatingAddress(); + } + + /** + * Returns the originating address, or email from address if this message + * was from an email gateway. Returns null if originating address + * unavailable. + * @deprecated Use android.telephony.SmsMessage. + */ + @Deprecated + public String getDisplayOriginatingAddress() { + return mWrappedSmsMessage.getDisplayOriginatingAddress(); + } + + /** + * Returns the message body as a String, if it exists and is text based. + * @return message body is there is one, otherwise null + * @deprecated Use android.telephony.SmsMessage. + */ + @Deprecated + public String getMessageBody() { + return mWrappedSmsMessage.getMessageBody(); + } + + /** + * Returns the class of this message. + * @deprecated Use android.telephony.SmsMessage. + */ + @Deprecated + public MessageClass getMessageClass() { + int index = mWrappedSmsMessage.getMessageClass().ordinal(); + + return MessageClass.values()[index]; + } + + /** + * Returns the message body, or email message body if this message was from + * an email gateway. Returns null if message body unavailable. + * @deprecated Use android.telephony.SmsMessage. + */ + @Deprecated + public String getDisplayMessageBody() { + return mWrappedSmsMessage.getDisplayMessageBody(); + } + + /** + * Unofficial convention of a subject line enclosed in parens empty string + * if not present + * @deprecated Use android.telephony.SmsMessage. + */ + @Deprecated + public String getPseudoSubject() { + return mWrappedSmsMessage.getPseudoSubject(); + } + + /** + * Returns the service centre timestamp in currentTimeMillis() format + * @deprecated Use android.telephony.SmsMessage. + */ + @Deprecated + public long getTimestampMillis() { + return mWrappedSmsMessage.getTimestampMillis(); + } + + /** + * Returns true if message is an email. + * + * @return true if this message came through an email gateway and email + * sender / subject / parsed body are available + * @deprecated Use android.telephony.SmsMessage. + */ + @Deprecated + public boolean isEmail() { + return mWrappedSmsMessage.isEmail(); + } + + /** + * @return if isEmail() is true, body of the email sent through the gateway. + * null otherwise + * @deprecated Use android.telephony.SmsMessage. + */ + @Deprecated + public String getEmailBody() { + return mWrappedSmsMessage.getEmailBody(); + } + + /** + * @return if isEmail() is true, email from address of email sent through + * the gateway. null otherwise + * @deprecated Use android.telephony.SmsMessage. + */ + @Deprecated + public String getEmailFrom() { + return mWrappedSmsMessage.getEmailFrom(); + } + + /** + * Get protocol identifier. + * @deprecated Use android.telephony.SmsMessage. + */ + @Deprecated + public int getProtocolIdentifier() { + return mWrappedSmsMessage.getProtocolIdentifier(); + } + + /** + * See TS 23.040 9.2.3.9 returns true if this is a "replace short message" SMS + * @deprecated Use android.telephony.SmsMessage. + */ + @Deprecated + public boolean isReplace() { + return mWrappedSmsMessage.isReplace(); + } + + /** + * Returns true for CPHS MWI toggle message. + * + * @return true if this is a CPHS MWI toggle message See CPHS 4.2 section B.4.2 + * @deprecated Use android.telephony.SmsMessage. + */ + @Deprecated + public boolean isCphsMwiMessage() { + return mWrappedSmsMessage.isCphsMwiMessage(); + } + + /** + * returns true if this message is a CPHS voicemail / message waiting + * indicator (MWI) clear message + * @deprecated Use android.telephony.SmsMessage. + */ + @Deprecated + public boolean isMWIClearMessage() { + return mWrappedSmsMessage.isMWIClearMessage(); + } + + /** + * returns true if this message is a CPHS voicemail / message waiting + * indicator (MWI) set message + * @deprecated Use android.telephony.SmsMessage. + */ + @Deprecated + public boolean isMWISetMessage() { + return mWrappedSmsMessage.isMWISetMessage(); + } + + /** + * returns true if this message is a "Message Waiting Indication Group: + * Discard Message" notification and should not be stored. + * @deprecated Use android.telephony.SmsMessage. + */ + @Deprecated + public boolean isMwiDontStore() { + return mWrappedSmsMessage.isMwiDontStore(); + } + + /** + * returns the user data section minus the user data header if one was present. + * @deprecated Use android.telephony.SmsMessage. + */ + @Deprecated + public byte[] getUserData() { + return mWrappedSmsMessage.getUserData(); + } + + /* Not part of the SDK interface and only needed by specific classes: + protected SmsHeader getUserDataHeader() + */ + + /** + * Returns the raw PDU for the message. + * + * @return the raw PDU for the message. + * @deprecated Use android.telephony.SmsMessage. + */ + @Deprecated + public byte[] getPdu() { + return mWrappedSmsMessage.getPdu(); + } + + /** + * Returns the status of the message on the SIM (read, unread, sent, unsent). + * + * @return the status of the message on the SIM. These are: + * SmsManager.STATUS_ON_SIM_FREE + * SmsManager.STATUS_ON_SIM_READ + * SmsManager.STATUS_ON_SIM_UNREAD + * SmsManager.STATUS_ON_SIM_SEND + * SmsManager.STATUS_ON_SIM_UNSENT + * @deprecated Use android.telephony.SmsMessage and getStatusOnIcc instead. + */ + @Deprecated + public int getStatusOnSim() { + return mWrappedSmsMessage.getStatusOnIcc(); + } + + /** + * Returns the status of the message on the ICC (read, unread, sent, unsent). + * + * @return the status of the message on the ICC. These are: + * SmsManager.STATUS_ON_ICC_FREE + * SmsManager.STATUS_ON_ICC_READ + * SmsManager.STATUS_ON_ICC_UNREAD + * SmsManager.STATUS_ON_ICC_SEND + * SmsManager.STATUS_ON_ICC_UNSENT + * @deprecated Use android.telephony.SmsMessage. + * @hide + */ + @Deprecated + public int getStatusOnIcc() { + + return mWrappedSmsMessage.getStatusOnIcc(); + } + + /** + * Returns the record index of the message on the SIM (1-based index). + * @return the record index of the message on the SIM, or -1 if this + * SmsMessage was not created from a SIM SMS EF record. + * @deprecated Use android.telephony.SmsMessage and getIndexOnIcc instead. + */ + @Deprecated + public int getIndexOnSim() { + return mWrappedSmsMessage.getIndexOnIcc(); + } + + /** + * Returns the record index of the message on the ICC (1-based index). + * @return the record index of the message on the ICC, or -1 if this + * SmsMessage was not created from a ICC SMS EF record. + * @deprecated Use android.telephony.SmsMessage. + * @hide + */ + @Deprecated + public int getIndexOnIcc() { + + return mWrappedSmsMessage.getIndexOnIcc(); + } + + /** + * GSM: + * For an SMS-STATUS-REPORT message, this returns the status field from + * the status report. This field indicates the status of a previously + * submitted SMS, if requested. See TS 23.040, 9.2.3.15 TP-Status for a + * description of values. + * CDMA: + * For not interfering with status codes from GSM, the value is + * shifted to the bits 31-16. + * The value is composed of an error class (bits 25-24) and a status code (bits 23-16). + * Possible codes are described in C.S0015-B, v2.0, 4.5.21. + * + * @return 0 indicates the previously sent message was received. + * See TS 23.040, 9.9.2.3.15 and C.S0015-B, v2.0, 4.5.21 + * for a description of other possible values. + * @deprecated Use android.telephony.SmsMessage. + */ + @Deprecated + public int getStatus() { + return mWrappedSmsMessage.getStatus(); + } + + /** + * Return true iff the message is a SMS-STATUS-REPORT message. + * @deprecated Use android.telephony.SmsMessage. + */ + @Deprecated + public boolean isStatusReportMessage() { + return mWrappedSmsMessage.isStatusReportMessage(); + } + + /** + * Returns true iff the TP-Reply-Path bit is set in + * this message. + * @deprecated Use android.telephony.SmsMessage. + */ + @Deprecated + public boolean isReplyPathPresent() { + return mWrappedSmsMessage.isReplyPathPresent(); + } + + /** This method returns the reference to a specific + * SmsMessage object, which is used for accessing its static methods. + * @return Specific SmsMessage. + * @deprecated Use android.telephony.SmsMessage. + */ + private static final SmsMessageBase getSmsFacility(){ + int activePhone = TelephonyManager.getDefault().getCurrentPhoneType(); + if (PHONE_TYPE_CDMA == activePhone) { + return new com.android.internal.telephony.cdma.SmsMessage(); + } else { + return new com.android.internal.telephony.gsm.SmsMessage(); + } + } +} -- cgit v1.1