1 /* 2 * Copyright (C) 2010 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of 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, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.internal.telephony.gsm; 18 19 import android.telephony.SmsCbConstants; 20 21 public class SmsCbHeader implements SmsCbConstants { 22 /** 23 * Length of SMS-CB header 24 */ 25 public static final int PDU_HEADER_LENGTH = 6; 26 27 /** 28 * GSM pdu format, as defined in 3gpp TS 23.041, section 9.4.1 29 */ 30 public static final int FORMAT_GSM = 1; 31 32 /** 33 * UMTS pdu format, as defined in 3gpp TS 23.041, section 9.4.2 34 */ 35 public static final int FORMAT_UMTS = 2; 36 37 /** 38 * GSM pdu format, as defined in 3gpp TS 23.041, section 9.4.1.3 39 */ 40 public static final int FORMAT_ETWS_PRIMARY = 3; 41 42 /** 43 * Message type value as defined in 3gpp TS 25.324, section 11.1. 44 */ 45 private static final int MESSAGE_TYPE_CBS_MESSAGE = 1; 46 47 /** 48 * Length of GSM pdus 49 */ 50 public static final int PDU_LENGTH_GSM = 88; 51 52 /** 53 * Maximum length of ETWS primary message GSM pdus 54 */ 55 public static final int PDU_LENGTH_ETWS = 56; 56 57 public final int geographicalScope; 58 59 public final int messageCode; 60 61 public final int updateNumber; 62 63 public final int messageIdentifier; 64 65 public final int dataCodingScheme; 66 67 public final int pageIndex; 68 69 public final int nrOfPages; 70 71 public final int format; 72 73 public final boolean etwsEmergencyUserAlert; 74 75 public final boolean etwsPopup; 76 77 public final int etwsWarningType; 78 79 public SmsCbHeader(byte[] pdu) throws IllegalArgumentException { 80 if (pdu == null || pdu.length < PDU_HEADER_LENGTH) { 81 throw new IllegalArgumentException("Illegal PDU"); 82 } 83 84 if (pdu.length <= PDU_LENGTH_ETWS) { 85 format = FORMAT_ETWS_PRIMARY; 86 geographicalScope = -1; //not applicable 87 messageCode = -1; 88 updateNumber = -1; 89 messageIdentifier = ((pdu[2] & 0xff) << 8) | (pdu[3] & 0xff); 90 dataCodingScheme = -1; 91 pageIndex = -1; 92 nrOfPages = -1; 93 etwsEmergencyUserAlert = (pdu[4] & 0x1) != 0; 94 etwsPopup = (pdu[5] & 0x80) != 0; 95 etwsWarningType = (pdu[4] & 0xfe) >> 1; 96 } else if (pdu.length <= PDU_LENGTH_GSM) { 97 // GSM pdus are no more than 88 bytes 98 format = FORMAT_GSM; 99 geographicalScope = (pdu[0] & 0xc0) >> 6; 100 messageCode = ((pdu[0] & 0x3f) << 4) | ((pdu[1] & 0xf0) >> 4); 101 updateNumber = pdu[1] & 0x0f; 102 messageIdentifier = ((pdu[2] & 0xff) << 8) | (pdu[3] & 0xff); 103 dataCodingScheme = pdu[4] & 0xff; 104 105 // Check for invalid page parameter 106 int pageIndex = (pdu[5] & 0xf0) >> 4; 107 int nrOfPages = pdu[5] & 0x0f; 108 109 if (pageIndex == 0 || nrOfPages == 0 || pageIndex > nrOfPages) { 110 pageIndex = 1; 111 nrOfPages = 1; 112 } 113 114 this.pageIndex = pageIndex; 115 this.nrOfPages = nrOfPages; 116 etwsEmergencyUserAlert = false; 117 etwsPopup = false; 118 etwsWarningType = -1; 119 } else { 120 // UMTS pdus are always at least 90 bytes since the payload includes 121 // a number-of-pages octet and also one length octet per page 122 format = FORMAT_UMTS; 123 124 int messageType = pdu[0]; 125 126 if (messageType != MESSAGE_TYPE_CBS_MESSAGE) { 127 throw new IllegalArgumentException("Unsupported message type " + messageType); 128 } 129 130 messageIdentifier = ((pdu[1] & 0xff) << 8) | pdu[2] & 0xff; 131 geographicalScope = (pdu[3] & 0xc0) >> 6; 132 messageCode = ((pdu[3] & 0x3f) << 4) | ((pdu[4] & 0xf0) >> 4); 133 updateNumber = pdu[4] & 0x0f; 134 dataCodingScheme = pdu[5] & 0xff; 135 136 // We will always consider a UMTS message as having one single page 137 // since there's only one instance of the header, even though the 138 // actual payload may contain several pages. 139 pageIndex = 1; 140 nrOfPages = 1; 141 etwsEmergencyUserAlert = false; 142 etwsPopup = false; 143 etwsWarningType = -1; 144 } 145 } 146 147 /** 148 * Return whether the specified message ID is an emergency (PWS) message type. 149 * This method is static and takes an argument so that it can be used by 150 * CellBroadcastReceiver, which stores message ID's in SQLite rather than PDU. 151 * @param id the message identifier to check 152 * @return true if the message is emergency type; false otherwise 153 */ 154 public static boolean isEmergencyMessage(int id) { 155 return id >= MESSAGE_ID_PWS_FIRST_IDENTIFIER && id <= MESSAGE_ID_PWS_LAST_IDENTIFIER; 156 } 157 158 /** 159 * Return whether the specified message ID is an ETWS emergency message type. 160 * This method is static and takes an argument so that it can be used by 161 * CellBroadcastReceiver, which stores message ID's in SQLite rather than PDU. 162 * @param id the message identifier to check 163 * @return true if the message is ETWS emergency type; false otherwise 164 */ 165 public static boolean isEtwsMessage(int id) { 166 return (id & MESSAGE_ID_ETWS_TYPE_MASK) == MESSAGE_ID_ETWS_TYPE; 167 } 168 169 /** 170 * Return whether the specified message ID is a CMAS emergency message type. 171 * This method is static and takes an argument so that it can be used by 172 * CellBroadcastReceiver, which stores message ID's in SQLite rather than PDU. 173 * @param id the message identifier to check 174 * @return true if the message is CMAS emergency type; false otherwise 175 */ 176 public static boolean isCmasMessage(int id) { 177 return id >= MESSAGE_ID_CMAS_FIRST_IDENTIFIER && id <= MESSAGE_ID_CMAS_LAST_IDENTIFIER; 178 } 179 180 /** 181 * Return whether the specified message code indicates an ETWS popup alert. 182 * This method is static and takes an argument so that it can be used by 183 * CellBroadcastReceiver, which stores message codes in SQLite rather than PDU. 184 * This method assumes that the message ID has already been checked for ETWS type. 185 * 186 * @param messageCode the message code to check 187 * @return true if the message code indicates a popup alert should be displayed 188 */ 189 public static boolean isEtwsPopupAlert(int messageCode) { 190 return (messageCode & MESSAGE_CODE_ETWS_ACTIVATE_POPUP) != 0; 191 } 192 193 /** 194 * Return whether the specified message code indicates an ETWS emergency user alert. 195 * This method is static and takes an argument so that it can be used by 196 * CellBroadcastReceiver, which stores message codes in SQLite rather than PDU. 197 * This method assumes that the message ID has already been checked for ETWS type. 198 * 199 * @param messageCode the message code to check 200 * @return true if the message code indicates an emergency user alert 201 */ 202 public static boolean isEtwsEmergencyUserAlert(int messageCode) { 203 return (messageCode & MESSAGE_CODE_ETWS_EMERGENCY_USER_ALERT) != 0; 204 } 205 206 @Override 207 public String toString() { 208 return "SmsCbHeader{GS=" + geographicalScope + ", messageCode=0x" + 209 Integer.toHexString(messageCode) + ", updateNumber=" + updateNumber + 210 ", messageIdentifier=0x" + Integer.toHexString(messageIdentifier) + 211 ", DCS=0x" + Integer.toHexString(dataCodingScheme) + 212 ", page " + pageIndex + " of " + nrOfPages + '}'; 213 } 214 } 215