/* * 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.Context; import android.graphics.Typeface; import android.telephony.SmsCbCmasInfo; import android.telephony.SmsCbEtwsInfo; import android.telephony.SmsCbMessage; import android.text.Spannable; import android.text.SpannableStringBuilder; import android.text.TextUtils; import android.text.style.StyleSpan; import com.android.cellbroadcastreceiver.CellBroadcastChannelManager.CellBroadcastChannelRange; import java.text.DateFormat; import java.util.ArrayList; /** * Returns the string resource ID's for CMAS and ETWS emergency alerts. */ public class CellBroadcastResources { private CellBroadcastResources() { } /** * Returns a styled CharSequence containing the message date/time and alert details. * @param context a Context for resource string access * @param showDebugInfo {@code true} if adding more information for debugging purposes. * @param message The cell broadcast message. * @param locationCheckTime The EPOCH time in milliseconds that Device-based Geo-fencing (DBGF) * was last performed. 0 if the message does not have DBGF information. * @param isDisplayed {@code true} if the message is displayed to the user. * @param geometry Geometry string for device-based geo-fencing message. * * @return a CharSequence for display in the broadcast alert dialog */ public static CharSequence getMessageDetails(Context context, boolean showDebugInfo, SmsCbMessage message, long locationCheckTime, boolean isDisplayed, String geometry) { SpannableStringBuilder buf = new SpannableStringBuilder(); // Alert date/time appendMessageDetail(context, buf, R.string.delivery_time_heading, DateFormat.getDateTimeInstance().format(message.getReceivedTime())); // Message id if (showDebugInfo) { appendMessageDetail(context, buf, R.string.message_identifier, Integer.toString(message.getServiceCategory())); appendMessageDetail(context, buf, R.string.message_serial_number, Integer.toString(message.getSerialNumber())); } if (message.isCmasMessage()) { // CMAS category, response type, severity, urgency, certainty appendCmasAlertDetails(context, buf, message.getCmasWarningInfo()); } if (showDebugInfo) { appendMessageDetail(context, buf, R.string.data_coding_scheme, Integer.toString(message.getDataCodingScheme())); appendMessageDetail(context, buf, R.string.message_content, message.getMessageBody()); appendMessageDetail(context, buf, R.string.location_check_time, locationCheckTime == -1 ? "N/A" : DateFormat.getDateTimeInstance().format(locationCheckTime)); appendMessageDetail(context, buf, R.string.maximum_waiting_time, message.getMaximumWaitingDuration() + " " + context.getString(R.string.seconds)); appendMessageDetail(context, buf, R.string.message_displayed, Boolean.toString(isDisplayed)); appendMessageDetail(context, buf, R.string.message_coordinates, TextUtils.isEmpty(geometry) ? "N/A" : geometry); } return buf; } private static void appendCmasAlertDetails(Context context, SpannableStringBuilder buf, SmsCbCmasInfo cmasInfo) { // CMAS category int categoryId = getCmasCategoryResId(cmasInfo); if (categoryId != 0) { appendMessageDetail(context, buf, R.string.cmas_category_heading, context.getString(categoryId)); } // CMAS response type int responseId = getCmasResponseResId(cmasInfo); if (responseId != 0) { appendMessageDetail(context, buf, R.string.cmas_response_heading, context.getString(responseId)); } // CMAS severity int severityId = getCmasSeverityResId(cmasInfo); if (severityId != 0) { appendMessageDetail(context, buf, R.string.cmas_severity_heading, context.getString(severityId)); } // CMAS urgency int urgencyId = getCmasUrgencyResId(cmasInfo); if (urgencyId != 0) { appendMessageDetail(context, buf, R.string.cmas_urgency_heading, context.getString(urgencyId)); } // CMAS certainty int certaintyId = getCmasCertaintyResId(cmasInfo); if (certaintyId != 0) { appendMessageDetail(context, buf, R.string.cmas_certainty_heading, context.getString(certaintyId)); } } private static void appendMessageDetail(Context context, SpannableStringBuilder buf, int typeId, String value) { if (buf.length() != 0) { buf.append("\n"); } int start = buf.length(); buf.append(context.getString(typeId)); int end = buf.length(); buf.setSpan(new StyleSpan(Typeface.BOLD), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); buf.append(" "); buf.append(value); } /** * Returns the string resource ID for the CMAS category. * @return a string resource ID, or 0 if the CMAS category is unknown or not present */ private static int getCmasCategoryResId(SmsCbCmasInfo cmasInfo) { switch (cmasInfo.getCategory()) { case SmsCbCmasInfo.CMAS_CATEGORY_GEO: return R.string.cmas_category_geo; case SmsCbCmasInfo.CMAS_CATEGORY_MET: return R.string.cmas_category_met; case SmsCbCmasInfo.CMAS_CATEGORY_SAFETY: return R.string.cmas_category_safety; case SmsCbCmasInfo.CMAS_CATEGORY_SECURITY: return R.string.cmas_category_security; case SmsCbCmasInfo.CMAS_CATEGORY_RESCUE: return R.string.cmas_category_rescue; case SmsCbCmasInfo.CMAS_CATEGORY_FIRE: return R.string.cmas_category_fire; case SmsCbCmasInfo.CMAS_CATEGORY_HEALTH: return R.string.cmas_category_health; case SmsCbCmasInfo.CMAS_CATEGORY_ENV: return R.string.cmas_category_env; case SmsCbCmasInfo.CMAS_CATEGORY_TRANSPORT: return R.string.cmas_category_transport; case SmsCbCmasInfo.CMAS_CATEGORY_INFRA: return R.string.cmas_category_infra; case SmsCbCmasInfo.CMAS_CATEGORY_CBRNE: return R.string.cmas_category_cbrne; case SmsCbCmasInfo.CMAS_CATEGORY_OTHER: return R.string.cmas_category_other; default: return 0; } } /** * Returns the string resource ID for the CMAS response type. * @return a string resource ID, or 0 if the CMAS response type is unknown or not present */ private static int getCmasResponseResId(SmsCbCmasInfo cmasInfo) { switch (cmasInfo.getResponseType()) { case SmsCbCmasInfo.CMAS_RESPONSE_TYPE_SHELTER: return R.string.cmas_response_shelter; case SmsCbCmasInfo.CMAS_RESPONSE_TYPE_EVACUATE: return R.string.cmas_response_evacuate; case SmsCbCmasInfo.CMAS_RESPONSE_TYPE_PREPARE: return R.string.cmas_response_prepare; case SmsCbCmasInfo.CMAS_RESPONSE_TYPE_EXECUTE: return R.string.cmas_response_execute; case SmsCbCmasInfo.CMAS_RESPONSE_TYPE_MONITOR: return R.string.cmas_response_monitor; case SmsCbCmasInfo.CMAS_RESPONSE_TYPE_AVOID: return R.string.cmas_response_avoid; case SmsCbCmasInfo.CMAS_RESPONSE_TYPE_ASSESS: return R.string.cmas_response_assess; case SmsCbCmasInfo.CMAS_RESPONSE_TYPE_NONE: return R.string.cmas_response_none; default: return 0; } } /** * Returns the string resource ID for the CMAS severity. * @return a string resource ID, or 0 if the CMAS severity is unknown or not present */ private static int getCmasSeverityResId(SmsCbCmasInfo cmasInfo) { switch (cmasInfo.getSeverity()) { case SmsCbCmasInfo.CMAS_SEVERITY_EXTREME: return R.string.cmas_severity_extreme; case SmsCbCmasInfo.CMAS_SEVERITY_SEVERE: return R.string.cmas_severity_severe; default: return 0; } } /** * Returns the string resource ID for the CMAS urgency. * @return a string resource ID, or 0 if the CMAS urgency is unknown or not present */ private static int getCmasUrgencyResId(SmsCbCmasInfo cmasInfo) { switch (cmasInfo.getUrgency()) { case SmsCbCmasInfo.CMAS_URGENCY_IMMEDIATE: return R.string.cmas_urgency_immediate; case SmsCbCmasInfo.CMAS_URGENCY_EXPECTED: return R.string.cmas_urgency_expected; default: return 0; } } /** * Returns the string resource ID for the CMAS certainty. * @return a string resource ID, or 0 if the CMAS certainty is unknown or not present */ private static int getCmasCertaintyResId(SmsCbCmasInfo cmasInfo) { switch (cmasInfo.getCertainty()) { case SmsCbCmasInfo.CMAS_CERTAINTY_OBSERVED: return R.string.cmas_certainty_observed; case SmsCbCmasInfo.CMAS_CERTAINTY_LIKELY: return R.string.cmas_certainty_likely; default: return 0; } } static int getDialogTitleResource(Context context, SmsCbMessage message) { // ETWS warning types SmsCbEtwsInfo etwsInfo = message.getEtwsWarningInfo(); if (etwsInfo != null) { switch (etwsInfo.getWarningType()) { case SmsCbEtwsInfo.ETWS_WARNING_TYPE_EARTHQUAKE: return R.string.etws_earthquake_warning; case SmsCbEtwsInfo.ETWS_WARNING_TYPE_TSUNAMI: return R.string.etws_tsunami_warning; case SmsCbEtwsInfo.ETWS_WARNING_TYPE_EARTHQUAKE_AND_TSUNAMI: return R.string.etws_earthquake_and_tsunami_warning; case SmsCbEtwsInfo.ETWS_WARNING_TYPE_TEST_MESSAGE: return R.string.etws_test_message; case SmsCbEtwsInfo.ETWS_WARNING_TYPE_OTHER_EMERGENCY: default: return R.string.etws_other_emergency_type; } } SmsCbCmasInfo cmasInfo = message.getCmasWarningInfo(); int subId = message.getSubscriptionId(); CellBroadcastChannelManager channelManager = new CellBroadcastChannelManager( context, subId); final int serviceCategory = message.getServiceCategory(); if (channelManager.checkCellBroadcastChannelRange(serviceCategory, R.array.emergency_alerts_channels_range_strings)) { return R.string.pws_other_message_identifiers; } // CMAS warning types if (channelManager.checkCellBroadcastChannelRange(serviceCategory, R.array.cmas_presidential_alerts_channels_range_strings)) { return R.string.cmas_presidential_level_alert; } if (channelManager.checkCellBroadcastChannelRange(serviceCategory, R.array.cmas_alert_extreme_channels_range_strings)) { if (message.isCmasMessage()) { if (cmasInfo.getSeverity() == SmsCbCmasInfo.CMAS_SEVERITY_EXTREME && cmasInfo.getUrgency() == SmsCbCmasInfo.CMAS_URGENCY_IMMEDIATE) { if (cmasInfo.getCertainty() == SmsCbCmasInfo.CMAS_CERTAINTY_OBSERVED) { return R.string.cmas_extreme_immediate_observed_alert; } else if (cmasInfo.getCertainty() == SmsCbCmasInfo.CMAS_CERTAINTY_LIKELY) { return R.string.cmas_extreme_immediate_likely_alert; } } } return R.string.cmas_extreme_alert; } if (channelManager.checkCellBroadcastChannelRange(serviceCategory, R.array.cmas_alerts_severe_range_strings)) { return R.string.cmas_severe_alert; } if (channelManager.checkCellBroadcastChannelRange(serviceCategory, R.array.cmas_amber_alerts_channels_range_strings)) { return R.string.cmas_amber_alert; } if (channelManager.checkCellBroadcastChannelRange(serviceCategory, R.array.required_monthly_test_range_strings)) { return R.string.cmas_required_monthly_test; } if (channelManager.checkCellBroadcastChannelRange(serviceCategory, R.array.exercise_alert_range_strings)) { return R.string.cmas_exercise_alert; } if (channelManager.checkCellBroadcastChannelRange(serviceCategory, R.array.operator_defined_alert_range_strings)) { return R.string.cmas_operator_defined_alert; } if (channelManager.checkCellBroadcastChannelRange(serviceCategory, R.array.public_safety_messages_channels_range_strings)) { return R.string.public_safety_message; } if (channelManager.checkCellBroadcastChannelRange(serviceCategory, R.array.state_local_test_alert_range_strings)) { return R.string.state_local_test_alert; } if (channelManager.isEmergencyMessage(message)) { ArrayList ranges = channelManager.getCellBroadcastChannelRanges( R.array.additional_cbs_channels_strings); if (ranges != null) { for (CellBroadcastChannelRange range : ranges) { if (serviceCategory >= range.mStartId && serviceCategory <= range.mEndId) { // Apply the closest title to the specified tones. switch (range.mAlertType) { case DEFAULT: return R.string.pws_other_message_identifiers; case ETWS_EARTHQUAKE: return R.string.etws_earthquake_warning; case ETWS_TSUNAMI: return R.string.etws_tsunami_warning; case TEST: return R.string.etws_test_message; case ETWS_DEFAULT: case OTHER: return R.string.etws_other_emergency_type; } } } } return R.string.pws_other_message_identifiers; } else { return R.string.cb_other_message_identifiers; } } /** * Choose pictogram resource according to etws type. * * @param context Application context * @param message Cell broadcast message * * @return The resource of the pictogram, -1 if not available. */ static int getDialogPictogramResource(Context context, SmsCbMessage message) { SmsCbEtwsInfo etwsInfo = message.getEtwsWarningInfo(); if (etwsInfo != null) { switch (etwsInfo.getWarningType()) { case SmsCbEtwsInfo.ETWS_WARNING_TYPE_EARTHQUAKE: case SmsCbEtwsInfo.ETWS_WARNING_TYPE_EARTHQUAKE_AND_TSUNAMI: return R.drawable.pict_icon_earthquake; case SmsCbEtwsInfo.ETWS_WARNING_TYPE_TSUNAMI: return R.drawable.pict_icon_tsunami; } } final int serviceCategory = message.getServiceCategory(); int subId = message.getSubscriptionId(); CellBroadcastChannelManager channelManager = new CellBroadcastChannelManager( context, subId); if (channelManager.isEmergencyMessage(message)) { ArrayList ranges = channelManager.getCellBroadcastChannelRanges( R.array.additional_cbs_channels_strings); for (CellBroadcastChannelRange range : ranges) { if (serviceCategory >= range.mStartId && serviceCategory <= range.mEndId) { // Apply the closest title to the specified tones. switch (range.mAlertType) { case ETWS_EARTHQUAKE: return R.drawable.pict_icon_earthquake; case ETWS_TSUNAMI: return R.drawable.pict_icon_tsunami; } } } return -1; } return -1; } }