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.Context;
20 import android.graphics.Typeface;
21 import android.telephony.CellBroadcastMessage;
22 import android.telephony.SmsCbCmasInfo;
23 import android.telephony.SmsCbEtwsInfo;
24 import android.text.Spannable;
25 import android.text.SpannableStringBuilder;
26 import android.text.style.StyleSpan;
27 import com.android.cellbroadcastreceiver.CellBroadcastOtherChannelsManager.CellBroadcastChannelRange;
28 
29 import java.util.ArrayList;
30 
31 /**
32  * Returns the string resource ID's for CMAS and ETWS emergency alerts.
33  */
34 public class CellBroadcastResources {
35 
CellBroadcastResources()36     private CellBroadcastResources() {
37     }
38 
39     /**
40      * Returns a styled CharSequence containing the message date/time and alert details.
41      * @param context a Context for resource string access
42      * @return a CharSequence for display in the broadcast alert dialog
43      */
getMessageDetails(Context context, CellBroadcastMessage cbm)44     public static CharSequence getMessageDetails(Context context, CellBroadcastMessage cbm) {
45         SpannableStringBuilder buf = new SpannableStringBuilder();
46 
47         // Alert date/time
48         int start = buf.length();
49         buf.append(context.getString(R.string.delivery_time_heading));
50         int end = buf.length();
51         buf.setSpan(new StyleSpan(Typeface.BOLD), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
52         buf.append(" ");
53         buf.append(cbm.getDateString(context));
54 
55         if (cbm.isCmasMessage()) {
56             // CMAS category, response type, severity, urgency, certainty
57             appendCmasAlertDetails(context, buf, cbm.getCmasWarningInfo());
58         }
59 
60         return buf;
61     }
62 
appendCmasAlertDetails(Context context, SpannableStringBuilder buf, SmsCbCmasInfo cmasInfo)63     private static void appendCmasAlertDetails(Context context, SpannableStringBuilder buf,
64             SmsCbCmasInfo cmasInfo) {
65         // CMAS category
66         int categoryId = getCmasCategoryResId(cmasInfo);
67         if (categoryId != 0) {
68             appendMessageDetail(context, buf, R.string.cmas_category_heading, categoryId);
69         }
70 
71         // CMAS response type
72         int responseId = getCmasResponseResId(cmasInfo);
73         if (responseId != 0) {
74             appendMessageDetail(context, buf, R.string.cmas_response_heading, responseId);
75         }
76 
77         // CMAS severity
78         int severityId = getCmasSeverityResId(cmasInfo);
79         if (severityId != 0) {
80             appendMessageDetail(context, buf, R.string.cmas_severity_heading, severityId);
81         }
82 
83         // CMAS urgency
84         int urgencyId = getCmasUrgencyResId(cmasInfo);
85         if (urgencyId != 0) {
86             appendMessageDetail(context, buf, R.string.cmas_urgency_heading, urgencyId);
87         }
88 
89         // CMAS certainty
90         int certaintyId = getCmasCertaintyResId(cmasInfo);
91         if (certaintyId != 0) {
92             appendMessageDetail(context, buf, R.string.cmas_certainty_heading, certaintyId);
93         }
94     }
95 
appendMessageDetail(Context context, SpannableStringBuilder buf, int typeId, int valueId)96     private static void appendMessageDetail(Context context, SpannableStringBuilder buf,
97             int typeId, int valueId) {
98         if (buf.length() != 0) {
99             buf.append("\n");
100         }
101         int start = buf.length();
102         buf.append(context.getString(typeId));
103         int end = buf.length();
104         buf.setSpan(new StyleSpan(Typeface.BOLD), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
105         buf.append(" ");
106         buf.append(context.getString(valueId));
107     }
108 
109     /**
110      * Returns the string resource ID for the CMAS category.
111      * @return a string resource ID, or 0 if the CMAS category is unknown or not present
112      */
getCmasCategoryResId(SmsCbCmasInfo cmasInfo)113     private static int getCmasCategoryResId(SmsCbCmasInfo cmasInfo) {
114         switch (cmasInfo.getCategory()) {
115             case SmsCbCmasInfo.CMAS_CATEGORY_GEO:
116                 return R.string.cmas_category_geo;
117 
118             case SmsCbCmasInfo.CMAS_CATEGORY_MET:
119                 return R.string.cmas_category_met;
120 
121             case SmsCbCmasInfo.CMAS_CATEGORY_SAFETY:
122                 return R.string.cmas_category_safety;
123 
124             case SmsCbCmasInfo.CMAS_CATEGORY_SECURITY:
125                 return R.string.cmas_category_security;
126 
127             case SmsCbCmasInfo.CMAS_CATEGORY_RESCUE:
128                 return R.string.cmas_category_rescue;
129 
130             case SmsCbCmasInfo.CMAS_CATEGORY_FIRE:
131                 return R.string.cmas_category_fire;
132 
133             case SmsCbCmasInfo.CMAS_CATEGORY_HEALTH:
134                 return R.string.cmas_category_health;
135 
136             case SmsCbCmasInfo.CMAS_CATEGORY_ENV:
137                 return R.string.cmas_category_env;
138 
139             case SmsCbCmasInfo.CMAS_CATEGORY_TRANSPORT:
140                 return R.string.cmas_category_transport;
141 
142             case SmsCbCmasInfo.CMAS_CATEGORY_INFRA:
143                 return R.string.cmas_category_infra;
144 
145             case SmsCbCmasInfo.CMAS_CATEGORY_CBRNE:
146                 return R.string.cmas_category_cbrne;
147 
148             case SmsCbCmasInfo.CMAS_CATEGORY_OTHER:
149                 return R.string.cmas_category_other;
150 
151             default:
152                 return 0;
153         }
154     }
155 
156     /**
157      * Returns the string resource ID for the CMAS response type.
158      * @return a string resource ID, or 0 if the CMAS response type is unknown or not present
159      */
getCmasResponseResId(SmsCbCmasInfo cmasInfo)160     private static int getCmasResponseResId(SmsCbCmasInfo cmasInfo) {
161         switch (cmasInfo.getResponseType()) {
162             case SmsCbCmasInfo.CMAS_RESPONSE_TYPE_SHELTER:
163                 return R.string.cmas_response_shelter;
164 
165             case SmsCbCmasInfo.CMAS_RESPONSE_TYPE_EVACUATE:
166                 return R.string.cmas_response_evacuate;
167 
168             case SmsCbCmasInfo.CMAS_RESPONSE_TYPE_PREPARE:
169                 return R.string.cmas_response_prepare;
170 
171             case SmsCbCmasInfo.CMAS_RESPONSE_TYPE_EXECUTE:
172                 return R.string.cmas_response_execute;
173 
174             case SmsCbCmasInfo.CMAS_RESPONSE_TYPE_MONITOR:
175                 return R.string.cmas_response_monitor;
176 
177             case SmsCbCmasInfo.CMAS_RESPONSE_TYPE_AVOID:
178                 return R.string.cmas_response_avoid;
179 
180             case SmsCbCmasInfo.CMAS_RESPONSE_TYPE_ASSESS:
181                 return R.string.cmas_response_assess;
182 
183             case SmsCbCmasInfo.CMAS_RESPONSE_TYPE_NONE:
184                 return R.string.cmas_response_none;
185 
186             default:
187                 return 0;
188         }
189     }
190 
191     /**
192      * Returns the string resource ID for the CMAS severity.
193      * @return a string resource ID, or 0 if the CMAS severity is unknown or not present
194      */
getCmasSeverityResId(SmsCbCmasInfo cmasInfo)195     private static int getCmasSeverityResId(SmsCbCmasInfo cmasInfo) {
196         switch (cmasInfo.getSeverity()) {
197             case SmsCbCmasInfo.CMAS_SEVERITY_EXTREME:
198                 return R.string.cmas_severity_extreme;
199 
200             case SmsCbCmasInfo.CMAS_SEVERITY_SEVERE:
201                 return R.string.cmas_severity_severe;
202 
203             default:
204                 return 0;
205         }
206     }
207 
208     /**
209      * Returns the string resource ID for the CMAS urgency.
210      * @return a string resource ID, or 0 if the CMAS urgency is unknown or not present
211      */
getCmasUrgencyResId(SmsCbCmasInfo cmasInfo)212     private static int getCmasUrgencyResId(SmsCbCmasInfo cmasInfo) {
213         switch (cmasInfo.getUrgency()) {
214             case SmsCbCmasInfo.CMAS_URGENCY_IMMEDIATE:
215                 return R.string.cmas_urgency_immediate;
216 
217             case SmsCbCmasInfo.CMAS_URGENCY_EXPECTED:
218                 return R.string.cmas_urgency_expected;
219 
220             default:
221                 return 0;
222         }
223     }
224 
225     /**
226      * Returns the string resource ID for the CMAS certainty.
227      * @return a string resource ID, or 0 if the CMAS certainty is unknown or not present
228      */
getCmasCertaintyResId(SmsCbCmasInfo cmasInfo)229     private static int getCmasCertaintyResId(SmsCbCmasInfo cmasInfo) {
230         switch (cmasInfo.getCertainty()) {
231             case SmsCbCmasInfo.CMAS_CERTAINTY_OBSERVED:
232                 return R.string.cmas_certainty_observed;
233 
234             case SmsCbCmasInfo.CMAS_CERTAINTY_LIKELY:
235                 return R.string.cmas_certainty_likely;
236 
237             default:
238                 return 0;
239         }
240     }
241 
getDialogTitleResource(Context context, CellBroadcastMessage cbm)242     public static int getDialogTitleResource(Context context, CellBroadcastMessage cbm) {
243         // ETWS warning types
244         SmsCbEtwsInfo etwsInfo = cbm.getEtwsWarningInfo();
245         if (etwsInfo != null) {
246             switch (etwsInfo.getWarningType()) {
247                 case SmsCbEtwsInfo.ETWS_WARNING_TYPE_EARTHQUAKE:
248                     return R.string.etws_earthquake_warning;
249 
250                 case SmsCbEtwsInfo.ETWS_WARNING_TYPE_TSUNAMI:
251                     return R.string.etws_tsunami_warning;
252 
253                 case SmsCbEtwsInfo.ETWS_WARNING_TYPE_EARTHQUAKE_AND_TSUNAMI:
254                     return R.string.etws_earthquake_and_tsunami_warning;
255 
256                 case SmsCbEtwsInfo.ETWS_WARNING_TYPE_TEST_MESSAGE:
257                     return R.string.etws_test_message;
258 
259                 case SmsCbEtwsInfo.ETWS_WARNING_TYPE_OTHER_EMERGENCY:
260                 default:
261                     return R.string.etws_other_emergency_type;
262             }
263         }
264 
265         // CMAS warning types
266         SmsCbCmasInfo cmasInfo = cbm.getCmasWarningInfo();
267         if (cmasInfo != null) {
268             switch (cmasInfo.getMessageClass()) {
269                 case SmsCbCmasInfo.CMAS_CLASS_PRESIDENTIAL_LEVEL_ALERT:
270                     return R.string.cmas_presidential_level_alert;
271 
272                 case SmsCbCmasInfo.CMAS_CLASS_EXTREME_THREAT:
273                     return R.string.cmas_extreme_alert;
274 
275                 case SmsCbCmasInfo.CMAS_CLASS_SEVERE_THREAT:
276                     return R.string.cmas_severe_alert;
277 
278                 case SmsCbCmasInfo.CMAS_CLASS_CHILD_ABDUCTION_EMERGENCY:
279                     return R.string.cmas_amber_alert;
280 
281                 case SmsCbCmasInfo.CMAS_CLASS_REQUIRED_MONTHLY_TEST:
282                     return R.string.cmas_required_monthly_test;
283 
284                 case SmsCbCmasInfo.CMAS_CLASS_CMAS_EXERCISE:
285                     return R.string.cmas_exercise_alert;
286 
287                 case SmsCbCmasInfo.CMAS_CLASS_OPERATOR_DEFINED_USE:
288                     return R.string.cmas_operator_defined_alert;
289 
290                 default:
291                     return R.string.pws_other_message_identifiers;
292             }
293         }
294 
295         if (CellBroadcastAlertService.isEmergencyMessage(context, cbm)) {
296             ArrayList<CellBroadcastChannelRange> ranges = CellBroadcastOtherChannelsManager.
297                     getInstance().getCellBroadcastChannelRanges(context, cbm.getSubId());
298             if (ranges != null) {
299                 for (CellBroadcastChannelRange range : ranges) {
300                     if (cbm.getServiceCategory() >= range.mStartId &&
301                             cbm.getServiceCategory() <= range.mEndId) {
302                         // Apply the closest title to the specified tones.
303                         switch (range.mToneType) {
304                             case CMAS_DEFAULT:
305                                 return R.string.pws_other_message_identifiers;
306                             case EARTHQUAKE:
307                                 return R.string.etws_earthquake_warning;
308                             case TSUNAMI:
309                                 return R.string.etws_tsunami_warning;
310                             case ETWS_DEFAULT:
311                             case OTHER:
312                                 return R.string.etws_other_emergency_type;
313                         }
314                     }
315                 }
316 
317             }
318             return R.string.pws_other_message_identifiers;
319         } else {
320             return R.string.cb_other_message_identifiers;
321         }
322     }
323 }
324