| /* |
| * Copyright (C) 2010 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.internal.telephony.gsm; |
| |
| import android.telephony.SmsCbConstants; |
| |
| public class SmsCbHeader implements SmsCbConstants { |
| /** |
| * Length of SMS-CB header |
| */ |
| public static final int PDU_HEADER_LENGTH = 6; |
| |
| /** |
| * GSM pdu format, as defined in 3gpp TS 23.041, section 9.4.1 |
| */ |
| public static final int FORMAT_GSM = 1; |
| |
| /** |
| * UMTS pdu format, as defined in 3gpp TS 23.041, section 9.4.2 |
| */ |
| public static final int FORMAT_UMTS = 2; |
| |
| /** |
| * GSM pdu format, as defined in 3gpp TS 23.041, section 9.4.1.3 |
| */ |
| public static final int FORMAT_ETWS_PRIMARY = 3; |
| |
| /** |
| * Message type value as defined in 3gpp TS 25.324, section 11.1. |
| */ |
| private static final int MESSAGE_TYPE_CBS_MESSAGE = 1; |
| |
| /** |
| * Length of GSM pdus |
| */ |
| public static final int PDU_LENGTH_GSM = 88; |
| |
| /** |
| * Maximum length of ETWS primary message GSM pdus |
| */ |
| public static final int PDU_LENGTH_ETWS = 56; |
| |
| public final int geographicalScope; |
| |
| public final int messageCode; |
| |
| public final int updateNumber; |
| |
| public final int messageIdentifier; |
| |
| public final int dataCodingScheme; |
| |
| public final int pageIndex; |
| |
| public final int nrOfPages; |
| |
| public final int format; |
| |
| public final boolean etwsEmergencyUserAlert; |
| |
| public final boolean etwsPopup; |
| |
| public final int etwsWarningType; |
| |
| public SmsCbHeader(byte[] pdu) throws IllegalArgumentException { |
| if (pdu == null || pdu.length < PDU_HEADER_LENGTH) { |
| throw new IllegalArgumentException("Illegal PDU"); |
| } |
| |
| if (pdu.length <= PDU_LENGTH_ETWS) { |
| format = FORMAT_ETWS_PRIMARY; |
| geographicalScope = -1; //not applicable |
| messageCode = -1; |
| updateNumber = -1; |
| messageIdentifier = ((pdu[2] & 0xff) << 8) | (pdu[3] & 0xff); |
| dataCodingScheme = -1; |
| pageIndex = -1; |
| nrOfPages = -1; |
| etwsEmergencyUserAlert = (pdu[4] & 0x1) != 0; |
| etwsPopup = (pdu[5] & 0x80) != 0; |
| etwsWarningType = (pdu[4] & 0xfe) >> 1; |
| } else if (pdu.length <= PDU_LENGTH_GSM) { |
| // GSM pdus are no more than 88 bytes |
| format = FORMAT_GSM; |
| geographicalScope = (pdu[0] & 0xc0) >> 6; |
| messageCode = ((pdu[0] & 0x3f) << 4) | ((pdu[1] & 0xf0) >> 4); |
| updateNumber = pdu[1] & 0x0f; |
| messageIdentifier = ((pdu[2] & 0xff) << 8) | (pdu[3] & 0xff); |
| dataCodingScheme = pdu[4] & 0xff; |
| |
| // Check for invalid page parameter |
| int pageIndex = (pdu[5] & 0xf0) >> 4; |
| int nrOfPages = pdu[5] & 0x0f; |
| |
| if (pageIndex == 0 || nrOfPages == 0 || pageIndex > nrOfPages) { |
| pageIndex = 1; |
| nrOfPages = 1; |
| } |
| |
| this.pageIndex = pageIndex; |
| this.nrOfPages = nrOfPages; |
| etwsEmergencyUserAlert = false; |
| etwsPopup = false; |
| etwsWarningType = -1; |
| } else { |
| // UMTS pdus are always at least 90 bytes since the payload includes |
| // a number-of-pages octet and also one length octet per page |
| format = FORMAT_UMTS; |
| |
| int messageType = pdu[0]; |
| |
| if (messageType != MESSAGE_TYPE_CBS_MESSAGE) { |
| throw new IllegalArgumentException("Unsupported message type " + messageType); |
| } |
| |
| messageIdentifier = ((pdu[1] & 0xff) << 8) | pdu[2] & 0xff; |
| geographicalScope = (pdu[3] & 0xc0) >> 6; |
| messageCode = ((pdu[3] & 0x3f) << 4) | ((pdu[4] & 0xf0) >> 4); |
| updateNumber = pdu[4] & 0x0f; |
| dataCodingScheme = pdu[5] & 0xff; |
| |
| // We will always consider a UMTS message as having one single page |
| // since there's only one instance of the header, even though the |
| // actual payload may contain several pages. |
| pageIndex = 1; |
| nrOfPages = 1; |
| etwsEmergencyUserAlert = false; |
| etwsPopup = false; |
| etwsWarningType = -1; |
| } |
| } |
| |
| /** |
| * Return whether the specified message ID is an emergency (PWS) message type. |
| * This method is static and takes an argument so that it can be used by |
| * CellBroadcastReceiver, which stores message ID's in SQLite rather than PDU. |
| * @param id the message identifier to check |
| * @return true if the message is emergency type; false otherwise |
| */ |
| public static boolean isEmergencyMessage(int id) { |
| return id >= MESSAGE_ID_PWS_FIRST_IDENTIFIER && id <= MESSAGE_ID_PWS_LAST_IDENTIFIER; |
| } |
| |
| /** |
| * Return whether the specified message ID is an ETWS emergency message type. |
| * This method is static and takes an argument so that it can be used by |
| * CellBroadcastReceiver, which stores message ID's in SQLite rather than PDU. |
| * @param id the message identifier to check |
| * @return true if the message is ETWS emergency type; false otherwise |
| */ |
| public static boolean isEtwsMessage(int id) { |
| return (id & MESSAGE_ID_ETWS_TYPE_MASK) == MESSAGE_ID_ETWS_TYPE; |
| } |
| |
| /** |
| * Return whether the specified message ID is a CMAS emergency message type. |
| * This method is static and takes an argument so that it can be used by |
| * CellBroadcastReceiver, which stores message ID's in SQLite rather than PDU. |
| * @param id the message identifier to check |
| * @return true if the message is CMAS emergency type; false otherwise |
| */ |
| public static boolean isCmasMessage(int id) { |
| return id >= MESSAGE_ID_CMAS_FIRST_IDENTIFIER && id <= MESSAGE_ID_CMAS_LAST_IDENTIFIER; |
| } |
| |
| /** |
| * Return whether the specified message code indicates an ETWS popup alert. |
| * This method is static and takes an argument so that it can be used by |
| * CellBroadcastReceiver, which stores message codes in SQLite rather than PDU. |
| * This method assumes that the message ID has already been checked for ETWS type. |
| * |
| * @param messageCode the message code to check |
| * @return true if the message code indicates a popup alert should be displayed |
| */ |
| public static boolean isEtwsPopupAlert(int messageCode) { |
| return (messageCode & MESSAGE_CODE_ETWS_ACTIVATE_POPUP) != 0; |
| } |
| |
| /** |
| * Return whether the specified message code indicates an ETWS emergency user alert. |
| * This method is static and takes an argument so that it can be used by |
| * CellBroadcastReceiver, which stores message codes in SQLite rather than PDU. |
| * This method assumes that the message ID has already been checked for ETWS type. |
| * |
| * @param messageCode the message code to check |
| * @return true if the message code indicates an emergency user alert |
| */ |
| public static boolean isEtwsEmergencyUserAlert(int messageCode) { |
| return (messageCode & MESSAGE_CODE_ETWS_EMERGENCY_USER_ALERT) != 0; |
| } |
| |
| @Override |
| public String toString() { |
| return "SmsCbHeader{GS=" + geographicalScope + ", messageCode=0x" + |
| Integer.toHexString(messageCode) + ", updateNumber=" + updateNumber + |
| ", messageIdentifier=0x" + Integer.toHexString(messageIdentifier) + |
| ", DCS=0x" + Integer.toHexString(dataCodingScheme) + |
| ", page " + pageIndex + " of " + nrOfPages + '}'; |
| } |
| } |