Merge "Add support for SMS-PP data download to USIM."
This commit is contained in:
@@ -157,6 +157,8 @@ public interface CommandsInterface {
|
||||
|
||||
// GSM SMS fail cause for acknowledgeLastIncomingSMS. From TS 23.040, 9.2.3.22.
|
||||
static final int GSM_SMS_FAIL_CAUSE_MEMORY_CAPACITY_EXCEEDED = 0xD3;
|
||||
static final int GSM_SMS_FAIL_CAUSE_USIM_APP_TOOLKIT_BUSY = 0xD4;
|
||||
static final int GSM_SMS_FAIL_CAUSE_USIM_DATA_DOWNLOAD_ERROR = 0xD5;
|
||||
static final int GSM_SMS_FAIL_CAUSE_UNSPECIFIED_ERROR = 0xFF;
|
||||
|
||||
// CDMA SMS fail cause for acknowledgeLastIncomingCdmaSms. From TS N.S0005, 6.5.2.125.
|
||||
|
||||
@@ -21,8 +21,8 @@ package com.android.internal.telephony;
|
||||
*/
|
||||
public class
|
||||
IccIoResult {
|
||||
int sw1;
|
||||
int sw2;
|
||||
public int sw1;
|
||||
public int sw2;
|
||||
|
||||
public byte[] payload;
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@ import android.os.Message;
|
||||
import android.os.Registrant;
|
||||
import android.os.RegistrantList;
|
||||
|
||||
import com.android.internal.telephony.gsm.UsimServiceTable;
|
||||
import com.android.internal.telephony.ims.IsimRecords;
|
||||
|
||||
/**
|
||||
@@ -362,4 +363,8 @@ public abstract class IccRecords extends Handler implements IccConstants {
|
||||
public IsimRecords getIsimRecords() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public UsimServiceTable getUsimServiceTable() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ import android.telephony.ServiceState;
|
||||
import android.telephony.SignalStrength;
|
||||
|
||||
import com.android.internal.telephony.DataConnection;
|
||||
import com.android.internal.telephony.gsm.UsimServiceTable;
|
||||
import com.android.internal.telephony.ims.IsimRecords;
|
||||
import com.android.internal.telephony.test.SimulatedRadioControl;
|
||||
|
||||
@@ -1765,4 +1766,10 @@ public interface Phone {
|
||||
* messages are waiting
|
||||
*/
|
||||
void setVoiceMessageWaiting(int line, int countWaiting);
|
||||
|
||||
/**
|
||||
* Gets the USIM service table from the UICC, if present and available.
|
||||
* @return an interface to the UsimServiceTable record, or null if not available
|
||||
*/
|
||||
UsimServiceTable getUsimServiceTable();
|
||||
}
|
||||
|
||||
@@ -37,6 +37,7 @@ import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.internal.R;
|
||||
import com.android.internal.telephony.gsm.UsimServiceTable;
|
||||
import com.android.internal.telephony.ims.IsimRecords;
|
||||
import com.android.internal.telephony.test.SimulatedRadioControl;
|
||||
import com.android.internal.telephony.gsm.SIMRecords;
|
||||
@@ -1178,4 +1179,13 @@ public abstract class PhoneBase extends Handler implements Phone {
|
||||
public void setVoiceMessageWaiting(int line, int countWaiting) {
|
||||
mIccRecords.setVoiceMessageWaiting(line, countWaiting);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the USIM service table from the UICC, if present and available.
|
||||
* @return an interface to the UsimServiceTable record, or null if not available
|
||||
*/
|
||||
@Override
|
||||
public UsimServiceTable getUsimServiceTable() {
|
||||
return mIccRecords.getUsimServiceTable();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@ import android.util.Log;
|
||||
|
||||
import com.android.internal.telephony.cdma.CDMAPhone;
|
||||
import com.android.internal.telephony.gsm.GSMPhone;
|
||||
import com.android.internal.telephony.gsm.UsimServiceTable;
|
||||
import com.android.internal.telephony.ims.IsimRecords;
|
||||
import com.android.internal.telephony.test.SimulatedRadioControl;
|
||||
|
||||
@@ -853,4 +854,9 @@ public class PhoneProxy extends Handler implements Phone {
|
||||
public void setVoiceMessageWaiting(int line, int countWaiting) {
|
||||
mActivePhone.setVoiceMessageWaiting(line, countWaiting);
|
||||
}
|
||||
|
||||
@Override
|
||||
public UsimServiceTable getUsimServiceTable() {
|
||||
return mActivePhone.getUsimServiceTable();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,61 +34,6 @@ import com.android.internal.telephony.IccRecords;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* Enumeration for representing the tag value of COMPREHENSION-TLV objects. If
|
||||
* you want to get the actual value, call {@link #value() value} method.
|
||||
*
|
||||
* {@hide}
|
||||
*/
|
||||
enum ComprehensionTlvTag {
|
||||
COMMAND_DETAILS(0x01),
|
||||
DEVICE_IDENTITIES(0x02),
|
||||
RESULT(0x03),
|
||||
DURATION(0x04),
|
||||
ALPHA_ID(0x05),
|
||||
USSD_STRING(0x0a),
|
||||
TEXT_STRING(0x0d),
|
||||
TONE(0x0e),
|
||||
ITEM(0x0f),
|
||||
ITEM_ID(0x10),
|
||||
RESPONSE_LENGTH(0x11),
|
||||
FILE_LIST(0x12),
|
||||
HELP_REQUEST(0x15),
|
||||
DEFAULT_TEXT(0x17),
|
||||
EVENT_LIST(0x19),
|
||||
ICON_ID(0x1e),
|
||||
ITEM_ICON_ID_LIST(0x1f),
|
||||
IMMEDIATE_RESPONSE(0x2b),
|
||||
LANGUAGE(0x2d),
|
||||
URL(0x31),
|
||||
BROWSER_TERMINATION_CAUSE(0x34),
|
||||
TEXT_ATTRIBUTE(0x50);
|
||||
|
||||
private int mValue;
|
||||
|
||||
ComprehensionTlvTag(int value) {
|
||||
mValue = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the actual value of this COMPREHENSION-TLV object.
|
||||
*
|
||||
* @return Actual tag value of this object
|
||||
*/
|
||||
public int value() {
|
||||
return mValue;
|
||||
}
|
||||
|
||||
public static ComprehensionTlvTag fromInt(int value) {
|
||||
for (ComprehensionTlvTag e : ComprehensionTlvTag.values()) {
|
||||
if (e.mValue == value) {
|
||||
return e;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
class RilMessage {
|
||||
int mId;
|
||||
Object mData;
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright (C) 2011 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.cat;
|
||||
|
||||
/**
|
||||
* Enumeration for representing the tag value of COMPREHENSION-TLV objects. If
|
||||
* you want to get the actual value, call {@link #value() value} method.
|
||||
*
|
||||
* {@hide}
|
||||
*/
|
||||
public enum ComprehensionTlvTag {
|
||||
COMMAND_DETAILS(0x01),
|
||||
DEVICE_IDENTITIES(0x02),
|
||||
RESULT(0x03),
|
||||
DURATION(0x04),
|
||||
ALPHA_ID(0x05),
|
||||
ADDRESS(0x06),
|
||||
USSD_STRING(0x0a),
|
||||
SMS_TPDU(0x0b),
|
||||
TEXT_STRING(0x0d),
|
||||
TONE(0x0e),
|
||||
ITEM(0x0f),
|
||||
ITEM_ID(0x10),
|
||||
RESPONSE_LENGTH(0x11),
|
||||
FILE_LIST(0x12),
|
||||
HELP_REQUEST(0x15),
|
||||
DEFAULT_TEXT(0x17),
|
||||
EVENT_LIST(0x19),
|
||||
ICON_ID(0x1e),
|
||||
ITEM_ICON_ID_LIST(0x1f),
|
||||
IMMEDIATE_RESPONSE(0x2b),
|
||||
LANGUAGE(0x2d),
|
||||
URL(0x31),
|
||||
BROWSER_TERMINATION_CAUSE(0x34),
|
||||
TEXT_ATTRIBUTE(0x50);
|
||||
|
||||
private int mValue;
|
||||
|
||||
ComprehensionTlvTag(int value) {
|
||||
mValue = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the actual value of this COMPREHENSION-TLV object.
|
||||
*
|
||||
* @return Actual tag value of this object
|
||||
*/
|
||||
public int value() {
|
||||
return mValue;
|
||||
}
|
||||
|
||||
public static ComprehensionTlvTag fromInt(int value) {
|
||||
for (ComprehensionTlvTag e : ComprehensionTlvTag.values()) {
|
||||
if (e.mValue == value) {
|
||||
return e;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -25,8 +25,9 @@ import android.os.Message;
|
||||
import android.os.SystemProperties;
|
||||
import android.provider.Telephony.Sms;
|
||||
import android.provider.Telephony.Sms.Intents;
|
||||
import android.telephony.ServiceState;
|
||||
import android.telephony.PhoneNumberUtils;
|
||||
import android.telephony.SmsCbMessage;
|
||||
import android.telephony.SmsManager;
|
||||
import android.telephony.gsm.GsmCellLocation;
|
||||
import android.util.Log;
|
||||
|
||||
@@ -41,7 +42,6 @@ import com.android.internal.telephony.SmsStorageMonitor;
|
||||
import com.android.internal.telephony.SmsUsageMonitor;
|
||||
import com.android.internal.telephony.TelephonyProperties;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
|
||||
@@ -56,9 +56,16 @@ public final class GsmSMSDispatcher extends SMSDispatcher {
|
||||
/** New broadcast SMS */
|
||||
private static final int EVENT_NEW_BROADCAST_SMS = 101;
|
||||
|
||||
/** Result of writing SM to UICC (when SMS-PP service is not available). */
|
||||
private static final int EVENT_WRITE_SMS_COMPLETE = 102;
|
||||
|
||||
/** Handler for SMS-PP data download messages to UICC. */
|
||||
private final UsimDataDownloadHandler mDataDownloadHandler;
|
||||
|
||||
public GsmSMSDispatcher(PhoneBase phone, SmsStorageMonitor storageMonitor,
|
||||
SmsUsageMonitor usageMonitor) {
|
||||
super(phone, storageMonitor, usageMonitor);
|
||||
mDataDownloadHandler = new UsimDataDownloadHandler(mCm);
|
||||
mCm.setOnNewGsmSms(this, EVENT_NEW_SMS, null);
|
||||
mCm.setOnSmsStatus(this, EVENT_NEW_SMS_STATUS_REPORT, null);
|
||||
mCm.setOnNewGsmBroadcastSms(this, EVENT_NEW_BROADCAST_SMS, null);
|
||||
@@ -93,6 +100,18 @@ public final class GsmSMSDispatcher extends SMSDispatcher {
|
||||
handleBroadcastSms((AsyncResult)msg.obj);
|
||||
break;
|
||||
|
||||
case EVENT_WRITE_SMS_COMPLETE:
|
||||
AsyncResult ar = (AsyncResult) msg.obj;
|
||||
if (ar.exception == null) {
|
||||
Log.d(TAG, "Successfully wrote SMS-PP message to UICC");
|
||||
mCm.acknowledgeLastIncomingGsmSms(true, 0, null);
|
||||
} else {
|
||||
Log.d(TAG, "Failed to write SMS-PP message to UICC", ar.exception);
|
||||
mCm.acknowledgeLastIncomingGsmSms(false,
|
||||
CommandsInterface.GSM_SMS_FAIL_CAUSE_UNSPECIFIED_ERROR, null);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
super.handleMessage(msg);
|
||||
}
|
||||
@@ -154,6 +173,29 @@ public final class GsmSMSDispatcher extends SMSDispatcher {
|
||||
return Intents.RESULT_SMS_HANDLED;
|
||||
}
|
||||
|
||||
// Send SMS-PP data download messages to UICC. See 3GPP TS 31.111 section 7.1.1.
|
||||
if (sms.isUsimDataDownload()) {
|
||||
UsimServiceTable ust = mPhone.getUsimServiceTable();
|
||||
// If we receive an SMS-PP message before the UsimServiceTable has been loaded,
|
||||
// assume that the data download service is not present. This is very unlikely to
|
||||
// happen because the IMS connection will not be established until after the ISIM
|
||||
// records have been loaded, after the USIM service table has been loaded.
|
||||
if (ust != null && ust.isAvailable(
|
||||
UsimServiceTable.UsimService.DATA_DL_VIA_SMS_PP)) {
|
||||
Log.d(TAG, "Received SMS-PP data download, sending to UICC.");
|
||||
return mDataDownloadHandler.startDataDownload(sms);
|
||||
} else {
|
||||
Log.d(TAG, "DATA_DL_VIA_SMS_PP service not available, storing message to UICC.");
|
||||
String smsc = IccUtils.bytesToHexString(
|
||||
PhoneNumberUtils.networkPortionToCalledPartyBCDWithLength(
|
||||
sms.getServiceCenterAddress()));
|
||||
mCm.writeSmsToSim(SmsManager.STATUS_ON_ICC_UNREAD, smsc,
|
||||
IccUtils.bytesToHexString(sms.getPdu()),
|
||||
obtainMessage(EVENT_WRITE_SMS_COMPLETE));
|
||||
return Activity.RESULT_OK; // acknowledge after response from write to USIM
|
||||
}
|
||||
}
|
||||
|
||||
if (mSmsReceiveDisabled) {
|
||||
// Device doesn't support SMS service,
|
||||
Log.d(TAG, "Received short message on device which doesn't support "
|
||||
|
||||
@@ -248,6 +248,7 @@ public class SIMRecords extends IccRecords {
|
||||
return msisdn;
|
||||
}
|
||||
|
||||
@Override
|
||||
public UsimServiceTable getUsimServiceTable() {
|
||||
return mUsimServiceTable;
|
||||
}
|
||||
|
||||
@@ -769,6 +769,14 @@ public class SmsMessage extends SmsMessageBase {
|
||||
return protocolIdentifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the TP-Data-Coding-Scheme byte, for acknowledgement of SMS-PP download messages.
|
||||
* @return the TP-DCS field of the SMS header
|
||||
*/
|
||||
int getDataCodingScheme() {
|
||||
return dataCodingScheme;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public boolean isReplace() {
|
||||
@@ -1129,4 +1137,14 @@ public class SmsMessage extends SmsMessageBase {
|
||||
return messageClass;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this is a (U)SIM data download type SM.
|
||||
* See 3GPP TS 31.111 section 9.1 and TS 23.040 section 9.2.3.9.
|
||||
*
|
||||
* @return true if this is a USIM data download message; false otherwise
|
||||
*/
|
||||
boolean isUsimDataDownload() {
|
||||
return messageClass == MessageClass.CLASS_2 &&
|
||||
(protocolIdentifier == 0x7f || protocolIdentifier == 0x7c);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,267 @@
|
||||
/*
|
||||
* Copyright (C) 2011 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.app.Activity;
|
||||
import android.os.AsyncResult;
|
||||
import android.os.Handler;
|
||||
import android.os.Message;
|
||||
import android.provider.Telephony.Sms.Intents;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.internal.telephony.CommandsInterface;
|
||||
import com.android.internal.telephony.IccIoResult;
|
||||
import com.android.internal.telephony.IccUtils;
|
||||
import com.android.internal.telephony.cat.ComprehensionTlvTag;
|
||||
|
||||
/**
|
||||
* Handler for SMS-PP data download messages.
|
||||
* See 3GPP TS 31.111 section 7.1.1
|
||||
*/
|
||||
public class UsimDataDownloadHandler extends Handler {
|
||||
private static final String TAG = "UsimDataDownloadHandler";
|
||||
|
||||
/** BER-TLV tag for SMS-PP download. TS 31.111 section 9.1. */
|
||||
private static final int BER_SMS_PP_DOWNLOAD_TAG = 0xd1;
|
||||
|
||||
/** Device identity value for UICC (destination). */
|
||||
private static final int DEV_ID_UICC = 0x81;
|
||||
|
||||
/** Device identity value for network (source). */
|
||||
private static final int DEV_ID_NETWORK = 0x83;
|
||||
|
||||
/** Message containing new SMS-PP message to process. */
|
||||
private static final int EVENT_START_DATA_DOWNLOAD = 1;
|
||||
|
||||
/** Response to SMS-PP download envelope command. */
|
||||
private static final int EVENT_SEND_ENVELOPE_RESPONSE = 2;
|
||||
|
||||
private final CommandsInterface mCI;
|
||||
|
||||
public UsimDataDownloadHandler(CommandsInterface commandsInterface) {
|
||||
mCI = commandsInterface;
|
||||
}
|
||||
|
||||
/**
|
||||
* Start an SMS-PP data download for the specified message. Can be called from a different
|
||||
* thread than this Handler is running on.
|
||||
*
|
||||
* @param smsMessage the message to process
|
||||
* @return Activity.RESULT_OK on success; Intents.RESULT_SMS_GENERIC_ERROR on failure
|
||||
*/
|
||||
public int startDataDownload(SmsMessage smsMessage) {
|
||||
if (sendMessage(obtainMessage(EVENT_START_DATA_DOWNLOAD, smsMessage))) {
|
||||
return Activity.RESULT_OK; // we will send SMS ACK/ERROR based on UICC response
|
||||
} else {
|
||||
Log.e(TAG, "startDataDownload failed to send message to start data download.");
|
||||
return Intents.RESULT_SMS_GENERIC_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
private void handleDataDownload(SmsMessage smsMessage) {
|
||||
int dcs = smsMessage.getDataCodingScheme();
|
||||
int pid = smsMessage.getProtocolIdentifier();
|
||||
byte[] pdu = smsMessage.getPdu(); // includes SC address
|
||||
|
||||
int scAddressLength = pdu[0] & 0xff;
|
||||
int tpduIndex = scAddressLength + 1; // start of TPDU
|
||||
int tpduLength = pdu.length - tpduIndex;
|
||||
|
||||
int bodyLength = getEnvelopeBodyLength(scAddressLength, tpduLength);
|
||||
|
||||
// Add 1 byte for SMS-PP download tag and 1-2 bytes for BER-TLV length.
|
||||
// See ETSI TS 102 223 Annex C for encoding of length and tags.
|
||||
int totalLength = bodyLength + 1 + (bodyLength > 127 ? 2 : 1);
|
||||
|
||||
byte[] envelope = new byte[totalLength];
|
||||
int index = 0;
|
||||
|
||||
// SMS-PP download tag and length (assumed to be < 256 bytes).
|
||||
envelope[index++] = (byte) BER_SMS_PP_DOWNLOAD_TAG;
|
||||
if (bodyLength > 127) {
|
||||
envelope[index++] = (byte) 0x81; // length 128-255 encoded as 0x81 + length
|
||||
}
|
||||
envelope[index++] = (byte) bodyLength;
|
||||
|
||||
// Device identities TLV
|
||||
envelope[index++] = (byte) (0x80 | ComprehensionTlvTag.DEVICE_IDENTITIES.value());
|
||||
envelope[index++] = (byte) 2;
|
||||
envelope[index++] = (byte) DEV_ID_NETWORK;
|
||||
envelope[index++] = (byte) DEV_ID_UICC;
|
||||
|
||||
// Address TLV (if present). Encoded length is assumed to be < 127 bytes.
|
||||
if (scAddressLength != 0) {
|
||||
envelope[index++] = (byte) ComprehensionTlvTag.ADDRESS.value();
|
||||
envelope[index++] = (byte) scAddressLength;
|
||||
System.arraycopy(pdu, 1, envelope, index, scAddressLength);
|
||||
index += scAddressLength;
|
||||
}
|
||||
|
||||
// SMS TPDU TLV. Length is assumed to be < 256 bytes.
|
||||
envelope[index++] = (byte) (0x80 | ComprehensionTlvTag.SMS_TPDU.value());
|
||||
if (tpduLength > 127) {
|
||||
envelope[index++] = (byte) 0x81; // length 128-255 encoded as 0x81 + length
|
||||
}
|
||||
envelope[index++] = (byte) tpduLength;
|
||||
System.arraycopy(pdu, tpduIndex, envelope, index, tpduLength);
|
||||
index += tpduLength;
|
||||
|
||||
// Verify that we calculated the payload size correctly.
|
||||
if (index != envelope.length) {
|
||||
Log.e(TAG, "startDataDownload() calculated incorrect envelope length, aborting.");
|
||||
acknowledgeSmsWithError(CommandsInterface.GSM_SMS_FAIL_CAUSE_UNSPECIFIED_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
String encodedEnvelope = IccUtils.bytesToHexString(envelope);
|
||||
mCI.sendEnvelopeWithStatus(encodedEnvelope, obtainMessage(
|
||||
EVENT_SEND_ENVELOPE_RESPONSE, new int[]{ dcs, pid }));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the size in bytes of the envelope to send to the UICC, excluding the
|
||||
* SMS-PP download tag byte and length byte(s). If the size returned is <= 127,
|
||||
* the BER-TLV length will be encoded in 1 byte, otherwise 2 bytes are required.
|
||||
*
|
||||
* @param scAddressLength the length of the SMSC address, or zero if not present
|
||||
* @param tpduLength the length of the TPDU from the SMS-PP message
|
||||
* @return the number of bytes to allocate for the envelope command
|
||||
*/
|
||||
private static int getEnvelopeBodyLength(int scAddressLength, int tpduLength) {
|
||||
// Add 4 bytes for device identities TLV + 1 byte for SMS TPDU tag byte
|
||||
int length = tpduLength + 5;
|
||||
// Add 1 byte for TPDU length, or 2 bytes if length > 127
|
||||
length += (tpduLength > 127 ? 2 : 1);
|
||||
// Add length of address tag, if present (+ 2 bytes for tag and length)
|
||||
if (scAddressLength != 0) {
|
||||
length = length + 2 + scAddressLength;
|
||||
}
|
||||
return length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the response to the ENVELOPE command.
|
||||
* @param response UICC response encoded as hexadecimal digits. First two bytes are the
|
||||
* UICC SW1 and SW2 status bytes.
|
||||
*/
|
||||
private void sendSmsAckForEnvelopeResponse(IccIoResult response, int dcs, int pid) {
|
||||
int sw1 = response.sw1;
|
||||
int sw2 = response.sw2;
|
||||
|
||||
boolean success;
|
||||
if ((sw1 == 0x90 && sw2 == 0x00) || sw1 == 0x91) {
|
||||
Log.d(TAG, "USIM data download succeeded: " + response.toString());
|
||||
success = true;
|
||||
} else if (sw1 == 0x93 && sw2 == 0x00) {
|
||||
Log.e(TAG, "USIM data download failed: Toolkit busy");
|
||||
acknowledgeSmsWithError(CommandsInterface.GSM_SMS_FAIL_CAUSE_USIM_APP_TOOLKIT_BUSY);
|
||||
return;
|
||||
} else if (sw1 == 0x62 || sw1 == 0x63) {
|
||||
Log.e(TAG, "USIM data download failed: " + response.toString());
|
||||
success = false;
|
||||
} else {
|
||||
Log.e(TAG, "Unexpected SW1/SW2 response from UICC: " + response.toString());
|
||||
success = false;
|
||||
}
|
||||
|
||||
byte[] responseBytes = response.payload;
|
||||
if (responseBytes == null || responseBytes.length == 0) {
|
||||
if (success) {
|
||||
mCI.acknowledgeLastIncomingGsmSms(true, 0, null);
|
||||
} else {
|
||||
acknowledgeSmsWithError(
|
||||
CommandsInterface.GSM_SMS_FAIL_CAUSE_USIM_DATA_DOWNLOAD_ERROR);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
byte[] smsAckPdu;
|
||||
int index = 0;
|
||||
if (success) {
|
||||
smsAckPdu = new byte[responseBytes.length + 5];
|
||||
smsAckPdu[index++] = 0x00; // TP-MTI, TP-UDHI
|
||||
smsAckPdu[index++] = 0x07; // TP-PI: TP-PID, TP-DCS, TP-UDL present
|
||||
} else {
|
||||
smsAckPdu = new byte[responseBytes.length + 6];
|
||||
smsAckPdu[index++] = 0x00; // TP-MTI, TP-UDHI
|
||||
smsAckPdu[index++] = (byte)
|
||||
CommandsInterface.GSM_SMS_FAIL_CAUSE_USIM_DATA_DOWNLOAD_ERROR; // TP-FCS
|
||||
smsAckPdu[index++] = 0x07; // TP-PI: TP-PID, TP-DCS, TP-UDL present
|
||||
}
|
||||
|
||||
smsAckPdu[index++] = (byte) pid;
|
||||
smsAckPdu[index++] = (byte) dcs;
|
||||
|
||||
if (is7bitDcs(dcs)) {
|
||||
int septetCount = responseBytes.length * 8 / 7;
|
||||
smsAckPdu[index++] = (byte) septetCount;
|
||||
} else {
|
||||
smsAckPdu[index++] = (byte) responseBytes.length;
|
||||
}
|
||||
|
||||
System.arraycopy(responseBytes, 0, smsAckPdu, index, responseBytes.length);
|
||||
|
||||
mCI.acknowledgeIncomingGsmSmsWithPdu(success,
|
||||
IccUtils.bytesToHexString(smsAckPdu), null);
|
||||
}
|
||||
|
||||
private void acknowledgeSmsWithError(int cause) {
|
||||
mCI.acknowledgeLastIncomingGsmSms(false, cause, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the DCS is 7 bit. If so, set TP-UDL to the septet count of TP-UD;
|
||||
* otherwise, set TP-UDL to the octet count of TP-UD.
|
||||
* @param dcs the TP-Data-Coding-Scheme field from the original download SMS
|
||||
* @return true if the DCS specifies 7 bit encoding; false otherwise
|
||||
*/
|
||||
private static boolean is7bitDcs(int dcs) {
|
||||
// See 3GPP TS 23.038 section 4
|
||||
return ((dcs & 0x8C) == 0x00) || ((dcs & 0xF4) == 0xF0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle UICC envelope response and send SMS acknowledgement.
|
||||
*
|
||||
* @param msg the message to handle
|
||||
*/
|
||||
@Override
|
||||
public void handleMessage(Message msg) {
|
||||
switch (msg.what) {
|
||||
case EVENT_START_DATA_DOWNLOAD:
|
||||
handleDataDownload((SmsMessage) msg.obj);
|
||||
break;
|
||||
|
||||
case EVENT_SEND_ENVELOPE_RESPONSE:
|
||||
AsyncResult ar = (AsyncResult) msg.obj;
|
||||
|
||||
if (ar.exception != null) {
|
||||
Log.e(TAG, "UICC Send Envelope failure, exception: " + ar.exception);
|
||||
acknowledgeSmsWithError(
|
||||
CommandsInterface.GSM_SMS_FAIL_CAUSE_USIM_DATA_DOWNLOAD_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
int[] dcsPid = (int[]) ar.userObj;
|
||||
sendSmsAckForEnvelopeResponse((IccIoResult) ar.result, dcsPid[0], dcsPid[1]);
|
||||
break;
|
||||
|
||||
default:
|
||||
Log.e(TAG, "Ignoring unexpected message, what=" + msg.what);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,611 @@
|
||||
/*
|
||||
* Copyright (C) 2011 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.content.Context;
|
||||
import android.os.AsyncResult;
|
||||
import android.os.Message;
|
||||
import android.os.SystemClock;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.internal.telephony.BaseCommands;
|
||||
import com.android.internal.telephony.IccIoResult;
|
||||
import com.android.internal.telephony.UUSInfo;
|
||||
|
||||
import junit.framework.Assert;
|
||||
|
||||
/**
|
||||
* Dummy BaseCommands for UsimDataDownloadTest. Only implements UICC envelope and
|
||||
* SMS acknowledgement commands.
|
||||
*/
|
||||
class UsimDataDownloadCommands extends BaseCommands {
|
||||
private static final String TAG = "UsimDataDownloadCommands";
|
||||
|
||||
private boolean mExpectingAcknowledgeGsmSms; // true if expecting ack GSM SMS
|
||||
private boolean mExpectingAcknowledgeGsmSmsSuccess; // true if expecting ack SMS success
|
||||
private int mExpectingAcknowledgeGsmSmsFailureCause; // expecting ack SMS failure cause
|
||||
private String mExpectingAcknowledgeGsmSmsPdu; // expecting ack SMS PDU
|
||||
|
||||
private boolean mExpectingSendEnvelope; // true to expect a send envelope command
|
||||
private String mExpectingSendEnvelopeContents; // expected string for send envelope
|
||||
private int mExpectingSendEnvelopeResponseSw1; // SW1/SW2 response status
|
||||
private int mExpectingSendEnvelopeResponseSw2; // SW1/SW2 response status
|
||||
private String mExpectingSendEnvelopeResponse; // Response string for Send Envelope
|
||||
|
||||
UsimDataDownloadCommands(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Expect a call to acknowledgeLastIncomingGsmSms with success flag and failure cause.
|
||||
* @param success true if expecting success; false if expecting failure
|
||||
* @param cause the failure cause, if success is false
|
||||
*/
|
||||
synchronized void expectAcknowledgeGsmSms(boolean success, int cause) {
|
||||
Assert.assertFalse("expectAcknowledgeGsmSms called twice", mExpectingAcknowledgeGsmSms);
|
||||
mExpectingAcknowledgeGsmSms = true;
|
||||
mExpectingAcknowledgeGsmSmsSuccess = success;
|
||||
mExpectingAcknowledgeGsmSmsFailureCause = cause;
|
||||
}
|
||||
|
||||
/**
|
||||
* Expect a call to acknowledgeLastIncomingGsmSmsWithPdu with success flag and PDU.
|
||||
* @param success true if expecting success; false if expecting failure
|
||||
* @param ackPdu the acknowledgement PDU to expect
|
||||
*/
|
||||
synchronized void expectAcknowledgeGsmSmsWithPdu(boolean success, String ackPdu) {
|
||||
Assert.assertFalse("expectAcknowledgeGsmSms called twice", mExpectingAcknowledgeGsmSms);
|
||||
mExpectingAcknowledgeGsmSms = true;
|
||||
mExpectingAcknowledgeGsmSmsSuccess = success;
|
||||
mExpectingAcknowledgeGsmSmsPdu = ackPdu;
|
||||
}
|
||||
|
||||
/**
|
||||
* Expect a call to sendEnvelopeWithStatus().
|
||||
* @param contents expected envelope contents to send
|
||||
* @param sw1 simulated SW1 status to return
|
||||
* @param sw2 simulated SW2 status to return
|
||||
* @param response simulated envelope response to return
|
||||
*/
|
||||
synchronized void expectSendEnvelope(String contents, int sw1, int sw2, String response) {
|
||||
Assert.assertFalse("expectSendEnvelope called twice", mExpectingSendEnvelope);
|
||||
mExpectingSendEnvelope = true;
|
||||
mExpectingSendEnvelopeContents = contents;
|
||||
mExpectingSendEnvelopeResponseSw1 = sw1;
|
||||
mExpectingSendEnvelopeResponseSw2 = sw2;
|
||||
mExpectingSendEnvelopeResponse = response;
|
||||
}
|
||||
|
||||
synchronized void assertExpectedMethodsCalled() {
|
||||
long stopTime = SystemClock.elapsedRealtime() + 5000;
|
||||
while ((mExpectingAcknowledgeGsmSms || mExpectingSendEnvelope)
|
||||
&& SystemClock.elapsedRealtime() < stopTime) {
|
||||
try {
|
||||
wait();
|
||||
} catch (InterruptedException ignored) {}
|
||||
}
|
||||
Assert.assertFalse("expecting SMS acknowledge call", mExpectingAcknowledgeGsmSms);
|
||||
Assert.assertFalse("expecting send envelope call", mExpectingSendEnvelope);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void acknowledgeLastIncomingGsmSms(boolean success, int cause,
|
||||
Message response) {
|
||||
Log.d(TAG, "acknowledgeLastIncomingGsmSms: success=" + success + ", cause=" + cause);
|
||||
Assert.assertTrue("unexpected call to acknowledge SMS", mExpectingAcknowledgeGsmSms);
|
||||
Assert.assertEquals(mExpectingAcknowledgeGsmSmsSuccess, success);
|
||||
Assert.assertEquals(mExpectingAcknowledgeGsmSmsFailureCause, cause);
|
||||
mExpectingAcknowledgeGsmSms = false;
|
||||
if (response != null) {
|
||||
AsyncResult.forMessage(response);
|
||||
response.sendToTarget();
|
||||
}
|
||||
notifyAll(); // wake up assertExpectedMethodsCalled()
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void acknowledgeIncomingGsmSmsWithPdu(boolean success, String ackPdu,
|
||||
Message response) {
|
||||
Log.d(TAG, "acknowledgeLastIncomingGsmSmsWithPdu: success=" + success
|
||||
+ ", ackPDU= " + ackPdu);
|
||||
Assert.assertTrue("unexpected call to acknowledge SMS", mExpectingAcknowledgeGsmSms);
|
||||
Assert.assertEquals(mExpectingAcknowledgeGsmSmsSuccess, success);
|
||||
Assert.assertEquals(mExpectingAcknowledgeGsmSmsPdu, ackPdu);
|
||||
mExpectingAcknowledgeGsmSms = false;
|
||||
if (response != null) {
|
||||
AsyncResult.forMessage(response);
|
||||
response.sendToTarget();
|
||||
}
|
||||
notifyAll(); // wake up assertExpectedMethodsCalled()
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void sendEnvelopeWithStatus(String contents, Message response) {
|
||||
// Add spaces between hex bytes for readability
|
||||
StringBuilder builder = new StringBuilder();
|
||||
for (int i = 0; i < contents.length(); i += 2) {
|
||||
builder.append(contents.charAt(i)).append(contents.charAt(i+1)).append(' ');
|
||||
}
|
||||
Log.d(TAG, "sendEnvelopeWithStatus: " + builder.toString());
|
||||
|
||||
Assert.assertTrue("unexpected call to send envelope", mExpectingSendEnvelope);
|
||||
Assert.assertEquals(mExpectingSendEnvelopeContents, contents);
|
||||
mExpectingSendEnvelope = false;
|
||||
|
||||
IccIoResult result = new IccIoResult(mExpectingSendEnvelopeResponseSw1,
|
||||
mExpectingSendEnvelopeResponseSw2, mExpectingSendEnvelopeResponse);
|
||||
|
||||
if (response != null) {
|
||||
AsyncResult.forMessage(response, result, null);
|
||||
response.sendToTarget();
|
||||
}
|
||||
notifyAll(); // wake up assertExpectedMethodsCalled()
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSuppServiceNotifications(boolean enable, Message result) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void supplyIccPin(String pin, Message result) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void supplyIccPinForApp(String pin, String aid, Message result) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void supplyIccPuk(String puk, String newPin, Message result) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void supplyIccPukForApp(String puk, String newPin, String aid, Message result) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void supplyIccPin2(String pin2, Message result) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void supplyIccPin2ForApp(String pin2, String aid, Message result) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void supplyIccPuk2(String puk2, String newPin2, Message result) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void supplyIccPuk2ForApp(String puk2, String newPin2, String aid, Message result) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void changeIccPin(String oldPin, String newPin, Message result) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void changeIccPinForApp(String oldPin, String newPin, String aidPtr, Message result) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void changeIccPin2(String oldPin2, String newPin2, Message result) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void changeIccPin2ForApp(String oldPin2, String newPin2, String aidPtr, Message result) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void changeBarringPassword(String facility, String oldPwd, String newPwd,
|
||||
Message result) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void supplyNetworkDepersonalization(String netpin, Message result) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getCurrentCalls(Message result) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getPDPContextList(Message result) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getDataCallList(Message result) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dial(String address, int clirMode, Message result) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dial(String address, int clirMode, UUSInfo uusInfo, Message result) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getIMSI(Message result) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getIMEI(Message result) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getIMEISV(Message result) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void hangupConnection(int gsmIndex, Message result) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void hangupWaitingOrBackground(Message result) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void hangupForegroundResumeBackground(Message result) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void switchWaitingOrHoldingAndActive(Message result) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void conference(Message result) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPreferredVoicePrivacy(boolean enable, Message result) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getPreferredVoicePrivacy(Message result) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void separateConnection(int gsmIndex, Message result) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void acceptCall(Message result) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void rejectCall(Message result) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void explicitCallTransfer(Message result) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getLastCallFailCause(Message result) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getLastPdpFailCause(Message result) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getLastDataCallFailCause(Message result) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMute(boolean enableMute, Message response) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getMute(Message response) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getSignalStrength(Message response) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getVoiceRegistrationState(Message response) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getDataRegistrationState(Message response) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getOperator(Message response) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendDtmf(char c, Message result) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startDtmf(char c, Message result) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stopDtmf(Message result) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendBurstDtmf(String dtmfString, int on, int off, Message result) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendSMS(String smscPDU, String pdu, Message response) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendCdmaSms(byte[] pdu, Message response) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteSmsOnSim(int index, Message response) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteSmsOnRuim(int index, Message response) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeSmsToSim(int status, String smsc, String pdu, Message response) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeSmsToRuim(int status, String pdu, Message response) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRadioPower(boolean on, Message response) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void acknowledgeLastIncomingCdmaSms(boolean success, int cause, Message response) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void iccIO(int command, int fileid, String path, int p1, int p2, int p3, String data,
|
||||
String pin2, Message response) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void queryCLIP(Message response) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getCLIR(Message response) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCLIR(int clirMode, Message response) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void queryCallWaiting(int serviceClass, Message response) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCallWaiting(boolean enable, int serviceClass, Message response) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCallForward(int action, int cfReason, int serviceClass, String number,
|
||||
int timeSeconds, Message response) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void queryCallForwardStatus(int cfReason, int serviceClass, String number,
|
||||
Message response) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setNetworkSelectionModeAutomatic(Message response) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setNetworkSelectionModeManual(String operatorNumeric, Message response) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getNetworkSelectionMode(Message response) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getAvailableNetworks(Message response) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getBasebandVersion(Message response) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void queryFacilityLock(String facility, String password, int serviceClass,
|
||||
Message response) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void queryFacilityLockForApp(String facility, String password, int serviceClass,
|
||||
String appId, Message response) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFacilityLock(String facility, boolean lockState, String password,
|
||||
int serviceClass, Message response) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFacilityLockForApp(String facility, boolean lockState, String password,
|
||||
int serviceClass, String appId, Message response) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendUSSD(String ussdString, Message response) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancelPendingUssd(Message response) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resetRadio(Message result) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBandMode(int bandMode, Message response) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void queryAvailableBandMode(Message response) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPreferredNetworkType(int networkType, Message response) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getPreferredNetworkType(Message response) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getNeighboringCids(Message response) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLocationUpdates(boolean enable, Message response) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getSmscAddress(Message result) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSmscAddress(String address, Message result) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reportSmsMemoryStatus(boolean available, Message result) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reportStkServiceIsRunning(Message result) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invokeOemRilRequestRaw(byte[] data, Message response) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invokeOemRilRequestStrings(String[] strings, Message response) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendTerminalResponse(String contents, Message response) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendEnvelope(String contents, Message response) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleCallSetupRequestFromSim(boolean accept, Message response) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setGsmBroadcastActivation(boolean activate, Message result) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setGsmBroadcastConfig(SmsBroadcastConfigInfo[] config, Message response) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getGsmBroadcastConfig(Message response) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getDeviceIdentity(Message response) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getCDMASubscription(Message response) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendCDMAFeatureCode(String FeatureCode, Message response) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPhoneType(int phoneType) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void queryCdmaRoamingPreference(Message response) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCdmaRoamingPreference(int cdmaRoamingType, Message response) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCdmaSubscriptionSource(int cdmaSubscriptionType, Message response) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getCdmaSubscriptionSource(Message response) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTTYMode(int ttyMode, Message response) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void queryTTYMode(Message response) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setupDataCall(String radioTechnology, String profile, String apn, String user,
|
||||
String password, String authType, String protocol, Message result) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deactivateDataCall(int cid, int reason, Message result) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCdmaBroadcastActivation(boolean activate, Message result) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCdmaBroadcastConfig(int[] configValuesArray, Message result) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getCdmaBroadcastConfig(Message result) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exitEmergencyCallbackMode(Message response) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getIccCardStatus(Message result) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void requestIsimAuthentication(String nonce, Message response) {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,144 @@
|
||||
/*
|
||||
* Copyright (C) 2011 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.os.HandlerThread;
|
||||
import android.test.AndroidTestCase;
|
||||
import android.util.Log;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
|
||||
/**
|
||||
* Test SMS-PP data download to UICC.
|
||||
* Uses test messages from 3GPP TS 31.124 section 27.22.5.
|
||||
*/
|
||||
public class UsimDataDownloadTest extends AndroidTestCase {
|
||||
private static final String TAG = "UsimDataDownloadTest";
|
||||
|
||||
class TestHandlerThread extends HandlerThread {
|
||||
private UsimDataDownloadHandler mHandler;
|
||||
|
||||
TestHandlerThread() {
|
||||
super("TestHandlerThread");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onLooperPrepared() {
|
||||
synchronized (this) {
|
||||
mHandler = new UsimDataDownloadHandler(mCm);
|
||||
notifyAll();
|
||||
}
|
||||
}
|
||||
|
||||
UsimDataDownloadHandler getHandler() {
|
||||
synchronized (this) {
|
||||
while (mHandler == null) {
|
||||
try {
|
||||
wait();
|
||||
} catch (InterruptedException ignored) {}
|
||||
}
|
||||
return mHandler;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private UsimDataDownloadCommands mCm;
|
||||
private TestHandlerThread mHandlerThread;
|
||||
UsimDataDownloadHandler mHandler;
|
||||
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
mCm = new UsimDataDownloadCommands(mContext);
|
||||
mHandlerThread = new TestHandlerThread();
|
||||
mHandlerThread.start();
|
||||
mHandler = mHandlerThread.getHandler();
|
||||
Log.d(TAG, "mHandler is constructed");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void tearDown() throws Exception {
|
||||
mHandlerThread.quit();
|
||||
super.tearDown();
|
||||
}
|
||||
|
||||
// SMS-PP Message 3.1.1
|
||||
private static final byte[] SMS_PP_MESSAGE_3_1_1 = {
|
||||
// Service center address
|
||||
0x09, (byte) 0x91, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, (byte) 0xf8,
|
||||
|
||||
0x04, 0x04, (byte) 0x91, 0x21, 0x43, 0x7f, 0x16, (byte) 0x89, 0x10, 0x10, 0x00, 0x00,
|
||||
0x00, 0x00, 0x0d, 0x54, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61,
|
||||
0x67, 0x65, 0x20, 0x31
|
||||
};
|
||||
|
||||
// SMS-PP Download Envelope 3.1.1
|
||||
private static final String SMS_PP_ENVELOPE_3_1_1 = "d12d8202838106099111223344556677f88b1c04"
|
||||
+ "049121437f16891010000000000d546573744d6573736167652031";
|
||||
|
||||
// SMS-PP Message 3.1.5
|
||||
private static final byte[] SMS_PP_MESSAGE_3_1_5 = {
|
||||
// Service center address
|
||||
0x09, (byte) 0x91, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, (byte) 0xf8,
|
||||
|
||||
0x44, 0x04, (byte) 0x91, 0x21, 0x43, 0x7f, (byte) 0xf6, (byte) 0x89, 0x10, 0x10, 0x00,
|
||||
0x00, 0x00, 0x00, 0x1e, 0x02, 0x70, 0x00, 0x00, 0x19, 0x00, 0x0d, 0x00, 0x00,
|
||||
0x00, 0x00, (byte) 0xbf, (byte) 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
|
||||
(byte) 0xdc, (byte) 0xdc, (byte) 0xdc, (byte) 0xdc, (byte) 0xdc, (byte) 0xdc,
|
||||
(byte) 0xdc, (byte) 0xdc, (byte) 0xdc, (byte) 0xdc
|
||||
};
|
||||
|
||||
// SMS-PP Download Envelope 3.1.5
|
||||
private static final String SMS_PP_ENVELOPE_3_1_5 = "d13e8202838106099111223344556677f88b2d44"
|
||||
+ "049121437ff6891010000000001e0270000019000d00000000bfff00000000000100"
|
||||
+ "dcdcdcdcdcdcdcdcdcdc";
|
||||
|
||||
public void testDataDownloadMessage1() {
|
||||
SmsMessage message = SmsMessage.createFromPdu(SMS_PP_MESSAGE_3_1_1);
|
||||
assertTrue("message is SMS-PP data download", message.isUsimDataDownload());
|
||||
|
||||
mCm.expectSendEnvelope(SMS_PP_ENVELOPE_3_1_1, 0x90, 0x00, "");
|
||||
mCm.expectAcknowledgeGsmSms(true, 0);
|
||||
mHandler.startDataDownload(message);
|
||||
mCm.assertExpectedMethodsCalled();
|
||||
|
||||
mCm.expectSendEnvelope(SMS_PP_ENVELOPE_3_1_1, 0x90, 0x00, "0123456789");
|
||||
mCm.expectAcknowledgeGsmSmsWithPdu(true, "00077f16050123456789");
|
||||
mHandler.startDataDownload(message);
|
||||
mCm.assertExpectedMethodsCalled();
|
||||
|
||||
mCm.expectSendEnvelope(SMS_PP_ENVELOPE_3_1_1, 0x62, 0xff, "0123456789abcdef");
|
||||
mCm.expectAcknowledgeGsmSmsWithPdu(false, "00d5077f16080123456789abcdef");
|
||||
mHandler.startDataDownload(message);
|
||||
mCm.assertExpectedMethodsCalled();
|
||||
}
|
||||
|
||||
public void testDataDownloadMessage5() {
|
||||
SmsMessage message = SmsMessage.createFromPdu(SMS_PP_MESSAGE_3_1_5);
|
||||
assertTrue("message is SMS-PP data download", message.isUsimDataDownload());
|
||||
|
||||
mCm.expectSendEnvelope(SMS_PP_ENVELOPE_3_1_5, 0x90, 0x00, "9876543210");
|
||||
mCm.expectAcknowledgeGsmSmsWithPdu(true, "00077ff6059876543210");
|
||||
mHandler.startDataDownload(message);
|
||||
mCm.assertExpectedMethodsCalled();
|
||||
|
||||
mCm.expectSendEnvelope(SMS_PP_ENVELOPE_3_1_5, 0x93, 0x00, "");
|
||||
mCm.expectAcknowledgeGsmSms(false, 0xd4); // SIM toolkit busy
|
||||
mHandler.startDataDownload(message);
|
||||
mCm.assertExpectedMethodsCalled();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user