• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2011 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5  * use this file except in compliance with the License. You may obtain a copy of
6  * the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13  * License for the specific language governing permissions and limitations under
14  * the License.
15  */
16 
17 package com.android.cellbroadcastreceiver;
18 
19 import android.content.ContentValues;
20 import android.content.Context;
21 import android.database.Cursor;
22 import android.os.Parcel;
23 import android.os.Parcelable;
24 import android.telephony.SmsCbConstants;
25 import android.telephony.SmsCbMessage;
26 import android.text.format.DateUtils;
27 
28 import com.android.internal.telephony.gsm.SmsCbHeader;
29 
30 /**
31  * Application wrapper for {@link SmsCbMessage}. This is Parcelable so that
32  * decoded broadcast message objects can be passed between running Services.
33  * New broadcasts are received by {@link CellBroadcastReceiver},
34  * displayed by {@link CellBroadcastAlertService}, and saved to SQLite by
35  * {@link CellBroadcastDatabaseService}.
36  */
37 public class CellBroadcastMessage implements Parcelable {
38 
39     /** Identifier for getExtra() when adding this object to an Intent. */
40     public static final String SMS_CB_MESSAGE_EXTRA =
41             "com.android.cellbroadcastreceiver.SMS_CB_MESSAGE";
42 
43     private final int mGeographicalScope;
44     private final int mSerialNumber;
45     private final int mMessageCode;
46     private final int mMessageIdentifier;
47     private final String mLanguageCode;
48     private final String mMessageBody;
49     private final long mDeliveryTime;
50     private boolean mIsRead;
51 
CellBroadcastMessage(SmsCbMessage message)52     public CellBroadcastMessage(SmsCbMessage message) {
53         mGeographicalScope = message.getGeographicalScope();
54         mSerialNumber = message.getUpdateNumber();
55         mMessageCode = message.getMessageCode();
56         mMessageIdentifier = message.getMessageIdentifier();
57         mLanguageCode = message.getLanguageCode();
58         mMessageBody = message.getMessageBody();
59         mDeliveryTime = System.currentTimeMillis();
60         mIsRead = false;
61     }
62 
CellBroadcastMessage(int geoScope, int serialNumber, int messageCode, int messageId, String languageCode, String messageBody, long deliveryTime, boolean isRead)63     private CellBroadcastMessage(int geoScope, int serialNumber,
64             int messageCode, int messageId, String languageCode,
65             String messageBody, long deliveryTime, boolean isRead) {
66         mGeographicalScope = geoScope;
67         mSerialNumber = serialNumber;
68         mMessageCode = messageCode;
69         mMessageIdentifier = messageId;
70         mLanguageCode = languageCode;
71         mMessageBody = messageBody;
72         mDeliveryTime = deliveryTime;
73         mIsRead = isRead;
74     }
75 
76     /** Parcelable: no special flags. */
describeContents()77     public int describeContents() {
78         return 0;
79     }
80 
writeToParcel(Parcel out, int flags)81     public void writeToParcel(Parcel out, int flags) {
82         out.writeInt(mGeographicalScope);
83         out.writeInt(mSerialNumber);
84         out.writeInt(mMessageCode);
85         out.writeInt(mMessageIdentifier);
86         out.writeString(mLanguageCode);
87         out.writeString(mMessageBody);
88         out.writeLong(mDeliveryTime);
89         out.writeInt(mIsRead ? 1 : 0);
90     }
91 
92     public static final Parcelable.Creator<CellBroadcastMessage> CREATOR
93             = new Parcelable.Creator<CellBroadcastMessage>() {
94         public CellBroadcastMessage createFromParcel(Parcel in) {
95             return new CellBroadcastMessage(
96                     in.readInt(), in.readInt(),
97                     in.readInt(), in.readInt(), in.readString(),
98                     in.readString(), in.readLong(), (in.readInt() != 0));
99         }
100 
101         public CellBroadcastMessage[] newArray(int size) {
102             return new CellBroadcastMessage[size];
103         }
104     };
105 
106     /**
107      * Create a CellBroadcastMessage from a row in the database.
108      * @param cursor an open SQLite cursor pointing to the row to read
109      * @return the new CellBroadcastMessage
110      */
createFromCursor(Cursor cursor)111     public static CellBroadcastMessage createFromCursor(Cursor cursor) {
112         int geoScope = cursor.getInt(CellBroadcastDatabase.COLUMN_GEOGRAPHICAL_SCOPE);
113         int serialNum = cursor.getInt(CellBroadcastDatabase.COLUMN_SERIAL_NUMBER);
114         int messageCode = cursor.getInt(CellBroadcastDatabase.COLUMN_MESSAGE_CODE);
115         int messageId = cursor.getInt(CellBroadcastDatabase.COLUMN_MESSAGE_IDENTIFIER);
116         String language = cursor.getString(CellBroadcastDatabase.COLUMN_LANGUAGE_CODE);
117         String body = cursor.getString(CellBroadcastDatabase.COLUMN_MESSAGE_BODY);
118         long deliveryTime = cursor.getLong(CellBroadcastDatabase.COLUMN_DELIVERY_TIME);
119         boolean isRead = (cursor.getInt(CellBroadcastDatabase.COLUMN_MESSAGE_READ) != 0);
120         return new CellBroadcastMessage(geoScope, serialNum, messageCode, messageId,
121                 language, body, deliveryTime, isRead);
122     }
123 
124     /**
125      * Return a ContentValues object for insertion into the database.
126      * @return a new ContentValues object containing this object's data
127      */
getContentValues()128     public ContentValues getContentValues() {
129         ContentValues cv = new ContentValues(8);
130         cv.put(CellBroadcastDatabase.Columns.GEOGRAPHICAL_SCOPE, mGeographicalScope);
131         cv.put(CellBroadcastDatabase.Columns.SERIAL_NUMBER, mSerialNumber);
132         cv.put(CellBroadcastDatabase.Columns.MESSAGE_CODE, mMessageCode);
133         cv.put(CellBroadcastDatabase.Columns.MESSAGE_IDENTIFIER, mMessageIdentifier);
134         cv.put(CellBroadcastDatabase.Columns.LANGUAGE_CODE, mLanguageCode);
135         cv.put(CellBroadcastDatabase.Columns.MESSAGE_BODY, mMessageBody);
136         cv.put(CellBroadcastDatabase.Columns.DELIVERY_TIME, mDeliveryTime);
137         cv.put(CellBroadcastDatabase.Columns.MESSAGE_READ, mIsRead);
138         return cv;
139     }
140 
141     /**
142      * Set or clear the "read message" flag.
143      * @param isRead true if the message has been read; false if not
144      */
setIsRead(boolean isRead)145     public void setIsRead(boolean isRead) {
146         mIsRead = isRead;
147     }
148 
getGeographicalScope()149     public int getGeographicalScope() {
150         return mGeographicalScope;
151     }
152 
getSerialNumber()153     public int getSerialNumber() {
154         return mSerialNumber;
155     }
156 
getMessageCode()157     public int getMessageCode() {
158         return mMessageCode;
159     }
160 
getMessageIdentifier()161     public int getMessageIdentifier() {
162         return mMessageIdentifier;
163     }
164 
getLanguageCode()165     public String getLanguageCode() {
166         return mLanguageCode;
167     }
168 
getDeliveryTime()169     public long getDeliveryTime() {
170         return mDeliveryTime;
171     }
172 
getMessageBody()173     public String getMessageBody() {
174         return mMessageBody;
175     }
176 
isRead()177     public boolean isRead() {
178         return mIsRead;
179     }
180 
181     /**
182      * Return whether the broadcast is an emergency (PWS) message type.
183      * This includes lower priority test messages and Amber alerts.
184      *
185      * All public alerts show the flashing warning icon in the dialog,
186      * but only emergency alerts play the alert sound and speak the message.
187      *
188      * @return true if the message is PWS type; false otherwise
189      */
isPublicAlertMessage()190     public boolean isPublicAlertMessage() {
191         return SmsCbHeader.isEmergencyMessage(mMessageIdentifier);
192     }
193 
194     /**
195      * Returns whether the broadcast is an emergency (PWS) message type,
196      * including test messages, but excluding lower priority Amber alert broadcasts.
197      *
198      * @return true if the message is PWS type, excluding Amber alerts
199      */
isEmergencyAlertMessage()200     public boolean isEmergencyAlertMessage() {
201         int id = mMessageIdentifier;
202         return SmsCbHeader.isEmergencyMessage(id) &&
203                 id != SmsCbConstants.MESSAGE_ID_CMAS_ALERT_CHILD_ABDUCTION_EMERGENCY;
204     }
205 
206     /**
207      * Return whether the broadcast is an ETWS emergency message type.
208      * @return true if the message is ETWS emergency type; false otherwise
209      */
isEtwsMessage()210     public boolean isEtwsMessage() {
211         return SmsCbHeader.isEtwsMessage(mMessageIdentifier);
212     }
213 
214     /**
215      * Return whether the broadcast is a CMAS emergency message type.
216      * @return true if the message is CMAS emergency type; false otherwise
217      */
isCmasMessage()218     public boolean isCmasMessage() {
219         return SmsCbHeader.isCmasMessage(mMessageIdentifier);
220     }
221 
222     /**
223      * Return whether the broadcast is an ETWS popup alert.
224      * This method checks the message ID and the message code.
225      * @return true if the message indicates an ETWS popup alert
226      */
isEtwsPopupAlert()227     public boolean isEtwsPopupAlert() {
228         return SmsCbHeader.isEtwsMessage(mMessageIdentifier) &&
229                 SmsCbHeader.isEtwsPopupAlert(mMessageCode);
230     }
231 
232     /**
233      * Return whether the broadcast is an ETWS emergency user alert.
234      * This method checks the message ID and the message code.
235      * @return true if the message indicates an ETWS emergency user alert
236      */
isEtwsEmergencyUserAlert()237     public boolean isEtwsEmergencyUserAlert() {
238         return SmsCbHeader.isEtwsMessage(mMessageIdentifier) &&
239                 SmsCbHeader.isEtwsEmergencyUserAlert(mMessageCode);
240     }
241 
getDialogTitleResource()242     public int getDialogTitleResource() {
243         switch (mMessageIdentifier) {
244             case SmsCbConstants.MESSAGE_ID_ETWS_EARTHQUAKE_WARNING:
245                 return R.string.etws_earthquake_warning;
246 
247             case SmsCbConstants.MESSAGE_ID_ETWS_TSUNAMI_WARNING:
248                 return R.string.etws_tsunami_warning;
249 
250             case SmsCbConstants.MESSAGE_ID_ETWS_EARTHQUAKE_AND_TSUNAMI_WARNING:
251                 return R.string.etws_earthquake_and_tsunami_warning;
252 
253             case SmsCbConstants.MESSAGE_ID_ETWS_TEST_MESSAGE:
254                 return R.string.etws_test_message;
255 
256             case SmsCbConstants.MESSAGE_ID_ETWS_OTHER_EMERGENCY_TYPE:
257                 return R.string.etws_other_emergency_type;
258 
259             case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_PRESIDENTIAL_LEVEL:
260                 return R.string.cmas_presidential_level_alert;
261 
262             case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXTREME_IMMEDIATE_OBSERVED:
263             case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXTREME_IMMEDIATE_LIKELY:
264             case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXTREME_EXPECTED_OBSERVED:
265             case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXTREME_EXPECTED_LIKELY:
266                 return R.string.cmas_extreme_alert;
267 
268             case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_SEVERE_IMMEDIATE_OBSERVED:
269             case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_SEVERE_IMMEDIATE_LIKELY:
270             case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_SEVERE_EXPECTED_OBSERVED:
271             case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_SEVERE_EXPECTED_LIKELY:
272                 return R.string.cmas_severe_alert;
273 
274             case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_CHILD_ABDUCTION_EMERGENCY:
275                 return R.string.cmas_amber_alert;
276 
277             case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_REQUIRED_MONTHLY_TEST:
278                 return R.string.cmas_required_monthly_test;
279 
280             case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXERCISE:
281                 return R.string.cmas_exercise_alert;
282 
283             case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_OPERATOR_DEFINED_USE:
284                 return R.string.cmas_operator_defined_alert;
285 
286             default:
287                 if (SmsCbHeader.isEmergencyMessage(mMessageIdentifier) ||
288                         CellBroadcastConfigService.isOperatorDefinedEmergencyId(
289                                 mMessageIdentifier)) {
290                     return R.string.pws_other_message_identifiers;
291                 } else {
292                     return R.string.cb_other_message_identifiers;
293                 }
294         }
295     }
296 
297     /**
298      * Return the abbreviated date string for the message delivery time.
299      * @param context the context object
300      * @return a String to use in the broadcast list UI
301      */
getDateString(Context context)302     String getDateString(Context context) {
303         int flags = DateUtils.FORMAT_NO_NOON_MIDNIGHT | DateUtils.FORMAT_SHOW_TIME |
304                 DateUtils.FORMAT_ABBREV_ALL | DateUtils.FORMAT_SHOW_DATE |
305                 DateUtils.FORMAT_CAP_AMPM;
306         return DateUtils.formatDateTime(context, mDeliveryTime, flags);
307     }
308 
309     /**
310      * Return the date string for the message delivery time, suitable for text-to-speech.
311      * @param context the context object
312      * @return a String for populating the list item AccessibilityEvent for TTS
313      */
getSpokenDateString(Context context)314     String getSpokenDateString(Context context) {
315         int flags = DateUtils.FORMAT_SHOW_TIME | DateUtils.FORMAT_SHOW_DATE;
316         return DateUtils.formatDateTime(context, mDeliveryTime, flags);
317     }
318 }
319