From 3e3c3f80a90b156ff500076f8655647dfb317acf Mon Sep 17 00:00:00 2001 From: Jake Hamby Date: Mon, 6 Feb 2012 14:53:43 -0800 Subject: Add support for CMAS warning notifications over CDMA. Refactor SMS Cell Broadcast support to enable receiving CMAS warning notifications over CDMA. The CellBroadcastReceiver app must also be updated with the corresponding change. All cell broadcasts are now delivered as a Parcelable SmsCbMessage object in the "message" extra of the SMS_CB_RECEIVED_ACTION or SMS_EMERGENCY_CB_RECEIVED_ACTION, instead of as a GSM/UMTS "pdu" byte array. Existing functionality for ETWS and CMAS alerts over GSM/UMTS continues to be supported using the new radio-technology independent SmsCbMessage and related objects. Test cases are added to verify that valid and invalid broadcast data is handled appropriately. Unit testing discovered a bug in the BitwiseOutputStream utility class used by the added test cases. When the BitwiseOutputStream object must be expanded (in the private possExpand() method), the mEnd field is not updated to the new array size. This causes a new array to be allocated on every new write, and for all data beyond the original array allocation to be replaced with zeroes. Fixed by adding a line to possExpand() to update mEnd. Added a test case to BitwiseStreamsTest to verify the fix. Besides the test cases, BitwiseOutputStream is only used by BearerData in two places, both of which allocate a sufficient initial buffer. So the bug in BitwiseOutputStream is not critical to fix for normal operation, but should be fixed so that the test cases using it function correctly. Bug: 5856308 Change-Id: I201ecbf11607fd200aaae3cbb32561efabf65672 --- .../java/android/telephony/SmsCbCmasInfo.java | 308 +++++++++++ .../java/android/telephony/SmsCbConstants.java | 117 ---- .../java/android/telephony/SmsCbEtwsInfo.java | 206 +++++++ .../java/android/telephony/SmsCbLocation.java | 202 +++++++ telephony/java/android/telephony/SmsCbMessage.java | 603 +++++++++------------ .../telephony/cdma/CdmaSmsCbProgramData.java | 210 +++++++ 6 files changed, 1189 insertions(+), 457 deletions(-) create mode 100644 telephony/java/android/telephony/SmsCbCmasInfo.java delete mode 100644 telephony/java/android/telephony/SmsCbConstants.java create mode 100644 telephony/java/android/telephony/SmsCbEtwsInfo.java create mode 100644 telephony/java/android/telephony/SmsCbLocation.java create mode 100644 telephony/java/android/telephony/cdma/CdmaSmsCbProgramData.java (limited to 'telephony/java/android') diff --git a/telephony/java/android/telephony/SmsCbCmasInfo.java b/telephony/java/android/telephony/SmsCbCmasInfo.java new file mode 100644 index 000000000000..7a89d94ab2ef --- /dev/null +++ b/telephony/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/telephony/java/android/telephony/SmsCbConstants.java b/telephony/java/android/telephony/SmsCbConstants.java deleted file mode 100644 index a1b4adf19baf..000000000000 --- a/telephony/java/android/telephony/SmsCbConstants.java +++ /dev/null @@ -1,117 +0,0 @@ -/* - * 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; - -/** - * Constants used in SMS Cell Broadcast messages. - * - * {@hide} - */ -public interface SmsCbConstants { - /** Start of PWS Message Identifier range (includes ETWS and CMAS). */ - public static final int MESSAGE_ID_PWS_FIRST_IDENTIFIER = 0x1100; - - /** Bitmask for messages of ETWS type (including future extensions). */ - public static final int MESSAGE_ID_ETWS_TYPE_MASK = 0xFFF8; - - /** Value for messages of ETWS type after applying {@link #MESSAGE_ID_ETWS_TYPE_MASK}. */ - public static final int MESSAGE_ID_ETWS_TYPE = 0x1100; - - /** ETWS Message Identifier for earthquake warning message. */ - public static final int MESSAGE_ID_ETWS_EARTHQUAKE_WARNING = 0x1100; - - /** ETWS Message Identifier for tsunami warning message. */ - public static final int MESSAGE_ID_ETWS_TSUNAMI_WARNING = 0x1101; - - /** ETWS Message Identifier for earthquake and tsunami combined warning message. */ - public static final int MESSAGE_ID_ETWS_EARTHQUAKE_AND_TSUNAMI_WARNING = 0x1102; - - /** ETWS Message Identifier for test message. */ - public static final int MESSAGE_ID_ETWS_TEST_MESSAGE = 0x1103; - - /** ETWS Message Identifier for messages related to other emergency types. */ - public static final int MESSAGE_ID_ETWS_OTHER_EMERGENCY_TYPE = 0x1104; - - /** Start of CMAS Message Identifier range. */ - public static final int MESSAGE_ID_CMAS_FIRST_IDENTIFIER = 0x1112; - - /** CMAS Message Identifier for Presidential Level alerts. */ - public static final int MESSAGE_ID_CMAS_ALERT_PRESIDENTIAL_LEVEL = 0x1112; - - /** CMAS Message Identifier for Extreme alerts, Urgency=Immediate, Certainty=Observed. */ - public static final int MESSAGE_ID_CMAS_ALERT_EXTREME_IMMEDIATE_OBSERVED = 0x1113; - - /** CMAS Message Identifier for Extreme alerts, Urgency=Immediate, Certainty=Likely. */ - public static final int MESSAGE_ID_CMAS_ALERT_EXTREME_IMMEDIATE_LIKELY = 0x1114; - - /** CMAS Message Identifier for Extreme alerts, Urgency=Expected, Certainty=Observed. */ - public static final int MESSAGE_ID_CMAS_ALERT_EXTREME_EXPECTED_OBSERVED = 0x1115; - - /** CMAS Message Identifier for Extreme alerts, Urgency=Expected, Certainty=Likely. */ - public static final int MESSAGE_ID_CMAS_ALERT_EXTREME_EXPECTED_LIKELY = 0x1116; - - /** CMAS Message Identifier for Severe alerts, Urgency=Immediate, Certainty=Observed. */ - public static final int MESSAGE_ID_CMAS_ALERT_SEVERE_IMMEDIATE_OBSERVED = 0x1117; - - /** CMAS Message Identifier for Severe alerts, Urgency=Immediate, Certainty=Likely. */ - public static final int MESSAGE_ID_CMAS_ALERT_SEVERE_IMMEDIATE_LIKELY = 0x1118; - - /** CMAS Message Identifier for Severe alerts, Urgency=Expected, Certainty=Observed. */ - public static final int MESSAGE_ID_CMAS_ALERT_SEVERE_EXPECTED_OBSERVED = 0x1119; - - /** CMAS Message Identifier for Severe alerts, Urgency=Expected, Certainty=Likely. */ - public static final int MESSAGE_ID_CMAS_ALERT_SEVERE_EXPECTED_LIKELY = 0x111A; - - /** CMAS Message Identifier for Child Abduction Emergency (Amber Alert). */ - public static final int MESSAGE_ID_CMAS_ALERT_CHILD_ABDUCTION_EMERGENCY = 0x111B; - - /** CMAS Message Identifier for the Required Monthly Test. */ - public static final int MESSAGE_ID_CMAS_ALERT_REQUIRED_MONTHLY_TEST = 0x111C; - - /** CMAS Message Identifier for CMAS Exercise. */ - public static final int MESSAGE_ID_CMAS_ALERT_EXERCISE = 0x111D; - - /** CMAS Message Identifier for operator defined use. */ - public static final int MESSAGE_ID_CMAS_ALERT_OPERATOR_DEFINED_USE = 0x111E; - - /** End of CMAS Message Identifier range (including future extensions). */ - public static final int MESSAGE_ID_CMAS_LAST_IDENTIFIER = 0x112F; - - /** End of PWS Message Identifier range (includes ETWS, CMAS, and future extensions). */ - public static final int MESSAGE_ID_PWS_LAST_IDENTIFIER = 0x18FF; - - /** ETWS message code flag to activate the popup display. */ - public static final int MESSAGE_CODE_ETWS_ACTIVATE_POPUP = 0x100; - - /** ETWS message code flag to activate the emergency user alert. */ - public static final int MESSAGE_CODE_ETWS_EMERGENCY_USER_ALERT = 0x200; - - /** ETWS warning type value for earthquake. */ - public static final int ETWS_WARNING_TYPE_EARTHQUAKE = 0x00; - - /** ETWS warning type value for tsunami. */ - public static final int ETWS_WARNING_TYPE_TSUNAMI = 0x01; - - /** ETWS warning type value for earthquake and tsunami. */ - public static final int ETWS_WARNING_TYPE_EARTHQUAKE_AND_TSUNAMI = 0x02; - - /** ETWS warning type value for test broadcast. */ - public static final int ETWS_WARNING_TYPE_TEST = 0x03; - - /** ETWS warning type value for other notifications. */ - public static final int ETWS_WARNING_TYPE_OTHER = 0x04; -} diff --git a/telephony/java/android/telephony/SmsCbEtwsInfo.java b/telephony/java/android/telephony/SmsCbEtwsInfo.java new file mode 100644 index 000000000000..0890d528f866 --- /dev/null +++ b/telephony/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/telephony/java/android/telephony/SmsCbLocation.java b/telephony/java/android/telephony/SmsCbLocation.java new file mode 100644 index 000000000000..7b5bd0d4bb71 --- /dev/null +++ b/telephony/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/telephony/java/android/telephony/SmsCbMessage.java b/telephony/java/android/telephony/SmsCbMessage.java index 383e0f9c90c4..046bf8c700eb 100644 --- a/telephony/java/android/telephony/SmsCbMessage.java +++ b/telephony/java/android/telephony/SmsCbMessage.java @@ -16,444 +16,367 @@ package android.telephony; -import android.text.format.Time; -import android.util.Log; - -import com.android.internal.telephony.GsmAlphabet; -import com.android.internal.telephony.IccUtils; -import com.android.internal.telephony.gsm.SmsCbHeader; - -import java.io.UnsupportedEncodingException; +import android.os.Parcel; +import android.os.Parcelable; /** - * Describes an SMS-CB message. + * 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} + * @hide */ -public class SmsCbMessage { +public class SmsCbMessage implements Parcelable { - /** - * Cell wide immediate geographical scope - */ + 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 - */ + /** 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 - */ + /** Location / service area wide geographical scope (GSM/UMTS only). */ public static final int GEOGRAPHICAL_SCOPE_LA_WIDE = 2; - /** - * Cell wide geographical scope - */ + /** 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; + /** - * Create an instance of this class from a received PDU - * - * @param pdu PDU bytes - * @return An instance of this class, or null if invalid pdu + * 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. */ - public static SmsCbMessage createFromPdu(byte[] pdu) { - try { - return new SmsCbMessage(pdu); - } catch (IllegalArgumentException e) { - Log.w(LOG_TAG, "Failed parsing SMS-CB pdu", e); - return null; - } - } - - private static final String LOG_TAG = "SMSCB"; + private final int mSerialNumber; /** - * Languages in the 0000xxxx DCS group as defined in 3GPP TS 23.038, section 5. + * 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 static final String[] LANGUAGE_CODES_GROUP_0 = { - "de", "en", "it", "fr", "es", "nl", "sv", "da", "pt", "fi", "no", "el", "tr", "hu", - "pl", null - }; + private final SmsCbLocation mLocation; /** - * Languages in the 0010xxxx DCS group as defined in 3GPP TS 23.038, section 5. + * 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 static final String[] LANGUAGE_CODES_GROUP_2 = { - "cs", "he", "ar", "ru", "is", null, null, null, null, null, null, null, null, null, - null, null - }; + private final int mServiceCategory; + + /** Message language, as a two-character string, e.g. "en". */ + private final String mLanguage; - private static final char CARRIAGE_RETURN = 0x0d; + /** Message body, as a String. */ + private final String mBody; - private static final int PDU_BODY_PAGE_LENGTH = 82; + /** Message priority (including emergency priority). */ + private final int mPriority; - private SmsCbHeader mHeader; + /** ETWS warning notification information (ETWS warnings only). */ + private final SmsCbEtwsInfo mEtwsWarningInfo; - private String mLanguage; + /** CMAS warning notification information (CMAS warnings only). */ + private final SmsCbCmasInfo mCmasWarningInfo; - private String mBody; + /** + * 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; + } - /** Timestamp of ETWS primary notification with security. */ - private long mPrimaryNotificationTimestamp; + /** 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; - /** 43 byte digital signature of ETWS primary notification with security. */ - private byte[] mPrimaryNotificationDigitalSignature; + case 'C': + // unparcel CMAS warning information + mEtwsWarningInfo = null; + mCmasWarningInfo = new SmsCbCmasInfo(in); + break; - private SmsCbMessage(byte[] pdu) throws IllegalArgumentException { - mHeader = new SmsCbHeader(pdu); - if (mHeader.format == SmsCbHeader.FORMAT_ETWS_PRIMARY) { - mBody = "ETWS"; - // ETWS primary notification with security is 56 octets in length - if (pdu.length >= SmsCbHeader.PDU_LENGTH_ETWS) { - mPrimaryNotificationTimestamp = getTimestampMillis(pdu); - mPrimaryNotificationDigitalSignature = new byte[43]; - // digital signature starts after 6 byte header and 7 byte timestamp - System.arraycopy(pdu, 13, mPrimaryNotificationDigitalSignature, 0, 43); - } - } else { - parseBody(pdu); + default: + mEtwsWarningInfo = null; + mCmasWarningInfo = null; } } /** - * Return the geographical scope of this message, one of - * {@link #GEOGRAPHICAL_SCOPE_CELL_WIDE_IMMEDIATE}, - * {@link #GEOGRAPHICAL_SCOPE_PLMN_WIDE}, - * {@link #GEOGRAPHICAL_SCOPE_LA_WIDE}, - * {@link #GEOGRAPHICAL_SCOPE_CELL_WIDE} + * Flatten this object into a Parcel. * - * @return Geographical scope + * @param dest The Parcel in which the object should be written. + * @param flags Additional flags about how the object should be written (ignored). */ - public int getGeographicalScope() { - return mHeader.geographicalScope; + @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]; + } + }; + /** - * Get the ISO-639-1 language code for this message, or null if unspecified + * Return the geographical scope of this message (GSM/UMTS only). * - * @return Language code + * @return Geographical scope */ - public String getLanguageCode() { - return mLanguage; + public int getGeographicalScope() { + return mGeographicalScope; } /** - * Get the body of this message, or null if no body available + * 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 Body, or null + * @return the 16-bit CDMA message identifier or GSM/UMTS serial number */ - public String getMessageBody() { - return mBody; + public int getSerialNumber() { + return mSerialNumber; } /** - * Get the message identifier of this message (0-65535) + * 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 Message identifier + * @return the geographical location code for duplicate message detection */ - public int getMessageIdentifier() { - return mHeader.messageIdentifier; + public SmsCbLocation getLocation() { + return mLocation; } /** - * Get the message code of this message (0-1023) + * 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 Message code + * @return the radio technology specific service category */ - public int getMessageCode() { - return mHeader.messageCode; + public int getServiceCategory() { + return mServiceCategory; } /** - * Get the update number of this message (0-15) + * Get the ISO-639-1 language code for this message, or null if unspecified * - * @return Update number + * @return Language code */ - public int getUpdateNumber() { - return mHeader.updateNumber; + public String getLanguageCode() { + return mLanguage; } /** - * Get the format of this message. - * @return {@link SmsCbHeader#FORMAT_GSM}, {@link SmsCbHeader#FORMAT_UMTS}, or - * {@link SmsCbHeader#FORMAT_ETWS_PRIMARY} + * Get the body of this message, or null if no body available + * + * @return Body, or null */ - public int getMessageFormat() { - return mHeader.format; + public String getMessageBody() { + return mBody; } /** - * For ETWS primary notifications, return the emergency user alert flag. - * @return true to notify terminal to activate emergency user alert; false otherwise + * Get the message format ({@link #MESSAGE_FORMAT_3GPP} or {@link #MESSAGE_FORMAT_3GPP2}). + * @return an integer representing 3GPP or 3GPP2 message format */ - public boolean getEtwsEmergencyUserAlert() { - return mHeader.etwsEmergencyUserAlert; + public int getMessageFormat() { + return mMessageFormat; } /** - * For ETWS primary notifications, return the popup flag. - * @return true to notify terminal to activate display popup; false otherwise + * 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 boolean getEtwsPopup() { - return mHeader.etwsPopup; + public int getMessagePriority() { + return mPriority; } /** - * For ETWS primary notifications, return the warning type. - * @return a value such as {@link SmsCbConstants#ETWS_WARNING_TYPE_EARTHQUAKE} + * 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 int getEtwsWarningType() { - return mHeader.etwsWarningType; + public SmsCbEtwsInfo getEtwsWarningInfo() { + return mEtwsWarningInfo; } /** - * For ETWS primary notifications, return the Warning-Security-Information timestamp. - * @return a timestamp in System.currentTimeMillis() format. + * 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 long getEtwsSecurityTimestamp() { - return mPrimaryNotificationTimestamp; + public SmsCbCmasInfo getCmasWarningInfo() { + return mCmasWarningInfo; } /** - * For ETWS primary notifications, return the 43 byte digital signature. - * @return a byte array containing a copy of the digital signature + * Return whether this message is an emergency (PWS) message type. + * @return true if the message is a public warning notification; false otherwise */ - public byte[] getEtwsSecuritySignature() { - return mPrimaryNotificationDigitalSignature.clone(); + public boolean isEmergencyMessage() { + return mPriority == MESSAGE_PRIORITY_EMERGENCY; } /** - * Parse and unpack the body text according to the encoding in the DCS. - * After completing successfully this method will have assigned the body - * text into mBody, and optionally the language code into mLanguage - * - * @param pdu The pdu + * Return whether this message is an ETWS warning alert. + * @return true if the message is an ETWS warning notification; false otherwise */ - private void parseBody(byte[] pdu) { - int encoding; - boolean hasLanguageIndicator = false; - - // Extract encoding and language from DCS, as defined in 3gpp TS 23.038, - // section 5. - switch ((mHeader.dataCodingScheme & 0xf0) >> 4) { - case 0x00: - encoding = SmsMessage.ENCODING_7BIT; - mLanguage = LANGUAGE_CODES_GROUP_0[mHeader.dataCodingScheme & 0x0f]; - break; - - case 0x01: - hasLanguageIndicator = true; - if ((mHeader.dataCodingScheme & 0x0f) == 0x01) { - encoding = SmsMessage.ENCODING_16BIT; - } else { - encoding = SmsMessage.ENCODING_7BIT; - } - break; - - case 0x02: - encoding = SmsMessage.ENCODING_7BIT; - mLanguage = LANGUAGE_CODES_GROUP_2[mHeader.dataCodingScheme & 0x0f]; - break; - - case 0x03: - encoding = SmsMessage.ENCODING_7BIT; - break; - - case 0x04: - case 0x05: - switch ((mHeader.dataCodingScheme & 0x0c) >> 2) { - case 0x01: - encoding = SmsMessage.ENCODING_8BIT; - break; - - case 0x02: - encoding = SmsMessage.ENCODING_16BIT; - break; - - case 0x00: - default: - encoding = SmsMessage.ENCODING_7BIT; - break; - } - break; - - case 0x06: - case 0x07: - // Compression not supported - case 0x09: - // UDH structure not supported - case 0x0e: - // Defined by the WAP forum not supported - encoding = SmsMessage.ENCODING_UNKNOWN; - break; - - case 0x0f: - if (((mHeader.dataCodingScheme & 0x04) >> 2) == 0x01) { - encoding = SmsMessage.ENCODING_8BIT; - } else { - encoding = SmsMessage.ENCODING_7BIT; - } - break; - - default: - // Reserved values are to be treated as 7-bit - encoding = SmsMessage.ENCODING_7BIT; - break; - } - - if (mHeader.format == SmsCbHeader.FORMAT_UMTS) { - // Payload may contain multiple pages - int nrPages = pdu[SmsCbHeader.PDU_HEADER_LENGTH]; - - if (pdu.length < SmsCbHeader.PDU_HEADER_LENGTH + 1 + (PDU_BODY_PAGE_LENGTH + 1) - * nrPages) { - throw new IllegalArgumentException("Pdu length " + pdu.length + " does not match " - + nrPages + " pages"); - } - - StringBuilder sb = new StringBuilder(); - - for (int i = 0; i < nrPages; i++) { - // Each page is 82 bytes followed by a length octet indicating - // the number of useful octets within those 82 - int offset = SmsCbHeader.PDU_HEADER_LENGTH + 1 + (PDU_BODY_PAGE_LENGTH + 1) * i; - int length = pdu[offset + PDU_BODY_PAGE_LENGTH]; - - if (length > PDU_BODY_PAGE_LENGTH) { - throw new IllegalArgumentException("Page length " + length - + " exceeds maximum value " + PDU_BODY_PAGE_LENGTH); - } - - sb.append(unpackBody(pdu, encoding, offset, length, hasLanguageIndicator)); - } - mBody = sb.toString(); - } else { - // Payload is one single page - int offset = SmsCbHeader.PDU_HEADER_LENGTH; - int length = pdu.length - offset; - - mBody = unpackBody(pdu, encoding, offset, length, hasLanguageIndicator); - } + public boolean isEtwsMessage() { + return mEtwsWarningInfo != null; } /** - * Unpack body text from the pdu using the given encoding, position and - * length within the pdu - * - * @param pdu The pdu - * @param encoding The encoding, as derived from the DCS - * @param offset Position of the first byte to unpack - * @param length Number of bytes to unpack - * @param hasLanguageIndicator true if the body text is preceded by a - * language indicator. If so, this method will as a side-effect - * assign the extracted language code into mLanguage - * @return Body text + * Return whether this message is a CMAS warning alert. + * @return true if the message is a CMAS warning notification; false otherwise */ - private String unpackBody(byte[] pdu, int encoding, int offset, int length, - boolean hasLanguageIndicator) { - String body = null; - - switch (encoding) { - case SmsMessage.ENCODING_7BIT: - body = GsmAlphabet.gsm7BitPackedToString(pdu, offset, length * 8 / 7); - - if (hasLanguageIndicator && body != null && body.length() > 2) { - // Language is two GSM characters followed by a CR. - // The actual body text is offset by 3 characters. - mLanguage = body.substring(0, 2); - body = body.substring(3); - } - break; - - case SmsMessage.ENCODING_16BIT: - if (hasLanguageIndicator && pdu.length >= offset + 2) { - // Language is two GSM characters. - // The actual body text is offset by 2 bytes. - mLanguage = GsmAlphabet.gsm7BitPackedToString(pdu, offset, 2); - offset += 2; - length -= 2; - } - - try { - body = new String(pdu, offset, (length & 0xfffe), "utf-16"); - } catch (UnsupportedEncodingException e) { - // Eeeek - } - break; - - default: - break; - } - - if (body != null) { - // Remove trailing carriage return - for (int i = body.length() - 1; i >= 0; i--) { - if (body.charAt(i) != CARRIAGE_RETURN) { - body = body.substring(0, i + 1); - break; - } - } - } else { - body = ""; - } - - return body; + public boolean isCmasMessage() { + return mCmasWarningInfo != null; } - /** - * Parses an ETWS primary notification timestamp and returns a currentTimeMillis()-style - * timestamp. Copied from com.android.internal.telephony.gsm.SmsMessage. - * @param pdu the ETWS primary notification PDU to decode - * @return the UTC timestamp from the Warning-Security-Information parameter - */ - private long getTimestampMillis(byte[] pdu) { - // Timestamp starts after CB header, in pdu[6] - int year = IccUtils.gsmBcdByteToInt(pdu[6]); - int month = IccUtils.gsmBcdByteToInt(pdu[7]); - int day = IccUtils.gsmBcdByteToInt(pdu[8]); - int hour = IccUtils.gsmBcdByteToInt(pdu[9]); - int minute = IccUtils.gsmBcdByteToInt(pdu[10]); - int second = IccUtils.gsmBcdByteToInt(pdu[11]); - - // 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 = pdu[12]; - - // Mask out sign bit. - int timezoneOffset = IccUtils.gsmBcdByteToInt((byte) (tzByte & (~0x08))); - - timezoneOffset = ((tzByte & 0x08) == 0) ? timezoneOffset : -timezoneOffset; - - Time time = new Time(Time.TIMEZONE_UTC); - - // It's 2006. Should I really support years < 2000? - time.year = year >= 90 ? year + 1900 : year + 2000; - time.month = month - 1; - time.monthDay = day; - time.hour = hour; - time.minute = minute; - time.second = second; - - // Timezone offset is in quarter hours. - return time.toMillis(true) - (timezoneOffset * 15 * 60 * 1000); + @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()) : "") + '}'; } /** - * Append text to the message body. This is used to concatenate multi-page GSM broadcasts. - * @param body the text to append to this message + * Describe the kinds of special objects contained in the marshalled representation. + * @return a bitmask indicating this Parcelable contains no special objects */ - public void appendToBody(String body) { - mBody = mBody + body; - } - @Override - public String toString() { - return "SmsCbMessage{" + mHeader.toString() + ", language=" + mLanguage + - ", body=\"" + mBody + "\"}"; + public int describeContents() { + return 0; } } diff --git a/telephony/java/android/telephony/cdma/CdmaSmsCbProgramData.java b/telephony/java/android/telephony/cdma/CdmaSmsCbProgramData.java new file mode 100644 index 000000000000..f94efd8f56d7 --- /dev/null +++ b/telephony/java/android/telephony/cdma/CdmaSmsCbProgramData.java @@ -0,0 +1,210 @@ +/* + * 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.cdma; + +import android.os.Parcel; +import android.os.Parcelable; + +/** + * CDMA Service Category Program Data from SCPT teleservice SMS. + * The CellBroadcastReceiver app receives an Intent with action + * {@link android.provider.Telephony.Sms.Intents#SMS_SERVICE_CATEGORY_PROGRAM_DATA_RECEIVED_ACTION} + * containing an array of these objects to update its list of cell broadcast service categories + * to display. + * + * {@hide} + */ +public class CdmaSmsCbProgramData implements Parcelable { + + /** Delete the specified service category from the list of enabled categories. */ + public static final int OPERATION_DELETE_CATEGORY = 0; + + /** Add the specified service category to the list of enabled categories. */ + public static final int OPERATION_ADD_CATEGORY = 1; + + /** Clear all service categories from the list of enabled categories. */ + public static final int OPERATION_CLEAR_CATEGORIES = 2; + + /** Alert option: no alert. */ + public static final int ALERT_OPTION_NO_ALERT = 0; + + /** Alert option: default alert. */ + public static final int ALERT_OPTION_DEFAULT_ALERT = 1; + + /** Alert option: vibrate alert once. */ + public static final int ALERT_OPTION_VIBRATE_ONCE = 2; + + /** Alert option: vibrate alert - repeat. */ + public static final int ALERT_OPTION_VIBRATE_REPEAT = 3; + + /** Alert option: visual alert once. */ + public static final int ALERT_OPTION_VISUAL_ONCE = 4; + + /** Alert option: visual alert - repeat. */ + public static final int ALERT_OPTION_VISUAL_REPEAT = 5; + + /** Alert option: low-priority alert once. */ + public static final int ALERT_OPTION_LOW_PRIORITY_ONCE = 6; + + /** Alert option: low-priority alert - repeat. */ + public static final int ALERT_OPTION_LOW_PRIORITY_REPEAT = 7; + + /** Alert option: medium-priority alert once. */ + public static final int ALERT_OPTION_MED_PRIORITY_ONCE = 8; + + /** Alert option: medium-priority alert - repeat. */ + public static final int ALERT_OPTION_MED_PRIORITY_REPEAT = 9; + + /** Alert option: high-priority alert once. */ + public static final int ALERT_OPTION_HIGH_PRIORITY_ONCE = 10; + + /** Alert option: high-priority alert - repeat. */ + public static final int ALERT_OPTION_HIGH_PRIORITY_REPEAT = 11; + + /** Service category operation (add/delete/clear). */ + private final int mOperation; + + /** Service category to modify. */ + private final int mCategory; + + /** Language used for service category name (ISO 639 two character code). */ + private final String mLanguage; + + /** Maximum number of messages to store for this service category. */ + private final int mMaxMessages; + + /** Service category alert option. */ + private final int mAlertOption; + + /** Name of service category. */ + private final String mCategoryName; + + /** Create a new CdmaSmsCbProgramData object with the specified values. */ + public CdmaSmsCbProgramData(int operation, int category, String language, int maxMessages, + int alertOption, String categoryName) { + mOperation = operation; + mCategory = category; + mLanguage = language; + mMaxMessages = maxMessages; + mAlertOption = alertOption; + mCategoryName = categoryName; + } + + /** Create a new CdmaSmsCbProgramData object from a Parcel. */ + CdmaSmsCbProgramData(Parcel in) { + mOperation = in.readInt(); + mCategory = in.readInt(); + mLanguage = in.readString(); + mMaxMessages = in.readInt(); + mAlertOption = in.readInt(); + mCategoryName = in.readString(); + } + + /** + * 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(mOperation); + dest.writeInt(mCategory); + dest.writeString(mLanguage); + dest.writeInt(mMaxMessages); + dest.writeInt(mAlertOption); + dest.writeString(mCategoryName); + } + + /** + * Returns the service category operation, e.g. {@link #OPERATION_ADD_CATEGORY}. + * @return one of the {@code OPERATION_*} values + */ + public int getOperation() { + return mOperation; + } + + /** + * Returns the CDMA service category to modify. + * @return a 16-bit CDMA service category value + */ + public int getCategory() { + return mCategory; + } + + /** + * Returns the ISO-639-1 language code for the service category name, or null if not present. + * @return a two-digit ISO-639-1 language code, e.g. "en" for English + */ + public String getLanguageCode() { + return mLanguage; + } + + /** + * Returns the maximum number of messages to store for this service category. + * @return the maximum number of messages to store for this service category + */ + public int getMaxMessages() { + return mMaxMessages; + } + + /** + * Returns the service category alert option, e.g. {@link #ALERT_OPTION_DEFAULT_ALERT}. + * @return one of the {@code ALERT_OPTION_*} values + */ + public int getAlertOption() { + return mAlertOption; + } + + /** + * Returns the service category name, in the language specified by {@link #getLanguageCode()}. + * @return an optional service category name + */ + public String getCategoryName() { + return mCategoryName; + } + + @Override + public String toString() { + return "CdmaSmsCbProgramData{operation=" + mOperation + ", category=" + mCategory + + ", language=" + mLanguage + ", max messages=" + mMaxMessages + + ", alert option=" + mAlertOption + ", category name=" + mCategoryName + '}'; + } + + /** + * 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() { + @Override + public CdmaSmsCbProgramData createFromParcel(Parcel in) { + return new CdmaSmsCbProgramData(in); + } + + @Override + public CdmaSmsCbProgramData[] newArray(int size) { + return new CdmaSmsCbProgramData[size]; + } + }; +} -- cgit v1.2.3-59-g8ed1b