Files
frameworks_base/telephony/java/android/telephony/SmsCbMessage.java
Henrik Hall 95bc625e29 Enabling cell broadcast (SMS-CB) support in the platform.
Adding a simple API enabling applications to control SMS-CB reception.
Implementing parsing, assembly and dispatching of SMS-CB messages over GSM.

Change-Id: Iee841605a45a3af60c7602af175056afb03a38da
2010-11-19 15:00:00 +01:00

268 lines
7.7 KiB
Java

/*
* 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 android.telephony;
import com.android.internal.telephony.GsmAlphabet;
import com.android.internal.telephony.gsm.SmsCbHeader;
import java.io.UnsupportedEncodingException;
/**
* Describes an SMS-CB message.
*
* {@hide}
*/
public class SmsCbMessage {
/**
* Cell wide immediate geographical scope
*/
public static final int GEOGRAPHICAL_SCOPE_CELL_WIDE_IMMEDIATE = 0;
/**
* PLMN wide geographical scope
*/
public static final int GEOGRAPHICAL_SCOPE_PLMN_WIDE = 1;
/**
* Location / service area wide geographical scope
*/
public static final int GEOGRAPHICAL_SCOPE_LA_WIDE = 2;
/**
* Cell wide geographical scope
*/
public static final int GEOGRAPHICAL_SCOPE_CELL_WIDE = 3;
/**
* Create an instance of this class from a received PDU
*
* @param pdu PDU bytes
* @return An instance of this class, or null if invalid pdu
*/
public static SmsCbMessage createFromPdu(byte[] pdu) {
try {
return new SmsCbMessage(pdu);
} catch (IllegalArgumentException e) {
return null;
}
}
/**
* Languages in the 0000xxxx DCS group as defined in 3GPP TS 23.038, section 5.
*/
private static final String[] LANGUAGE_CODES_GROUP_0 = {
"de", "en", "it", "fr", "es", "nl", "sv", "da", "pt", "fi", "no", "el", "tr", "hu",
"pl", null
};
/**
* Languages in the 0010xxxx DCS group as defined in 3GPP TS 23.038, section 5.
*/
private static final String[] LANGUAGE_CODES_GROUP_2 = {
"cs", "he", "ar", "ru", "is", null, null, null, null, null, null, null, null, null,
null, null
};
private static final char CARRIAGE_RETURN = 0x0d;
private SmsCbHeader mHeader;
private String mLanguage;
private String mBody;
private SmsCbMessage(byte[] pdu) throws IllegalArgumentException {
mHeader = new SmsCbHeader(pdu);
parseBody(pdu);
}
/**
* Return the geographical scope of this message, one of
* {@link #GEOGRAPHICAL_SCOPE_CELL_WIDE_IMMEDIATE},
* {@link #GEOGRAPHICAL_SCOPE_PLMN_WIDE},
* {@link #GEOGRAPHICAL_SCOPE_LA_WIDE},
* {@link #GEOGRAPHICAL_SCOPE_CELL_WIDE}
*
* @return Geographical scope
*/
public int getGeographicalScope() {
return mHeader.geographicalScope;
}
/**
* Get the ISO-639-1 language code for this message, or null if unspecified
*
* @return Language code
*/
public String getLanguageCode() {
return mLanguage;
}
/**
* Get the body of this message, or null if no body available
*
* @return Body, or null
*/
public String getMessageBody() {
return mBody;
}
/**
* Get the message identifier of this message (0-65535)
*
* @return Message identifier
*/
public int getMessageIdentifier() {
return mHeader.messageIdentifier;
}
/**
* Get the message code of this message (0-1023)
*
* @return Message code
*/
public int getMessageCode() {
return mHeader.messageCode;
}
/**
* Get the update number of this message (0-15)
*
* @return Update number
*/
public int getUpdateNumber() {
return mHeader.updateNumber;
}
private void parseBody(byte[] pdu) {
int encoding;
boolean hasLanguageIndicator = false;
// Extract encoding and language from DCS, as defined in 3gpp TS 23.038,
// section 5.
switch ((mHeader.dataCodingScheme & 0xf0) >> 4) {
case 0x00:
encoding = SmsMessage.ENCODING_7BIT;
mLanguage = LANGUAGE_CODES_GROUP_0[mHeader.dataCodingScheme & 0x0f];
break;
case 0x01:
hasLanguageIndicator = true;
if ((mHeader.dataCodingScheme & 0x0f) == 0x01) {
encoding = SmsMessage.ENCODING_16BIT;
} else {
encoding = SmsMessage.ENCODING_7BIT;
}
break;
case 0x02:
encoding = SmsMessage.ENCODING_7BIT;
mLanguage = LANGUAGE_CODES_GROUP_2[mHeader.dataCodingScheme & 0x0f];
break;
case 0x03:
encoding = SmsMessage.ENCODING_7BIT;
break;
case 0x04:
case 0x05:
switch ((mHeader.dataCodingScheme & 0x0c) >> 2) {
case 0x01:
encoding = SmsMessage.ENCODING_8BIT;
break;
case 0x02:
encoding = SmsMessage.ENCODING_16BIT;
break;
case 0x00:
default:
encoding = SmsMessage.ENCODING_7BIT;
break;
}
break;
case 0x06:
case 0x07:
// Compression not supported
case 0x09:
// UDH structure not supported
case 0x0e:
// Defined by the WAP forum not supported
encoding = SmsMessage.ENCODING_UNKNOWN;
break;
case 0x0f:
if (((mHeader.dataCodingScheme & 0x04) >> 2) == 0x01) {
encoding = SmsMessage.ENCODING_8BIT;
} else {
encoding = SmsMessage.ENCODING_7BIT;
}
break;
default:
// Reserved values are to be treated as 7-bit
encoding = SmsMessage.ENCODING_7BIT;
break;
}
switch (encoding) {
case SmsMessage.ENCODING_7BIT:
mBody = GsmAlphabet.gsm7BitPackedToString(pdu, SmsCbHeader.PDU_HEADER_LENGTH,
(pdu.length - SmsCbHeader.PDU_HEADER_LENGTH) * 8 / 7);
if (hasLanguageIndicator && mBody != null && mBody.length() > 2) {
mLanguage = mBody.substring(0, 2);
mBody = mBody.substring(3);
}
break;
case SmsMessage.ENCODING_16BIT:
int offset = SmsCbHeader.PDU_HEADER_LENGTH;
if (hasLanguageIndicator && pdu.length >= SmsCbHeader.PDU_HEADER_LENGTH + 2) {
mLanguage = GsmAlphabet.gsm7BitPackedToString(pdu,
SmsCbHeader.PDU_HEADER_LENGTH, 2);
offset += 2;
}
try {
mBody = new String(pdu, offset, (pdu.length & 0xfffe) - offset, "utf-16");
} catch (UnsupportedEncodingException e) {
// Eeeek
}
break;
default:
break;
}
if (mBody != null) {
// Remove trailing carriage return
for (int i = mBody.length() - 1; i >= 0; i--) {
if (mBody.charAt(i) != CARRIAGE_RETURN) {
mBody = mBody.substring(0, i + 1);
break;
}
}
} else {
mBody = "";
}
}
}