Home | History | Annotate | Download | only in gsm
      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