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