Implement CMAS service category program results.

Correctly handle CDMA Service Category Program Data requests,
and send the SCPT response to the message center. Parcel SCPD
operations as an ArrayList instead of an array (current version
will throw ClassCastException when the array is cast).

Bug: 6853691
Change-Id: I949ea68891c78306059248832e59a593ab606e11
This commit is contained in:
Jake Hamby
2012-07-24 15:39:45 -07:00
parent 8d6ff012ed
commit 7b661fb3fc
7 changed files with 287 additions and 29 deletions

View File

@@ -81,8 +81,8 @@ public class CdmaSmsCbProgramData implements Parcelable {
/** Service category to modify. */ /** Service category to modify. */
private final int mCategory; private final int mCategory;
/** Language used for service category name (ISO 639 two character code). */ /** Language used for service category name (defined in BearerData.LANGUAGE_*). */
private final String mLanguage; private final int mLanguage;
/** Maximum number of messages to store for this service category. */ /** Maximum number of messages to store for this service category. */
private final int mMaxMessages; private final int mMaxMessages;
@@ -94,7 +94,7 @@ public class CdmaSmsCbProgramData implements Parcelable {
private final String mCategoryName; private final String mCategoryName;
/** Create a new CdmaSmsCbProgramData object with the specified values. */ /** Create a new CdmaSmsCbProgramData object with the specified values. */
public CdmaSmsCbProgramData(int operation, int category, String language, int maxMessages, public CdmaSmsCbProgramData(int operation, int category, int language, int maxMessages,
int alertOption, String categoryName) { int alertOption, String categoryName) {
mOperation = operation; mOperation = operation;
mCategory = category; mCategory = category;
@@ -108,7 +108,7 @@ public class CdmaSmsCbProgramData implements Parcelable {
CdmaSmsCbProgramData(Parcel in) { CdmaSmsCbProgramData(Parcel in) {
mOperation = in.readInt(); mOperation = in.readInt();
mCategory = in.readInt(); mCategory = in.readInt();
mLanguage = in.readString(); mLanguage = in.readInt();
mMaxMessages = in.readInt(); mMaxMessages = in.readInt();
mAlertOption = in.readInt(); mAlertOption = in.readInt();
mCategoryName = in.readString(); mCategoryName = in.readString();
@@ -124,7 +124,7 @@ public class CdmaSmsCbProgramData implements Parcelable {
public void writeToParcel(Parcel dest, int flags) { public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(mOperation); dest.writeInt(mOperation);
dest.writeInt(mCategory); dest.writeInt(mCategory);
dest.writeString(mLanguage); dest.writeInt(mLanguage);
dest.writeInt(mMaxMessages); dest.writeInt(mMaxMessages);
dest.writeInt(mAlertOption); dest.writeInt(mAlertOption);
dest.writeString(mCategoryName); dest.writeString(mCategoryName);
@@ -147,10 +147,10 @@ public class CdmaSmsCbProgramData implements Parcelable {
} }
/** /**
* Returns the ISO-639-1 language code for the service category name, or null if not present. * Returns the CDMA language code for this service category.
* @return a two-digit ISO-639-1 language code, e.g. "en" for English * @return one of the language values defined in BearerData.LANGUAGE_*
*/ */
public String getLanguageCode() { public int getLanguage() {
return mLanguage; return mLanguage;
} }
@@ -171,7 +171,7 @@ public class CdmaSmsCbProgramData implements Parcelable {
} }
/** /**
* Returns the service category name, in the language specified by {@link #getLanguageCode()}. * Returns the service category name, in the language specified by {@link #getLanguage()}.
* @return an optional service category name * @return an optional service category name
*/ */
public String getCategoryName() { public String getCategoryName() {

View File

@@ -0,0 +1,144 @@
/*
* Copyright (C) 2012 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.cdma;
import android.os.Parcel;
import android.os.Parcelable;
/**
* CDMA Service Category Program Results from SCPT teleservice SMS.
*
* {@hide}
*/
public class CdmaSmsCbProgramResults implements Parcelable {
/** Program result: success. */
public static final int RESULT_SUCCESS = 0;
/** Program result: memory limit exceeded. */
public static final int RESULT_MEMORY_LIMIT_EXCEEDED = 1;
/** Program result: limit exceeded. */
public static final int RESULT_CATEGORY_LIMIT_EXCEEDED = 2;
/** Program result: category already opted in. */
public static final int RESULT_CATEGORY_ALREADY_ADDED = 3;
/** Program result: category already opted in. */
public static final int RESULT_CATEGORY_ALREADY_DELETED = 4;
/** Program result: invalid MAX_MESSAGES. */
public static final int RESULT_INVALID_MAX_MESSAGES = 5;
/** Program result: invalid ALERT_OPTION. */
public static final int RESULT_INVALID_ALERT_OPTION = 6;
/** Program result: invalid service category name. */
public static final int RESULT_INVALID_CATEGORY_NAME = 7;
/** Program result: unspecified programming failure. */
public static final int RESULT_UNSPECIFIED_FAILURE = 8;
/** Service category to modify. */
private final int mCategory;
/** Language used for service category name (defined in BearerData.LANGUAGE_*). */
private final int mLanguage;
/** Result of service category programming for this category. */
private final int mCategoryResult;
/** Create a new CdmaSmsCbProgramResults object with the specified values. */
public CdmaSmsCbProgramResults(int category, int language, int categoryResult) {
mCategory = category;
mLanguage = language;
mCategoryResult = categoryResult;
}
/** Create a new CdmaSmsCbProgramResults object from a Parcel. */
CdmaSmsCbProgramResults(Parcel in) {
mCategory = in.readInt();
mLanguage = in.readInt();
mCategoryResult = in.readInt();
}
/**
* Flatten this object into a Parcel.
*
* @param dest The Parcel in which the object should be written.
* @param flags Additional flags about how the object should be written (ignored).
*/
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(mCategory);
dest.writeInt(mLanguage);
dest.writeInt(mCategoryResult);
}
/**
* Returns the CDMA service category to modify.
* @return a 16-bit CDMA service category value
*/
public int getCategory() {
return mCategory;
}
/**
* Returns the CDMA language code for this service category.
* @return one of the language values defined in BearerData.LANGUAGE_*
*/
public int getLanguage() {
return mLanguage;
}
/**
* Returns the result of service programming for this category
* @return the result of service programming for this category
*/
public int getCategoryResult() {
return mCategoryResult;
}
@Override
public String toString() {
return "CdmaSmsCbProgramResults{category=" + mCategory
+ ", language=" + mLanguage + ", result=" + mCategoryResult + '}';
}
/**
* Describe the kinds of special objects contained in the marshalled representation.
* @return a bitmask indicating this Parcelable contains no special objects
*/
@Override
public int describeContents() {
return 0;
}
/** Creator for unparcelling objects. */
public static final Parcelable.Creator<CdmaSmsCbProgramResults>
CREATOR = new Parcelable.Creator<CdmaSmsCbProgramResults>() {
@Override
public CdmaSmsCbProgramResults createFromParcel(Parcel in) {
return new CdmaSmsCbProgramResults(in);
}
@Override
public CdmaSmsCbProgramResults[] newArray(int size) {
return new CdmaSmsCbProgramResults[size];
}
};
}

View File

@@ -338,6 +338,22 @@ public abstract class SMSDispatcher extends Handler {
this, Activity.RESULT_OK, null, null); this, Activity.RESULT_OK, null, null);
} }
/**
* Grabs a wake lock and sends intent as an ordered broadcast.
* Used for setting a custom result receiver for CDMA SCPD.
*
* @param intent intent to broadcast
* @param permission Receivers are required to have this permission
* @param resultReceiver the result receiver to use
*/
public void dispatch(Intent intent, String permission, BroadcastReceiver resultReceiver) {
// Hold a wake lock for WAKE_LOCK_TIMEOUT seconds, enough to give any
// receivers time to take their own wake locks.
mWakeLock.acquire(WAKE_LOCK_TIMEOUT);
mContext.sendOrderedBroadcast(intent, permission, resultReceiver,
this, Activity.RESULT_OK, null, null);
}
/** /**
* Called when SMS send completes. Broadcasts a sentIntent on success. * Called when SMS send completes. Broadcasts a sentIntent on success.
* On failure, either sets up retries or broadcasts a sentIntent with * On failure, either sets up retries or broadcasts a sentIntent with

View File

@@ -20,20 +20,23 @@ package com.android.internal.telephony.cdma;
import android.app.Activity; import android.app.Activity;
import android.app.PendingIntent; import android.app.PendingIntent;
import android.app.PendingIntent.CanceledException; import android.app.PendingIntent.CanceledException;
import android.content.ContentValues; import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.database.Cursor; import android.content.res.Resources;
import android.database.SQLException; import android.os.Bundle;
import android.os.Message; import android.os.Message;
import android.os.SystemProperties; import android.os.SystemProperties;
import android.preference.PreferenceManager; import android.preference.PreferenceManager;
import android.provider.Telephony; import android.provider.Telephony;
import android.provider.Telephony.Sms.Intents; import android.provider.Telephony.Sms.Intents;
import android.telephony.PhoneNumberUtils;
import android.telephony.SmsCbMessage; import android.telephony.SmsCbMessage;
import android.telephony.SmsManager; import android.telephony.SmsManager;
import android.telephony.SmsMessage.MessageClass; import android.telephony.SmsMessage.MessageClass;
import android.telephony.cdma.CdmaSmsCbProgramData; import android.telephony.cdma.CdmaSmsCbProgramData;
import android.telephony.cdma.CdmaSmsCbProgramResults;
import android.util.Log; import android.util.Log;
import com.android.internal.telephony.CommandsInterface; import com.android.internal.telephony.CommandsInterface;
@@ -45,16 +48,17 @@ import com.android.internal.telephony.SmsStorageMonitor;
import com.android.internal.telephony.SmsUsageMonitor; import com.android.internal.telephony.SmsUsageMonitor;
import com.android.internal.telephony.TelephonyProperties; import com.android.internal.telephony.TelephonyProperties;
import com.android.internal.telephony.WspTypeDecoder; import com.android.internal.telephony.WspTypeDecoder;
import com.android.internal.telephony.cdma.sms.BearerData;
import com.android.internal.telephony.cdma.sms.CdmaSmsAddress;
import com.android.internal.telephony.cdma.sms.SmsEnvelope; import com.android.internal.telephony.cdma.sms.SmsEnvelope;
import com.android.internal.telephony.cdma.sms.UserData; import com.android.internal.telephony.cdma.sms.UserData;
import com.android.internal.util.HexDump;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashMap; import java.util.HashMap;
import java.util.List;
import android.content.res.Resources;
final class CdmaSMSDispatcher extends SMSDispatcher { final class CdmaSMSDispatcher extends SMSDispatcher {
@@ -107,15 +111,16 @@ final class CdmaSMSDispatcher extends SMSDispatcher {
* {@link android.telephony.cdma.CdmaSmsCbProgramData} objects. * {@link android.telephony.cdma.CdmaSmsCbProgramData} objects.
*/ */
private void handleServiceCategoryProgramData(SmsMessage sms) { private void handleServiceCategoryProgramData(SmsMessage sms) {
List<CdmaSmsCbProgramData> programDataList = sms.getSmsCbProgramData(); ArrayList<CdmaSmsCbProgramData> programDataList = sms.getSmsCbProgramData();
if (programDataList == null) { if (programDataList == null) {
Log.e(TAG, "handleServiceCategoryProgramData: program data list is null!"); Log.e(TAG, "handleServiceCategoryProgramData: program data list is null!");
return; return;
} }
Intent intent = new Intent(Intents.SMS_SERVICE_CATEGORY_PROGRAM_DATA_RECEIVED_ACTION); Intent intent = new Intent(Intents.SMS_SERVICE_CATEGORY_PROGRAM_DATA_RECEIVED_ACTION);
intent.putExtra("program_data_list", (CdmaSmsCbProgramData[]) programDataList.toArray()); intent.putExtra("sender", sms.getOriginatingAddress());
dispatch(intent, RECEIVE_SMS_PERMISSION); intent.putParcelableArrayListExtra("program_data", programDataList);
dispatch(intent, RECEIVE_SMS_PERMISSION, mScpResultsReceiver);
} }
/** {@inheritDoc} */ /** {@inheritDoc} */
@@ -425,4 +430,72 @@ final class CdmaSMSDispatcher extends SMSDispatcher {
} }
return false; return false;
} }
// Receiver for Service Category Program Data results.
// We already ACK'd the original SCPD SMS, so this sends a new response SMS.
// TODO: handle retries if the RIL returns an error.
private final BroadcastReceiver mScpResultsReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
int rc = getResultCode();
boolean success = (rc == Activity.RESULT_OK) || (rc == Intents.RESULT_SMS_HANDLED);
if (!success) {
Log.e(TAG, "SCP results error: result code = " + rc);
return;
}
Bundle extras = getResultExtras(false);
if (extras == null) {
Log.e(TAG, "SCP results error: missing extras");
return;
}
String sender = extras.getString("sender");
if (sender == null) {
Log.e(TAG, "SCP results error: missing sender extra.");
return;
}
ArrayList<CdmaSmsCbProgramResults> results
= extras.getParcelableArrayList("results");
if (results == null) {
Log.e(TAG, "SCP results error: missing results extra.");
return;
}
BearerData bData = new BearerData();
bData.messageType = BearerData.MESSAGE_TYPE_SUBMIT;
bData.messageId = SmsMessage.getNextMessageId();
bData.serviceCategoryProgramResults = results;
byte[] encodedBearerData = BearerData.encode(bData);
ByteArrayOutputStream baos = new ByteArrayOutputStream(100);
DataOutputStream dos = new DataOutputStream(baos);
try {
dos.writeInt(SmsEnvelope.TELESERVICE_SCPT);
dos.writeInt(0); //servicePresent
dos.writeInt(0); //serviceCategory
CdmaSmsAddress destAddr = CdmaSmsAddress.parse(
PhoneNumberUtils.cdmaCheckAndProcessPlusCode(sender));
dos.write(destAddr.digitMode);
dos.write(destAddr.numberMode);
dos.write(destAddr.ton); // number_type
dos.write(destAddr.numberPlan);
dos.write(destAddr.numberOfDigits);
dos.write(destAddr.origBytes, 0, destAddr.origBytes.length); // digits
// Subaddress is not supported.
dos.write(0); //subaddressType
dos.write(0); //subaddr_odd
dos.write(0); //subaddr_nbr_of_digits
dos.write(encodedBearerData.length);
dos.write(encodedBearerData, 0, encodedBearerData.length);
// Ignore the RIL response. TODO: implement retry if SMS send fails.
mCm.sendCdmaSms(baos.toByteArray(), null);
} catch (IOException e) {
Log.e(TAG, "exception creating SCP results PDU", e);
} finally {
try {
dos.close();
} catch (IOException ignored) {
}
}
}
};
} }

View File

@@ -42,6 +42,7 @@ import java.io.ByteArrayOutputStream;
import java.io.DataInputStream; import java.io.DataInputStream;
import java.io.DataOutputStream; import java.io.DataOutputStream;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import static android.telephony.SmsMessage.MessageClass; import static android.telephony.SmsMessage.MessageClass;
@@ -781,7 +782,7 @@ public class SmsMessage extends SmsMessageBase {
* binder-call, and hence should be thread-safe, it has been * binder-call, and hence should be thread-safe, it has been
* synchronized. * synchronized.
*/ */
private synchronized static int getNextMessageId() { synchronized static int getNextMessageId() {
// Testing and dialog with partners has indicated that // Testing and dialog with partners has indicated that
// msgId==0 is (sometimes?) treated specially by lower levels. // msgId==0 is (sometimes?) treated specially by lower levels.
// Specifically, the ID is not preserved for delivery ACKs. // Specifically, the ID is not preserved for delivery ACKs.
@@ -997,7 +998,7 @@ public class SmsMessage extends SmsMessageBase {
* Returns the list of service category program data, if present. * Returns the list of service category program data, if present.
* @return a list of CdmaSmsCbProgramData objects, or null if not present * @return a list of CdmaSmsCbProgramData objects, or null if not present
*/ */
List<CdmaSmsCbProgramData> getSmsCbProgramData() { ArrayList<CdmaSmsCbProgramData> getSmsCbProgramData() {
return mBearerData.serviceCategoryProgramData; return mBearerData.serviceCategoryProgramData;
} }
} }

View File

@@ -18,9 +18,9 @@ package com.android.internal.telephony.cdma.sms;
import android.content.res.Resources; import android.content.res.Resources;
import android.telephony.SmsCbCmasInfo; import android.telephony.SmsCbCmasInfo;
import android.telephony.SmsCbMessage;
import android.telephony.SmsMessage; import android.telephony.SmsMessage;
import android.telephony.cdma.CdmaSmsCbProgramData; import android.telephony.cdma.CdmaSmsCbProgramData;
import android.telephony.cdma.CdmaSmsCbProgramResults;
import android.text.format.Time; import android.text.format.Time;
import android.util.Log; import android.util.Log;
@@ -32,8 +32,6 @@ import com.android.internal.util.BitwiseInputStream;
import com.android.internal.util.BitwiseOutputStream; import com.android.internal.util.BitwiseOutputStream;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.TimeZone; import java.util.TimeZone;
import static android.telephony.SmsMessage.ENCODING_16BIT; import static android.telephony.SmsMessage.ENCODING_16BIT;
@@ -353,7 +351,14 @@ public final class BearerData {
* {@link android.telephony.cdma.CdmaSmsCbProgramData} objects containing the * {@link android.telephony.cdma.CdmaSmsCbProgramData} objects containing the
* operation(s) to perform. * operation(s) to perform.
*/ */
public List<CdmaSmsCbProgramData> serviceCategoryProgramData; public ArrayList<CdmaSmsCbProgramData> serviceCategoryProgramData;
/**
* The Service Category Program Results subparameter informs the message center
* of the results of a Service Category Program Data request.
*/
public ArrayList<CdmaSmsCbProgramResults> serviceCategoryProgramResults;
private static class CodingException extends Exception { private static class CodingException extends Exception {
public CodingException(String s) { public CodingException(String s) {
@@ -857,6 +862,21 @@ public final class BearerData {
outStream.skip(6); outStream.skip(6);
} }
private static void encodeScpResults(BearerData bData, BitwiseOutputStream outStream)
throws BitwiseOutputStream.AccessException
{
ArrayList<CdmaSmsCbProgramResults> results = bData.serviceCategoryProgramResults;
outStream.write(8, (results.size() * 4)); // 4 octets per program result
for (CdmaSmsCbProgramResults result : results) {
int category = result.getCategory();
outStream.write(8, category >> 8);
outStream.write(8, category);
outStream.write(8, result.getLanguage());
outStream.write(4, result.getCategoryResult());
outStream.skip(4);
}
}
/** /**
* Create serialized representation for BearerData object. * Create serialized representation for BearerData object.
* (See 3GPP2 C.R1001-F, v1.0, section 4.5 for layout details) * (See 3GPP2 C.R1001-F, v1.0, section 4.5 for layout details)
@@ -916,6 +936,10 @@ public final class BearerData {
outStream.write(8, SUBPARAM_MESSAGE_STATUS); outStream.write(8, SUBPARAM_MESSAGE_STATUS);
encodeMsgStatus(bData, outStream); encodeMsgStatus(bData, outStream);
} }
if (bData.serviceCategoryProgramResults != null) {
outStream.write(8, SUBPARAM_SERVICE_CATEGORY_PROGRAM_RESULTS);
encodeScpResults(bData, outStream);
}
return outStream.toByteArray(); return outStream.toByteArray();
} catch (BitwiseOutputStream.AccessException ex) { } catch (BitwiseOutputStream.AccessException ex) {
Log.e(LOG_TAG, "BearerData encode failed: " + ex); Log.e(LOG_TAG, "BearerData encode failed: " + ex);
@@ -1638,7 +1662,7 @@ public final class BearerData {
while (paramBits >= CATEGORY_FIELD_MIN_SIZE) { while (paramBits >= CATEGORY_FIELD_MIN_SIZE) {
int operation = inStream.read(4); int operation = inStream.read(4);
int category = (inStream.read(8) << 8) | inStream.read(8); int category = (inStream.read(8) << 8) | inStream.read(8);
String language = getLanguageCodeForValue(inStream.read(8)); int language = inStream.read(8);
int maxMessages = inStream.read(8); int maxMessages = inStream.read(8);
int alertOption = inStream.read(4); int alertOption = inStream.read(4);
int numFields = inStream.read(8); int numFields = inStream.read(8);

View File

@@ -635,7 +635,7 @@ public class CdmaSmsCbTest extends AndroidTestCase {
assertEquals(CdmaSmsCbProgramData.OPERATION_ADD_CATEGORY, programData.getOperation()); assertEquals(CdmaSmsCbProgramData.OPERATION_ADD_CATEGORY, programData.getOperation());
assertEquals(SmsEnvelope.SERVICE_CATEGORY_CMAS_EXTREME_THREAT, programData.getCategory()); assertEquals(SmsEnvelope.SERVICE_CATEGORY_CMAS_EXTREME_THREAT, programData.getCategory());
assertEquals(CAT_EXTREME_THREAT, programData.getCategoryName()); assertEquals(CAT_EXTREME_THREAT, programData.getCategoryName());
assertEquals("en", programData.getLanguageCode()); assertEquals(BearerData.LANGUAGE_ENGLISH, programData.getLanguage());
assertEquals(100, programData.getMaxMessages()); assertEquals(100, programData.getMaxMessages());
assertEquals(CdmaSmsCbProgramData.ALERT_OPTION_DEFAULT_ALERT, programData.getAlertOption()); assertEquals(CdmaSmsCbProgramData.ALERT_OPTION_DEFAULT_ALERT, programData.getAlertOption());
} }
@@ -692,7 +692,7 @@ public class CdmaSmsCbTest extends AndroidTestCase {
assertEquals(CdmaSmsCbProgramData.OPERATION_DELETE_CATEGORY, programData.getOperation()); assertEquals(CdmaSmsCbProgramData.OPERATION_DELETE_CATEGORY, programData.getOperation());
assertEquals(SmsEnvelope.SERVICE_CATEGORY_CMAS_SEVERE_THREAT, programData.getCategory()); assertEquals(SmsEnvelope.SERVICE_CATEGORY_CMAS_SEVERE_THREAT, programData.getCategory());
assertEquals(CAT_SEVERE_THREAT, programData.getCategoryName()); assertEquals(CAT_SEVERE_THREAT, programData.getCategoryName());
assertEquals("en", programData.getLanguageCode()); assertEquals(BearerData.LANGUAGE_ENGLISH, programData.getLanguage());
assertEquals(0, programData.getMaxMessages()); assertEquals(0, programData.getMaxMessages());
assertEquals(CdmaSmsCbProgramData.ALERT_OPTION_NO_ALERT, programData.getAlertOption()); assertEquals(CdmaSmsCbProgramData.ALERT_OPTION_NO_ALERT, programData.getAlertOption());
@@ -701,7 +701,7 @@ public class CdmaSmsCbTest extends AndroidTestCase {
assertEquals(SmsEnvelope.SERVICE_CATEGORY_CMAS_CHILD_ABDUCTION_EMERGENCY, assertEquals(SmsEnvelope.SERVICE_CATEGORY_CMAS_CHILD_ABDUCTION_EMERGENCY,
programData.getCategory()); programData.getCategory());
assertEquals(CAT_AMBER_ALERTS, programData.getCategoryName()); assertEquals(CAT_AMBER_ALERTS, programData.getCategoryName());
assertEquals("en", programData.getLanguageCode()); assertEquals(BearerData.LANGUAGE_ENGLISH, programData.getLanguage());
assertEquals(0, programData.getMaxMessages()); assertEquals(0, programData.getMaxMessages());
assertEquals(CdmaSmsCbProgramData.ALERT_OPTION_NO_ALERT, programData.getAlertOption()); assertEquals(CdmaSmsCbProgramData.ALERT_OPTION_NO_ALERT, programData.getAlertOption());
} }