/* * 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 com.android.cellbroadcastreceiver; import android.content.ContentValues; import android.content.Context; import android.database.Cursor; import android.os.Parcel; import android.os.Parcelable; import android.telephony.SmsCbConstants; import android.telephony.SmsCbMessage; import android.text.format.DateUtils; import com.android.internal.telephony.gsm.SmsCbHeader; /** * 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 {@link CellBroadcastReceiver}, * displayed by {@link CellBroadcastAlertService}, and saved to SQLite by * {@link CellBroadcastDatabaseService}. */ 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"; private final int mGeographicalScope; private final int mSerialNumber; private final int mMessageCode; private final int mMessageIdentifier; private final String mLanguageCode; private final String mMessageBody; private final long mDeliveryTime; private boolean mIsRead; public CellBroadcastMessage(SmsCbMessage message) { mGeographicalScope = message.getGeographicalScope(); mSerialNumber = message.getUpdateNumber(); mMessageCode = message.getMessageCode(); mMessageIdentifier = message.getMessageIdentifier(); mLanguageCode = message.getLanguageCode(); mMessageBody = message.getMessageBody(); mDeliveryTime = System.currentTimeMillis(); mIsRead = false; } private CellBroadcastMessage(int geoScope, int serialNumber, int messageCode, int messageId, String languageCode, String messageBody, long deliveryTime, boolean isRead) { mGeographicalScope = geoScope; mSerialNumber = serialNumber; mMessageCode = messageCode; mMessageIdentifier = messageId; mLanguageCode = languageCode; mMessageBody = messageBody; mDeliveryTime = deliveryTime; mIsRead = isRead; } /** Parcelable: no special flags. */ public int describeContents() { return 0; } public void writeToParcel(Parcel out, int flags) { out.writeInt(mGeographicalScope); out.writeInt(mSerialNumber); out.writeInt(mMessageCode); out.writeInt(mMessageIdentifier); out.writeString(mLanguageCode); out.writeString(mMessageBody); out.writeLong(mDeliveryTime); out.writeInt(mIsRead ? 1 : 0); } public static final Parcelable.Creator<CellBroadcastMessage> CREATOR = new Parcelable.Creator<CellBroadcastMessage>() { public CellBroadcastMessage createFromParcel(Parcel in) { return new CellBroadcastMessage( in.readInt(), in.readInt(), in.readInt(), in.readInt(), in.readString(), in.readString(), in.readLong(), (in.readInt() != 0)); } 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 */ public static CellBroadcastMessage createFromCursor(Cursor cursor) { int geoScope = cursor.getInt(CellBroadcastDatabase.COLUMN_GEOGRAPHICAL_SCOPE); int serialNum = cursor.getInt(CellBroadcastDatabase.COLUMN_SERIAL_NUMBER); int messageCode = cursor.getInt(CellBroadcastDatabase.COLUMN_MESSAGE_CODE); int messageId = cursor.getInt(CellBroadcastDatabase.COLUMN_MESSAGE_IDENTIFIER); String language = cursor.getString(CellBroadcastDatabase.COLUMN_LANGUAGE_CODE); String body = cursor.getString(CellBroadcastDatabase.COLUMN_MESSAGE_BODY); long deliveryTime = cursor.getLong(CellBroadcastDatabase.COLUMN_DELIVERY_TIME); boolean isRead = (cursor.getInt(CellBroadcastDatabase.COLUMN_MESSAGE_READ) != 0); return new CellBroadcastMessage(geoScope, serialNum, messageCode, messageId, language, body, 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(8); cv.put(CellBroadcastDatabase.Columns.GEOGRAPHICAL_SCOPE, mGeographicalScope); cv.put(CellBroadcastDatabase.Columns.SERIAL_NUMBER, mSerialNumber); cv.put(CellBroadcastDatabase.Columns.MESSAGE_CODE, mMessageCode); cv.put(CellBroadcastDatabase.Columns.MESSAGE_IDENTIFIER, mMessageIdentifier); cv.put(CellBroadcastDatabase.Columns.LANGUAGE_CODE, mLanguageCode); cv.put(CellBroadcastDatabase.Columns.MESSAGE_BODY, mMessageBody); cv.put(CellBroadcastDatabase.Columns.DELIVERY_TIME, mDeliveryTime); cv.put(CellBroadcastDatabase.Columns.MESSAGE_READ, mIsRead); 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 int getGeographicalScope() { return mGeographicalScope; } public int getSerialNumber() { return mSerialNumber; } public int getMessageCode() { return mMessageCode; } public int getMessageIdentifier() { return mMessageIdentifier; } public String getLanguageCode() { return mLanguageCode; } public long getDeliveryTime() { return mDeliveryTime; } public String getMessageBody() { return mMessageBody; } public boolean isRead() { return mIsRead; } /** * 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 SmsCbHeader.isEmergencyMessage(mMessageIdentifier); } /** * 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() { int id = mMessageIdentifier; return SmsCbHeader.isEmergencyMessage(id) && id != SmsCbConstants.MESSAGE_ID_CMAS_ALERT_CHILD_ABDUCTION_EMERGENCY; } /** * 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 SmsCbHeader.isEtwsMessage(mMessageIdentifier); } /** * 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 SmsCbHeader.isCmasMessage(mMessageIdentifier); } /** * 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() { return SmsCbHeader.isEtwsMessage(mMessageIdentifier) && SmsCbHeader.isEtwsPopupAlert(mMessageCode); } /** * 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() { return SmsCbHeader.isEtwsMessage(mMessageIdentifier) && SmsCbHeader.isEtwsEmergencyUserAlert(mMessageCode); } public int getDialogTitleResource() { switch (mMessageIdentifier) { case SmsCbConstants.MESSAGE_ID_ETWS_EARTHQUAKE_WARNING: return R.string.etws_earthquake_warning; case SmsCbConstants.MESSAGE_ID_ETWS_TSUNAMI_WARNING: return R.string.etws_tsunami_warning; case SmsCbConstants.MESSAGE_ID_ETWS_EARTHQUAKE_AND_TSUNAMI_WARNING: return R.string.etws_earthquake_and_tsunami_warning; case SmsCbConstants.MESSAGE_ID_ETWS_TEST_MESSAGE: return R.string.etws_test_message; case SmsCbConstants.MESSAGE_ID_ETWS_OTHER_EMERGENCY_TYPE: return R.string.etws_other_emergency_type; case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_PRESIDENTIAL_LEVEL: return R.string.cmas_presidential_level_alert; case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXTREME_IMMEDIATE_OBSERVED: case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXTREME_IMMEDIATE_LIKELY: case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXTREME_EXPECTED_OBSERVED: case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXTREME_EXPECTED_LIKELY: return R.string.cmas_extreme_alert; case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_SEVERE_IMMEDIATE_OBSERVED: case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_SEVERE_IMMEDIATE_LIKELY: case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_SEVERE_EXPECTED_OBSERVED: case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_SEVERE_EXPECTED_LIKELY: return R.string.cmas_severe_alert; case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_CHILD_ABDUCTION_EMERGENCY: return R.string.cmas_amber_alert; case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_REQUIRED_MONTHLY_TEST: return R.string.cmas_required_monthly_test; case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXERCISE: return R.string.cmas_exercise_alert; case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_OPERATOR_DEFINED_USE: return R.string.cmas_operator_defined_alert; default: if (SmsCbHeader.isEmergencyMessage(mMessageIdentifier) || CellBroadcastConfigService.isOperatorDefinedEmergencyId( mMessageIdentifier)) { return R.string.pws_other_message_identifiers; } else { return R.string.cb_other_message_identifiers; } } } /** * 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 */ 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 */ String getSpokenDateString(Context context) { int flags = DateUtils.FORMAT_SHOW_TIME | DateUtils.FORMAT_SHOW_DATE; return DateUtils.formatDateTime(context, mDeliveryTime, flags); } }