Home | History | Annotate | Download | only in sap
      1 package com.android.bluetooth.sap;
      2 
      3 import java.io.IOException;
      4 import java.io.InputStream;
      5 import java.io.OutputStream;
      6 import java.security.InvalidParameterException;
      7 import java.util.Arrays;
      8 import java.util.Hashtable;
      9 import java.util.Map;
     10 import java.util.concurrent.atomic.AtomicInteger;
     11 
     12 import org.android.btsap.SapApi;
     13 import org.android.btsap.SapApi.*;
     14 import com.google.protobuf.micro.*;
     15 
     16 import android.os.Parcel;
     17 import android.os.Parcelable;
     18 import android.util.Log;
     19 
     20 /**
     21  * SapMessage is used for incoming and outgoing messages.
     22  *
     23  * For incoming messages
     24  *
     25  */
     26 public class SapMessage {
     27 
     28     public static final String TAG = "SapMessage";
     29     public static final boolean DEBUG = SapService.DEBUG;
     30     public static final boolean VERBOSE = SapService.VERBOSE;
     31     public static final boolean TEST = false;
     32 
     33     /* Message IDs - SAP specification */
     34     public static final int ID_CONNECT_REQ        = 0x00;
     35     public static final int ID_CONNECT_RESP       = 0x01;
     36 
     37     public static final int ID_DISCONNECT_REQ     = 0x02;
     38     public static final int ID_DISCONNECT_RESP    = 0x03;
     39     public static final int ID_DISCONNECT_IND     = 0x04;
     40 
     41     public static final int ID_TRANSFER_APDU_REQ  = 0x05;
     42     public static final int ID_TRANSFER_APDU_RESP = 0x06;
     43 
     44     public static final int ID_TRANSFER_ATR_REQ   = 0x07;
     45     public static final int ID_TRANSFER_ATR_RESP  = 0x08;
     46 
     47     public static final int ID_POWER_SIM_OFF_REQ  = 0x09;
     48     public static final int ID_POWER_SIM_OFF_RESP = 0x0A;
     49 
     50     public static final int ID_POWER_SIM_ON_REQ   = 0x0B;
     51     public static final int ID_POWER_SIM_ON_RESP  = 0x0C;
     52 
     53     public static final int ID_RESET_SIM_REQ      = 0x0D;
     54     public static final int ID_RESET_SIM_RESP     = 0x0E;
     55 
     56     public static final int ID_TRANSFER_CARD_READER_STATUS_REQ  = 0x0F;
     57     public static final int ID_TRANSFER_CARD_READER_STATUS_RESP = 0x10;
     58 
     59     public static final int ID_STATUS_IND         = 0x11;
     60     public static final int ID_ERROR_RESP         = 0x12;
     61 
     62     public static final int ID_SET_TRANSPORT_PROTOCOL_REQ  = 0x13;
     63     public static final int ID_SET_TRANSPORT_PROTOCOL_RESP = 0x14;
     64 
     65     /* Message IDs - RIL specific unsolicited */
     66     // First RIL message id
     67     public static final int ID_RIL_BASE                    = 0x100;
     68     // RIL_UNSOL_RIL_CONNECTED
     69     public static final int ID_RIL_UNSOL_CONNECTED         = 0x100;
     70     // A disconnect ind from RIL will be converted after handled locally
     71     public static final int ID_RIL_UNSOL_DISCONNECT_IND    = 0x102;
     72     // All others
     73     public static final int ID_RIL_UNKNOWN                 = 0x1ff;
     74 
     75     /* Message IDs - RIL specific solicited */
     76     public static final int ID_RIL_GET_SIM_STATUS_REQ      = 0x200; // RIL_REQUEST_GET_SIM_STATUS
     77     /* Test signals used to set the reference ril in test mode */
     78     public static final int ID_RIL_SIM_ACCESS_TEST_REQ     = 0x201; // RIL_REQUEST_SIM_ACCESS_TEST
     79     public static final int ID_RIL_SIM_ACCESS_TEST_RESP    = 0x202; /* response for
     80                                                                     RIL_REQUEST_SIM_ACCESS_TEST */
     81 
     82     /* Parameter IDs and lengths */
     83     public static final int PARAM_MAX_MSG_SIZE_ID        = 0x00;
     84     public static final int PARAM_MAX_MSG_SIZE_LENGTH    = 2;
     85 
     86     public static final int PARAM_CONNECTION_STATUS_ID   = 0x01;
     87     public static final int PARAM_CONNECTION_STATUS_LENGTH = 1;
     88 
     89     public static final int PARAM_RESULT_CODE_ID         = 0x02;
     90     public static final int PARAM_RESULT_CODE_LENGTH     = 1;
     91 
     92     public static final int PARAM_DISCONNECT_TYPE_ID     = 0x03;
     93     public static final int PARAM_DISCONNECT_TYPE_LENGTH = 1;
     94 
     95     public static final int PARAM_COMMAND_APDU_ID        = 0x04;
     96 
     97     public static final int PARAM_COMMAND_APDU7816_ID    = 0x10;
     98 
     99     public static final int PARAM_RESPONSE_APDU_ID       = 0x05;
    100 
    101     public static final int PARAM_ATR_ID                 = 0x06;
    102 
    103     public static final int PARAM_CARD_READER_STATUS_ID  = 0x07;
    104     public static final int PARAM_CARD_READER_STATUS_LENGTH = 1;
    105 
    106     public static final int PARAM_STATUS_CHANGE_ID       = 0x08;
    107     public static final int PARAM_STATUS_CHANGE_LENGTH   = 1;
    108 
    109     public static final int PARAM_TRANSPORT_PROTOCOL_ID        = 0x09;
    110     public static final int PARAM_TRANSPORT_PROTOCOL_LENGTH    = 1;
    111 
    112     /* Result codes */
    113     public static final int RESULT_OK                        = 0x00;
    114     public static final int RESULT_ERROR_NO_REASON           = 0x01;
    115     public static final int RESULT_ERROR_CARD_NOT_ACCESSIBLE = 0x02;
    116     public static final int RESULT_ERROR_CARD_POWERED_OFF    = 0x03;
    117     public static final int RESULT_ERROR_CARD_REMOVED        = 0x04;
    118     public static final int RESULT_ERROR_CARD_POWERED_ON     = 0x05;
    119     public static final int RESULT_ERROR_DATA_NOT_AVAILABLE  = 0x06;
    120     public static final int RESULT_ERROR_NOT_SUPPORTED       = 0x07;
    121 
    122     /* Connection Status codes */
    123     public static final int CON_STATUS_OK                             = 0x00;
    124     public static final int CON_STATUS_ERROR_CONNECTION               = 0x01;
    125     public static final int CON_STATUS_ERROR_MAX_MSG_SIZE_UNSUPPORTED = 0x02;
    126     public static final int CON_STATUS_ERROR_MAX_MSG_SIZE_TOO_SMALL   = 0x03;
    127     public static final int CON_STATUS_OK_ONGOING_CALL                = 0x04;
    128 
    129     /* Disconnection type */
    130     public static final int DISC_GRACEFULL                = 0x00;
    131     public static final int DISC_IMMEDIATE                = 0x01;
    132     public static final int DISC_FORCED                   = 0x100; // Used internal only
    133     public static final int DISC_RFCOMM                   = 0x101; // Used internal only
    134 
    135     /* Status Change */
    136     public static final int STATUS_UNKNOWN_ERROR       = 0x00;
    137     public static final int STATUS_CARD_RESET          = 0x01;
    138     public static final int STATUS_CARD_NOT_ACCESSIBLE = 0x02;
    139     public static final int STATUS_CARD_REMOVED        = 0x03;
    140     public static final int STATUS_CARD_INSERTED       = 0x04;
    141     public static final int STATUS_RECOVERED           = 0x05;
    142 
    143     /* Transport Protocol */
    144     public static final int TRANS_PROTO_T0           = 0x00;
    145     public static final int TRANS_PROTO_T1           = 0x01;
    146 
    147     /* Test Mode */
    148     public static final int TEST_MODE_DISABLE        = 0x00;
    149     public static final int TEST_MODE_ENABLE         = 0x01;
    150 
    151     /* Used to detect uninitialized values */
    152     public static final int INVALID_VALUE = -1;
    153 
    154     /* Stuff related to communicating with rild-bt */
    155     static final int RESPONSE_SOLICITED = 0;
    156     static final int RESPONSE_UNSOLICITED = 1;
    157     static AtomicInteger sNextSerial = new AtomicInteger(1);
    158 
    159     // Map<rilSerial, RequestType> - HashTable is synchronized
    160     private static Map<Integer, Integer> sOngoingRequests = new Hashtable<Integer, Integer>();
    161     private boolean mSendToRil = false; // set to true for messages that needs to go to the RIL
    162     private boolean mClearRilQueue = false; /* set to true for messages that needs to cause the
    163                                               sOngoingRequests to be cleared. */
    164 
    165     /* Instance members */
    166     private int mMsgType = INVALID_VALUE; // The SAP message ID
    167 
    168     private int mMaxMsgSize = INVALID_VALUE;
    169     private int mConnectionStatus = INVALID_VALUE;
    170     private int mResultCode = INVALID_VALUE;
    171     private int mDisconnectionType = INVALID_VALUE;
    172     private int mCardReaderStatus = INVALID_VALUE;
    173     private int mStatusChange = INVALID_VALUE;
    174     private int mTransportProtocol = INVALID_VALUE;
    175     private int mTestMode = INVALID_VALUE;
    176     private byte[] mApdu = null;
    177     private byte[] mApdu7816 = null;
    178     private byte[] mApduResp = null;
    179     private byte[] mAtr = null;
    180 
    181     /**
    182      * Create a SapMessage
    183      * @param msgType the SAP message type
    184      */
    185     public SapMessage(int msgType){
    186         this.mMsgType = msgType;
    187     }
    188 
    189     private static void resetPendingRilMessages() {
    190         int numMessages = sOngoingRequests.size();
    191         if(numMessages != 0) {
    192             Log.w(TAG, "Clearing message queue with size: " + numMessages);
    193             sOngoingRequests.clear();
    194         }
    195     }
    196 
    197     public static int getNumPendingRilMessages() {
    198         return sOngoingRequests.size();
    199     }
    200 
    201     public int getMsgType() {
    202         return mMsgType;
    203     }
    204 
    205     public void setMsgType(int msgType) {
    206         this.mMsgType = msgType;
    207     }
    208 
    209     public int getMaxMsgSize() {
    210         return mMaxMsgSize;
    211     }
    212 
    213     public void setMaxMsgSize(int maxMsgSize) {
    214         this.mMaxMsgSize = maxMsgSize;
    215     }
    216 
    217     public int getConnectionStatus() {
    218         return mConnectionStatus;
    219     }
    220 
    221     public void setConnectionStatus(int connectionStatus) {
    222         this.mConnectionStatus = connectionStatus;
    223     }
    224 
    225     public int getResultCode() {
    226         return mResultCode;
    227     }
    228 
    229     public void setResultCode(int resultCode) {
    230         this.mResultCode = resultCode;
    231     }
    232 
    233     public int getDisconnectionType() {
    234         return mDisconnectionType;
    235     }
    236 
    237     public void setDisconnectionType(int disconnectionType) {
    238         this.mDisconnectionType = disconnectionType;
    239     }
    240 
    241     public int getCardReaderStatus() {
    242         return mCardReaderStatus;
    243     }
    244 
    245     public void setCardReaderStatus(int cardReaderStatus) {
    246         this.mCardReaderStatus = cardReaderStatus;
    247     }
    248 
    249     public int getStatusChange() {
    250         return mStatusChange;
    251     }
    252 
    253     public void setStatusChange(int statusChange) {
    254         this.mStatusChange = statusChange;
    255     }
    256 
    257     public int getTransportProtocol() {
    258         return mTransportProtocol;
    259     }
    260 
    261     public void setTransportProtocol(int transportProtocol) {
    262         this.mTransportProtocol = transportProtocol;
    263     }
    264 
    265     public byte[] getApdu() {
    266         return mApdu;
    267     }
    268 
    269     public void setApdu(byte[] apdu) {
    270         this.mApdu = apdu;
    271     }
    272 
    273     public byte[] getApdu7816() {
    274         return mApdu7816;
    275     }
    276 
    277     public void setApdu7816(byte[] apdu) {
    278         this.mApdu7816 = apdu;
    279     }
    280 
    281     public byte[] getApduResp() {
    282         return mApduResp;
    283     }
    284 
    285     public void setApduResp(byte[] apduResp) {
    286         this.mApduResp = apduResp;
    287     }
    288 
    289     public byte[] getAtr() {
    290         return mAtr;
    291     }
    292 
    293     public void setAtr(byte[] atr) {
    294         this.mAtr = atr;
    295     }
    296 
    297     public boolean getSendToRil() {
    298         return mSendToRil;
    299     }
    300 
    301     public void setSendToRil(boolean sendToRil) {
    302         this.mSendToRil = sendToRil;
    303     }
    304 
    305     public boolean getClearRilQueue() {
    306         return mClearRilQueue;
    307     }
    308 
    309     public void setClearRilQueue(boolean clearRilQueue) {
    310         this.mClearRilQueue = clearRilQueue;
    311     }
    312 
    313     public int getTestMode() {
    314         return mTestMode;
    315     }
    316 
    317     public void setTestMode(int testMode) {
    318         this.mTestMode = testMode;
    319     }
    320 
    321     private int getParamCount() {
    322         int paramCount = 0;
    323         if(mMaxMsgSize != INVALID_VALUE)
    324             paramCount++;
    325         if(mConnectionStatus != INVALID_VALUE)
    326             paramCount++;
    327         if(mResultCode != INVALID_VALUE)
    328             paramCount++;
    329         if(mDisconnectionType != INVALID_VALUE)
    330             paramCount++;
    331         if(mCardReaderStatus != INVALID_VALUE)
    332             paramCount++;
    333         if(mStatusChange != INVALID_VALUE)
    334             paramCount++;
    335         if(mTransportProtocol != INVALID_VALUE)
    336             paramCount++;
    337         if(mApdu != null)
    338             paramCount++;
    339         if(mApdu7816 != null)
    340             paramCount++;
    341         if(mApduResp != null)
    342             paramCount++;
    343         if(mAtr != null)
    344             paramCount++;
    345         return paramCount;
    346     }
    347 
    348     /**
    349      * Construct a SapMessage based on the incoming rfcomm request.
    350      * @param requestType The type of the request
    351      * @param is the input stream to read the data from
    352      * @return the resulting message, or null if an error occurs
    353      */
    354     @SuppressWarnings("unused")
    355     public static SapMessage readMessage(int requestType, InputStream is) {
    356         SapMessage newMessage = new SapMessage(requestType);
    357 
    358         /* Read in all the parameters (if any) */
    359         int paramCount;
    360         try {
    361             paramCount = is.read();
    362             skip(is, 2); // Skip the 2 padding bytes
    363             if(paramCount > 0) {
    364                 if(VERBOSE) Log.i(TAG, "Parsing message with paramCount: " + paramCount);
    365                 if(newMessage.parseParameters(paramCount, is) == false)
    366                     return null;
    367             }
    368         } catch (IOException e) {
    369             Log.w(TAG, e);
    370             return null;
    371         }
    372         if(DEBUG) Log.i(TAG, "readMessage() Read message: " + getMsgTypeName(requestType));
    373 
    374         /* Validate parameters */
    375         switch(requestType) {
    376         case ID_CONNECT_REQ:
    377             if(newMessage.getMaxMsgSize() == INVALID_VALUE) {
    378                 Log.e(TAG, "Missing MaxMsgSize parameter in CONNECT_REQ");
    379                 return null;
    380             }
    381             break;
    382         case ID_TRANSFER_APDU_REQ:
    383             if(newMessage.getApdu() == null &&
    384                    newMessage.getApdu7816() == null) {
    385                 Log.e(TAG, "Missing Apdu parameter in TRANSFER_APDU_REQ");
    386                 return null;
    387             }
    388             newMessage.setSendToRil(true);
    389             break;
    390         case ID_SET_TRANSPORT_PROTOCOL_REQ:
    391             if(newMessage.getTransportProtocol() == INVALID_VALUE) {
    392                 Log.e(TAG, "Missing TransportProtocol parameter in SET_TRANSPORT_PROTOCOL_REQ");
    393                 return null;
    394             }
    395             newMessage.setSendToRil(true);
    396             break;
    397         case ID_TRANSFER_ATR_REQ:  /* No params */
    398         case ID_POWER_SIM_OFF_REQ: /* No params */
    399         case ID_POWER_SIM_ON_REQ:  /* No params */
    400         case ID_RESET_SIM_REQ:     /* No params */
    401         case ID_TRANSFER_CARD_READER_STATUS_REQ: /* No params */
    402             newMessage.setSendToRil(true);
    403             break;
    404         case ID_DISCONNECT_REQ:    /* No params */
    405             break;
    406         default:
    407             Log.e(TAG, "Unknown request type");
    408             return null;
    409         }
    410         return newMessage;
    411     }
    412 
    413     /**
    414      * Blocking read of an entire array of data.
    415      * @param is the input stream to read from
    416      * @param buffer the buffer to read into - the length of the buffer will
    417      *        determine how many bytes will be read.
    418      */
    419     private static void read(InputStream is, byte[] buffer) throws IOException {
    420         int bytesToRead = buffer.length;
    421         int bytesRead = 0;
    422         int tmpBytesRead;
    423         while (bytesRead < bytesToRead) {
    424             tmpBytesRead = is.read(buffer, bytesRead, bytesToRead-bytesRead);
    425             if(tmpBytesRead == -1)
    426                 throw new IOException("EOS reached while reading a byte array.");
    427             else
    428                 bytesRead += tmpBytesRead;
    429         }
    430     }
    431 
    432     /**
    433      * Skip a number of bytes in an InputStream.
    434      * @param is the input stream
    435      * @param count the number of bytes to skip
    436      * @throws IOException In case of reaching EOF or a stream error
    437      */
    438     private static void skip(InputStream is, int count) throws IOException {
    439         for(int i = 0; i < count; i++) {
    440             is.read(); // Do not use the InputStream.skip as it fails for some stream types
    441         }
    442     }
    443 
    444     /**
    445      * Read the parameters from the stream and update the relevant members.
    446      * This function will ensure that all parameters are read from the stream, even
    447      * if an error is detected.
    448      * @param count the number of parameters to read
    449      * @param is the input stream
    450      * @return True if all parameters were successfully parsed, False if an error were detected.
    451      * @throws IOException
    452      */
    453     private boolean parseParameters(int count, InputStream is) throws IOException {
    454         int paramId;
    455         int paramLength;
    456         boolean success = true;
    457         int skipLen = 0;
    458 
    459         for(int i = 0; i < count; i++) {
    460             paramId = is.read();
    461             is.read(); // Skip the reserved byte
    462             paramLength = is.read();
    463             paramLength = paramLength << 8 | is.read();
    464 
    465             // As per SAP spec padding should be 0-3 bytes
    466             if ((paramLength % 4) != 0)
    467                 skipLen = 4 - (paramLength % 4);
    468 
    469             if(VERBOSE) Log.i(TAG, "parsing paramId: " + paramId + " with length: " + paramLength);
    470             switch(paramId) {
    471             case PARAM_MAX_MSG_SIZE_ID:
    472                 if(paramLength != PARAM_MAX_MSG_SIZE_LENGTH) {
    473                     Log.e(TAG, "Received PARAM_MAX_MSG_SIZE with wrong length: " +
    474                             paramLength + " skipping this parameter.");
    475                     skip(is, paramLength + skipLen);
    476                     success = false;
    477                 } else {
    478                     mMaxMsgSize = is.read();
    479                     mMaxMsgSize = mMaxMsgSize << 8 | is.read();
    480                     skip(is, 4 - PARAM_MAX_MSG_SIZE_LENGTH);
    481                 }
    482                 break;
    483             case PARAM_COMMAND_APDU_ID:
    484                 mApdu = new byte[paramLength];
    485                 read(is, mApdu);
    486                 skip(is, skipLen);
    487                 break;
    488             case PARAM_COMMAND_APDU7816_ID:
    489                 mApdu7816 = new byte[paramLength];
    490                 read(is, mApdu7816);
    491                 skip(is, skipLen);
    492                 break;
    493             case PARAM_TRANSPORT_PROTOCOL_ID:
    494                 if(paramLength != PARAM_TRANSPORT_PROTOCOL_LENGTH) {
    495                     Log.e(TAG, "Received PARAM_TRANSPORT_PROTOCOL with wrong length: " +
    496                             paramLength + " skipping this parameter.");
    497                     skip(is, paramLength + skipLen);
    498                     success = false;
    499                 } else {
    500                     mTransportProtocol = is.read();
    501                     skip(is, 4 - PARAM_TRANSPORT_PROTOCOL_LENGTH);
    502                 }
    503                 break;
    504             case PARAM_CONNECTION_STATUS_ID:
    505                 // not needed for server role, but used for module test
    506                 if(paramLength != PARAM_CONNECTION_STATUS_LENGTH) {
    507                     Log.e(TAG, "Received PARAM_CONNECTION_STATUS with wrong length: " +
    508                             paramLength + " skipping this parameter.");
    509                     skip(is, paramLength + skipLen);
    510                     success = false;
    511                 } else {
    512                     mConnectionStatus = is.read();
    513                     skip(is, 4 - PARAM_CONNECTION_STATUS_LENGTH);
    514                 }
    515                 break;
    516             case PARAM_CARD_READER_STATUS_ID:
    517                 // not needed for server role, but used for module test
    518                 if(paramLength != PARAM_CARD_READER_STATUS_LENGTH) {
    519                     Log.e(TAG, "Received PARAM_CARD_READER_STATUS with wrong length: " +
    520                             paramLength + " skipping this parameter.");
    521                     skip(is, paramLength + skipLen);
    522                     success = false;
    523                 } else {
    524                     mCardReaderStatus = is.read();
    525                     skip(is, 4 - PARAM_CARD_READER_STATUS_LENGTH);
    526                 }
    527                 break;
    528             case PARAM_STATUS_CHANGE_ID:
    529                 // not needed for server role, but used for module test
    530                 if(paramLength != PARAM_STATUS_CHANGE_LENGTH) {
    531                     Log.e(TAG, "Received PARAM_STATUS_CHANGE with wrong length: " +
    532                             paramLength + " skipping this parameter.");
    533                     skip(is, paramLength + skipLen);
    534                     success = false;
    535                 } else {
    536                     mStatusChange = is.read();
    537                     skip(is, 4 - PARAM_STATUS_CHANGE_LENGTH);
    538                 }
    539                 break;
    540             case PARAM_RESULT_CODE_ID:
    541                 // not needed for server role, but used for module test
    542                 if(paramLength != PARAM_RESULT_CODE_LENGTH) {
    543                     Log.e(TAG, "Received PARAM_RESULT_CODE with wrong length: " +
    544                             paramLength + " skipping this parameter.");
    545                     skip(is, paramLength + skipLen);
    546                     success = false;
    547                 } else {
    548                     mResultCode = is.read();
    549                     skip(is, 4 - PARAM_RESULT_CODE_LENGTH);
    550                 }
    551                 break;
    552             case PARAM_DISCONNECT_TYPE_ID:
    553                 // not needed for server role, but used for module test
    554                 if(paramLength != PARAM_DISCONNECT_TYPE_LENGTH) {
    555                     Log.e(TAG, "Received PARAM_DISCONNECT_TYPE_ID with wrong length: " +
    556                             paramLength + " skipping this parameter.");
    557                     skip(is, paramLength + skipLen);
    558                     success = false;
    559                 } else {
    560                     mDisconnectionType = is.read();
    561                     skip(is, 4 - PARAM_DISCONNECT_TYPE_LENGTH);
    562                 }
    563                 break;
    564             case PARAM_RESPONSE_APDU_ID:
    565                 // not needed for server role, but used for module test
    566                 mApduResp = new byte[paramLength];
    567                 read(is, mApduResp);
    568                 skip(is, skipLen);
    569                 break;
    570             case PARAM_ATR_ID:
    571                 // not needed for server role, but used for module test
    572                 mAtr = new byte[paramLength];
    573                 read(is, mAtr);
    574                 skip(is, skipLen);
    575                 break;
    576             default:
    577                 Log.e(TAG, "Received unknown parameter ID: " + paramId + " length: " +
    578                         paramLength + " skipping this parameter.");
    579                 skip(is, paramLength + skipLen);
    580             }
    581         }
    582         return success;
    583     }
    584 
    585     /**
    586      * Writes a single value parameter of 1 or 2 bytes in length.
    587      * @param os The BufferedOutputStream to write to.
    588      * @param id The Parameter ID
    589      * @param value The parameter value
    590      * @param length The length of the parameter value
    591      * @throws IOException if the write to os fails
    592      */
    593     private static void writeParameter(OutputStream os, int id, int value, int length)
    594                 throws IOException {
    595 
    596         /* Parameter Header*/
    597         os.write(id);
    598         os.write(0);
    599         os.write(0);
    600         os.write(length);
    601 
    602         switch(length) {
    603         case 1:
    604             os.write(value & 0xff);
    605             os.write(0); // Padding
    606             os.write(0); // Padding
    607             os.write(0); // padding
    608             break;
    609         case 2:
    610             os.write((value >> 8) & 0xff);
    611             os.write(value & 0xff);
    612             os.write(0); // Padding
    613             os.write(0); // padding
    614             break;
    615         default:
    616             throw new IOException("Unable to write value of length: " + length);
    617         }
    618     }
    619 
    620     /**
    621      * Writes a byte[] parameter of any length.
    622      * @param os The BufferedOutputStream to write to.
    623      * @param id The Parameter ID
    624      * @param value The byte array to write, the length will be extracted from the array.
    625      * @throws IOException if the write to os fails
    626      */
    627     private static void writeParameter(OutputStream os, int id, byte[] value) throws IOException {
    628 
    629         /* Parameter Header*/
    630         os.write(id);
    631         os.write(0); // reserved
    632         os.write((value.length >> 8) & 0xff);
    633         os.write(value.length & 0xff);
    634 
    635         /* Payload */
    636         os.write(value);
    637         if (value.length % 4 != 0) {
    638             for (int i = 0; i < (4 - (value.length % 4)); ++i) {
    639                 os.write(0); // Padding
    640             }
    641         }
    642     }
    643 
    644     public void write(OutputStream os) throws IOException {
    645         /* Write the header */
    646         os.write(mMsgType);
    647         os.write(getParamCount());
    648         os.write(0); // padding
    649         os.write(0); // padding
    650 
    651         /* write the parameters */
    652         if(mConnectionStatus != INVALID_VALUE) {
    653             writeParameter(os,PARAM_CONNECTION_STATUS_ID, mConnectionStatus,
    654                             PARAM_CONNECTION_STATUS_LENGTH);
    655         }
    656         if(mMaxMsgSize != INVALID_VALUE) {
    657             writeParameter(os, PARAM_MAX_MSG_SIZE_ID, mMaxMsgSize,
    658                             PARAM_MAX_MSG_SIZE_LENGTH);
    659         }
    660         if(mResultCode != INVALID_VALUE) {
    661             writeParameter(os, PARAM_RESULT_CODE_ID, mResultCode,
    662                             PARAM_RESULT_CODE_LENGTH);
    663         }
    664         if(mDisconnectionType != INVALID_VALUE) {
    665             writeParameter(os, PARAM_DISCONNECT_TYPE_ID, mDisconnectionType,
    666                             PARAM_DISCONNECT_TYPE_LENGTH);
    667         }
    668         if(mCardReaderStatus != INVALID_VALUE) {
    669             writeParameter(os, PARAM_CARD_READER_STATUS_ID, mCardReaderStatus,
    670                             PARAM_CARD_READER_STATUS_LENGTH);
    671         }
    672         if(mStatusChange != INVALID_VALUE) {
    673             writeParameter(os, PARAM_STATUS_CHANGE_ID, mStatusChange,
    674                             PARAM_STATUS_CHANGE_LENGTH);
    675         }
    676         if(mTransportProtocol != INVALID_VALUE) {
    677             writeParameter(os, PARAM_TRANSPORT_PROTOCOL_ID, mTransportProtocol,
    678                             PARAM_TRANSPORT_PROTOCOL_LENGTH);
    679         }
    680         if(mApdu != null) {
    681             writeParameter(os, PARAM_COMMAND_APDU_ID, mApdu);
    682         }
    683         if(mApdu7816 != null) {
    684             writeParameter(os, PARAM_COMMAND_APDU7816_ID, mApdu7816);
    685         }
    686         if(mApduResp != null) {
    687             writeParameter(os, PARAM_RESPONSE_APDU_ID, mApduResp);
    688         }
    689         if(mAtr != null) {
    690             writeParameter(os, PARAM_ATR_ID, mAtr);
    691         }
    692     }
    693 
    694     /***************************************************************************
    695      * RILD Interface message conversion functions.
    696      ***************************************************************************/
    697 
    698     /**
    699      * We use this function to
    700      * @param length
    701      * @param rawOut
    702      * @throws IOException
    703      */
    704     private void writeLength(int length, CodedOutputStreamMicro out) throws IOException {
    705         byte[] dataLength = new byte[4];
    706         dataLength[0] = dataLength[1] = 0;
    707         dataLength[2] = (byte)((length >> 8) & 0xff);
    708         dataLength[3] = (byte)((length) & 0xff);
    709         out.writeRawBytes(dataLength);
    710     }
    711     /**
    712      * Write this SAP message as a rild compatible protobuf message.
    713      * Solicited Requests are formed as follows:
    714      *  int type - the rild-bt type
    715      *  int serial - an number incrementing for each message.
    716      */
    717     public void writeReqToStream(CodedOutputStreamMicro out) throws IOException {
    718 
    719         int rilSerial = sNextSerial.getAndIncrement();
    720         SapApi.MsgHeader msg = new MsgHeader();
    721         /* Common variables for all requests */
    722         msg.setToken(rilSerial);
    723         msg.setType(SapApi.REQUEST);
    724         msg.setError(SapApi.RIL_E_UNUSED);
    725 
    726         switch(mMsgType) {
    727         case ID_CONNECT_REQ:
    728         {
    729             SapApi.RIL_SIM_SAP_CONNECT_REQ reqMsg = new RIL_SIM_SAP_CONNECT_REQ();
    730             reqMsg.setMaxMessageSize(mMaxMsgSize);
    731             msg.setId(SapApi.RIL_SIM_SAP_CONNECT);
    732             msg.setPayload(ByteStringMicro.copyFrom(reqMsg.toByteArray()));
    733             writeLength(msg.getSerializedSize(), out);
    734             msg.writeTo(out);
    735             break;
    736         }
    737         case ID_DISCONNECT_REQ:
    738         {
    739             SapApi.RIL_SIM_SAP_DISCONNECT_REQ reqMsg = new RIL_SIM_SAP_DISCONNECT_REQ();
    740             msg.setId(SapApi.RIL_SIM_SAP_DISCONNECT);
    741             msg.setPayload(ByteStringMicro.copyFrom(reqMsg.toByteArray()));
    742             writeLength(msg.getSerializedSize(), out);
    743             msg.writeTo(out);
    744             break;
    745         }
    746         case ID_TRANSFER_APDU_REQ:
    747         {
    748             SapApi.RIL_SIM_SAP_APDU_REQ reqMsg = new RIL_SIM_SAP_APDU_REQ();
    749             msg.setId(SapApi.RIL_SIM_SAP_APDU);
    750             if(mApdu != null) {
    751                 reqMsg.setType(SapApi.RIL_SIM_SAP_APDU_REQ.RIL_TYPE_APDU);
    752                 reqMsg.setCommand(ByteStringMicro.copyFrom(mApdu));
    753             } else if (mApdu7816 != null) {
    754                 reqMsg.setType(SapApi.RIL_SIM_SAP_APDU_REQ.RIL_TYPE_APDU7816);
    755                 reqMsg.setCommand(ByteStringMicro.copyFrom(mApdu7816));
    756             } else {
    757                 Log.e(TAG, "Missing Apdu parameter in TRANSFER_APDU_REQ");
    758                 throw new IllegalArgumentException();
    759             }
    760             msg.setPayload(ByteStringMicro.copyFrom(reqMsg.toByteArray()));
    761             writeLength(msg.getSerializedSize(), out);
    762             msg.writeTo(out);
    763             break;
    764         }
    765         case ID_SET_TRANSPORT_PROTOCOL_REQ:
    766         {
    767             SapApi.RIL_SIM_SAP_SET_TRANSFER_PROTOCOL_REQ reqMsg =
    768                                             new RIL_SIM_SAP_SET_TRANSFER_PROTOCOL_REQ();
    769             msg.setId(SapApi.RIL_SIM_SAP_SET_TRANSFER_PROTOCOL);
    770 
    771             if(mTransportProtocol == TRANS_PROTO_T0) {
    772                 reqMsg.setProtocol(SapApi.RIL_SIM_SAP_SET_TRANSFER_PROTOCOL_REQ.t0);
    773             } else if(mTransportProtocol == TRANS_PROTO_T1) {
    774                 reqMsg.setProtocol(SapApi.RIL_SIM_SAP_SET_TRANSFER_PROTOCOL_REQ.t1);
    775             } else {
    776                 Log.e(TAG, "Missing or invalid TransportProtocol parameter in"+
    777                            " SET_TRANSPORT_PROTOCOL_REQ: "+ mTransportProtocol );
    778                 throw new IllegalArgumentException();
    779             }
    780             msg.setPayload(ByteStringMicro.copyFrom(reqMsg.toByteArray()));
    781             writeLength(msg.getSerializedSize(), out);
    782             msg.writeTo(out);
    783             break;
    784         }
    785         case ID_TRANSFER_ATR_REQ:
    786         {
    787             SapApi.RIL_SIM_SAP_TRANSFER_ATR_REQ reqMsg = new RIL_SIM_SAP_TRANSFER_ATR_REQ();
    788             msg.setId(SapApi.RIL_SIM_SAP_TRANSFER_ATR);
    789             msg.setPayload(ByteStringMicro.copyFrom(reqMsg.toByteArray()));
    790             writeLength(msg.getSerializedSize(), out);
    791             msg.writeTo(out);
    792             break;
    793         }
    794         case ID_POWER_SIM_OFF_REQ:
    795         {
    796             SapApi.RIL_SIM_SAP_POWER_REQ reqMsg = new RIL_SIM_SAP_POWER_REQ();
    797             msg.setId(SapApi.RIL_SIM_SAP_POWER);
    798             reqMsg.setState(false);
    799             msg.setPayload(ByteStringMicro.copyFrom(reqMsg.toByteArray()));
    800             writeLength(msg.getSerializedSize(), out);
    801             msg.writeTo(out);
    802             break;
    803         }
    804         case ID_POWER_SIM_ON_REQ:
    805         {
    806             SapApi.RIL_SIM_SAP_POWER_REQ reqMsg = new RIL_SIM_SAP_POWER_REQ();
    807             msg.setId(SapApi.RIL_SIM_SAP_POWER);
    808             reqMsg.setState(true);
    809             msg.setPayload(ByteStringMicro.copyFrom(reqMsg.toByteArray()));
    810             writeLength(msg.getSerializedSize(), out);
    811             msg.writeTo(out);
    812             break;
    813         }
    814         case ID_RESET_SIM_REQ:
    815         {
    816             SapApi.RIL_SIM_SAP_RESET_SIM_REQ reqMsg = new RIL_SIM_SAP_RESET_SIM_REQ();
    817             msg.setId(SapApi.RIL_SIM_SAP_RESET_SIM);
    818             msg.setPayload(ByteStringMicro.copyFrom(reqMsg.toByteArray()));
    819             writeLength(msg.getSerializedSize(), out);
    820             msg.writeTo(out);
    821             break;
    822         }
    823         case ID_TRANSFER_CARD_READER_STATUS_REQ:
    824         {
    825             SapApi.RIL_SIM_SAP_TRANSFER_CARD_READER_STATUS_REQ reqMsg =
    826                                     new RIL_SIM_SAP_TRANSFER_CARD_READER_STATUS_REQ();
    827             msg.setId(SapApi.RIL_SIM_SAP_TRANSFER_CARD_READER_STATUS);
    828             msg.setPayload(ByteStringMicro.copyFrom(reqMsg.toByteArray()));
    829             writeLength(msg.getSerializedSize(), out);
    830             msg.writeTo(out);
    831             break;
    832         }
    833         default:
    834             Log.e(TAG, "Unknown request type");
    835             throw new IllegalArgumentException();
    836         }
    837         /* Update the ongoing requests queue */
    838         if(mClearRilQueue == true) {
    839             resetPendingRilMessages();
    840         }
    841         // No need to synchronize this, as the HashList is already doing this.
    842         sOngoingRequests.put(rilSerial, mMsgType);
    843         out.flush();
    844     }
    845 
    846     public static SapMessage newInstance(MsgHeader msg) throws IOException {
    847         return new SapMessage(msg);
    848     }
    849 
    850     private SapMessage(MsgHeader msg) throws IOException {
    851         // All header members are "required" hence the hasXxxx() is not needed for those
    852         try{
    853             switch(msg.getType()){
    854             case SapApi.UNSOL_RESPONSE:
    855                 createUnsolicited(msg);
    856                 break;
    857             case SapApi.RESPONSE:
    858                 createSolicited(msg);
    859                 break;
    860             default:
    861                 throw new IOException("Wrong msg header received: Type: " + msg.getType());
    862             }
    863         } catch (InvalidProtocolBufferMicroException e) {
    864             Log.w(TAG, "Error occured parsing a RIL message", e);
    865             throw new IOException("Error occured parsing a RIL message");
    866         }
    867     }
    868 
    869     private void createUnsolicited(MsgHeader msg)
    870                     throws IOException, InvalidProtocolBufferMicroException {
    871         switch(msg.getId()) {
    872 // TODO:
    873 //        Not sure when we use these?        case RIL_UNSOL_RIL_CONNECTED:
    874 //            if(VERBOSE) Log.i(TAG, "RIL_UNSOL_RIL_CONNECTED received, ignoring");
    875 //            msgType = ID_RIL_UNSOL_CONNECTED;
    876 //            break;
    877         case SapApi.RIL_SIM_SAP_STATUS:
    878         {
    879             if(VERBOSE) Log.i(TAG, "RIL_SIM_SAP_STATUS_IND received");
    880             RIL_SIM_SAP_STATUS_IND indMsg =
    881                     RIL_SIM_SAP_STATUS_IND.parseFrom(msg.getPayload().toByteArray());
    882             mMsgType = ID_STATUS_IND;
    883             if(indMsg.hasStatusChange()) {
    884                 setStatusChange(indMsg.getStatusChange());
    885                 if(VERBOSE) Log.i(TAG, "RIL_UNSOL_SIM_SAP_STATUS_IND received value = "
    886                         + mStatusChange);
    887             } else {
    888                 if(VERBOSE) Log.i(TAG, "Wrong number of parameters in SAP_STATUS_IND, ignoring...");
    889                 mMsgType = ID_RIL_UNKNOWN;
    890             }
    891             break;
    892         }
    893         case SapApi.RIL_SIM_SAP_DISCONNECT:
    894         {
    895             if(VERBOSE) Log.i(TAG, "RIL_SIM_SAP_DISCONNECT_IND received");
    896 
    897             RIL_SIM_SAP_DISCONNECT_IND indMsg =
    898                     RIL_SIM_SAP_DISCONNECT_IND.parseFrom(msg.getPayload().toByteArray());
    899             mMsgType = ID_RIL_UNSOL_DISCONNECT_IND; // don't use ID_DISCONNECT_IND;
    900             if(indMsg.hasDisconnectType()) {
    901                 setDisconnectionType(indMsg.getDisconnectType());
    902                 if(VERBOSE) Log.i(TAG, "RIL_UNSOL_SIM_SAP_STATUS_IND received value = "
    903                                                                 + mDisconnectionType);
    904             } else {
    905                 if(VERBOSE) Log.i(TAG, "Wrong number of parameters in SAP_STATUS_IND, ignoring...");
    906                 mMsgType = ID_RIL_UNKNOWN;
    907             }
    908             break;
    909         }
    910         default:
    911             if(VERBOSE) Log.i(TAG, "Unused unsolicited message received, ignoring: " + msg.getId());
    912             mMsgType = ID_RIL_UNKNOWN;
    913         }
    914     }
    915 
    916     private void createSolicited(MsgHeader msg) throws IOException,
    917                                                        InvalidProtocolBufferMicroException{
    918         /* re-evaluate if we should just ignore these - we could simply catch the exception? */
    919         if(msg.hasToken() == false) throw new IOException("Token is missing");
    920         if(msg.hasError() == false) throw new IOException("Error code is missing");
    921         int serial = msg.getToken();
    922         int error = msg.getError();
    923         Integer reqType = null;
    924         reqType = sOngoingRequests.remove(serial);
    925         if(VERBOSE) Log.i(TAG, "RIL SOLICITED serial: " + serial + ", error: " + error
    926                 + " SapReqType: " + ((reqType== null)?"null":getMsgTypeName(reqType)));
    927 
    928         if(reqType == null) {
    929             /* This can happen if we get a resp. for a canceled request caused by a power off,
    930              *  reset or disconnect
    931              */
    932             Log.w(TAG, "Solicited response received on a command not initiated - ignoring.");
    933             return;
    934         }
    935         mResultCode = mapRilErrorCode(error);
    936 
    937         switch(reqType) {
    938         case ID_CONNECT_REQ:
    939         {
    940             RIL_SIM_SAP_CONNECT_RSP resMsg =
    941                     RIL_SIM_SAP_CONNECT_RSP.parseFrom(msg.getPayload().toByteArray());
    942             mMsgType = ID_CONNECT_RESP;
    943             if(resMsg.hasMaxMessageSize()) {
    944                 mMaxMsgSize = resMsg.getMaxMessageSize();
    945 
    946             }
    947             switch(resMsg.getResponse()) {
    948             case RIL_SIM_SAP_CONNECT_RSP.RIL_E_SUCCESS:
    949                 mConnectionStatus = CON_STATUS_OK;
    950                 break;
    951             case RIL_SIM_SAP_CONNECT_RSP.RIL_E_SAP_CONNECT_OK_CALL_ONGOING:
    952                 mConnectionStatus = CON_STATUS_OK_ONGOING_CALL;
    953                 break;
    954             case RIL_SIM_SAP_CONNECT_RSP.RIL_E_SAP_CONNECT_FAILURE:
    955                 mConnectionStatus = CON_STATUS_ERROR_CONNECTION;
    956                 break;
    957             case RIL_SIM_SAP_CONNECT_RSP.RIL_E_SAP_MSG_SIZE_TOO_LARGE:
    958                 mConnectionStatus = CON_STATUS_ERROR_MAX_MSG_SIZE_UNSUPPORTED;
    959                 break;
    960             case RIL_SIM_SAP_CONNECT_RSP.RIL_E_SAP_MSG_SIZE_TOO_SMALL:
    961                 mConnectionStatus = CON_STATUS_ERROR_MAX_MSG_SIZE_TOO_SMALL;
    962                 break;
    963             default:
    964                 mConnectionStatus = CON_STATUS_ERROR_CONNECTION; // Cannot happen!
    965                 break;
    966             }
    967             mResultCode = INVALID_VALUE;
    968             if(VERBOSE) Log.v(TAG, "  ID_CONNECT_REQ: mMaxMsgSize: " + mMaxMsgSize
    969                     + "  mConnectionStatus: " + mConnectionStatus);
    970             break;
    971         }
    972         case ID_DISCONNECT_REQ:
    973             mMsgType = ID_DISCONNECT_RESP;
    974             mResultCode = INVALID_VALUE;
    975             break;
    976         case ID_TRANSFER_APDU_REQ:
    977         {
    978             RIL_SIM_SAP_APDU_RSP resMsg =
    979                     RIL_SIM_SAP_APDU_RSP.parseFrom(msg.getPayload().toByteArray());
    980             mMsgType = ID_TRANSFER_APDU_RESP;
    981             switch(resMsg.getResponse()) {
    982             case RIL_SIM_SAP_APDU_RSP.RIL_E_SUCCESS:
    983                 mResultCode = RESULT_OK;
    984                 /* resMsg.getType is unused as the client knows the type of request used. */
    985                 if(resMsg.hasApduResponse()){
    986                     mApduResp = resMsg.getApduResponse().toByteArray();
    987                 }
    988                 break;
    989             case RIL_SIM_SAP_APDU_RSP.RIL_E_GENERIC_FAILURE:
    990                 mResultCode = RESULT_ERROR_NO_REASON;
    991                 break;
    992             case RIL_SIM_SAP_APDU_RSP.RIL_E_SIM_ABSENT:
    993                 mResultCode = RESULT_ERROR_CARD_NOT_ACCESSIBLE;
    994                 break;
    995             case RIL_SIM_SAP_APDU_RSP.RIL_E_SIM_ALREADY_POWERED_OFF:
    996                 mResultCode = RESULT_ERROR_CARD_POWERED_OFF;
    997                 break;
    998             case RIL_SIM_SAP_APDU_RSP.RIL_E_SIM_NOT_READY:
    999                 mResultCode = RESULT_ERROR_CARD_REMOVED;
   1000                 break;
   1001             default:
   1002                 mResultCode = RESULT_ERROR_NO_REASON;
   1003                 break;
   1004             }
   1005             break;
   1006         }
   1007         case ID_SET_TRANSPORT_PROTOCOL_REQ:
   1008         {
   1009             RIL_SIM_SAP_SET_TRANSFER_PROTOCOL_RSP resMsg =
   1010                         RIL_SIM_SAP_SET_TRANSFER_PROTOCOL_RSP.parseFrom(
   1011                                 msg.getPayload().toByteArray());
   1012             mMsgType = ID_SET_TRANSPORT_PROTOCOL_RESP;
   1013             switch(resMsg.getResponse()) {
   1014             case RIL_SIM_SAP_SET_TRANSFER_PROTOCOL_RSP.RIL_E_SUCCESS:
   1015                 mResultCode = RESULT_OK;
   1016                 break;
   1017             case RIL_SIM_SAP_SET_TRANSFER_PROTOCOL_RSP.RIL_E_GENERIC_FAILURE:
   1018                 mResultCode = RESULT_ERROR_NOT_SUPPORTED;
   1019                 break;
   1020             case RIL_SIM_SAP_SET_TRANSFER_PROTOCOL_RSP.RIL_E_SIM_ABSENT:
   1021                 mResultCode = RESULT_ERROR_CARD_NOT_ACCESSIBLE;
   1022                 break;
   1023             case RIL_SIM_SAP_SET_TRANSFER_PROTOCOL_RSP.RIL_E_SIM_ALREADY_POWERED_OFF:
   1024                 mResultCode = RESULT_ERROR_CARD_POWERED_OFF;
   1025                 break;
   1026             case RIL_SIM_SAP_SET_TRANSFER_PROTOCOL_RSP.RIL_E_SIM_NOT_READY:
   1027                 mResultCode = RESULT_ERROR_CARD_REMOVED;
   1028                 break;
   1029             default:
   1030                 mResultCode = RESULT_ERROR_NOT_SUPPORTED;
   1031                 break;
   1032             }
   1033             break;
   1034         }
   1035         case ID_TRANSFER_ATR_REQ:
   1036         {
   1037             RIL_SIM_SAP_TRANSFER_ATR_RSP resMsg =
   1038                     RIL_SIM_SAP_TRANSFER_ATR_RSP.parseFrom(msg.getPayload().toByteArray());
   1039             mMsgType =ID_TRANSFER_ATR_RESP;
   1040             if(resMsg.hasAtr()) {
   1041                 mAtr = resMsg.getAtr().toByteArray();
   1042             }
   1043             switch(resMsg.getResponse()) {
   1044             case RIL_SIM_SAP_TRANSFER_ATR_RSP.RIL_E_SUCCESS:
   1045                 mResultCode = RESULT_OK;
   1046                 break;
   1047             case RIL_SIM_SAP_TRANSFER_ATR_RSP.RIL_E_GENERIC_FAILURE:
   1048                 mResultCode = RESULT_ERROR_NO_REASON;
   1049                 break;
   1050             case RIL_SIM_SAP_TRANSFER_ATR_RSP.RIL_E_SIM_ABSENT:
   1051                 mResultCode = RESULT_ERROR_CARD_NOT_ACCESSIBLE;
   1052                 break;
   1053             case RIL_SIM_SAP_TRANSFER_ATR_RSP.RIL_E_SIM_ALREADY_POWERED_OFF:
   1054                 mResultCode = RESULT_ERROR_CARD_POWERED_OFF;
   1055                 break;
   1056             case RIL_SIM_SAP_TRANSFER_ATR_RSP.RIL_E_SIM_ALREADY_POWERED_ON:
   1057                 mResultCode = RESULT_ERROR_CARD_POWERED_ON;
   1058                 break;
   1059             case RIL_SIM_SAP_TRANSFER_ATR_RSP.RIL_E_SIM_DATA_NOT_AVAILABLE:
   1060                 mResultCode = RESULT_ERROR_DATA_NOT_AVAILABLE;
   1061                 break;
   1062             default:
   1063                 mResultCode = RESULT_ERROR_NO_REASON;
   1064                 break;
   1065             }
   1066             break;
   1067         }
   1068         case ID_POWER_SIM_OFF_REQ:
   1069         {
   1070             RIL_SIM_SAP_POWER_RSP resMsg =
   1071                     RIL_SIM_SAP_POWER_RSP.parseFrom(msg.getPayload().toByteArray());
   1072             mMsgType = ID_POWER_SIM_OFF_RESP;
   1073             switch(resMsg.getResponse()) {
   1074             case RIL_SIM_SAP_POWER_RSP.RIL_E_SUCCESS:
   1075                 mResultCode = RESULT_OK;
   1076                 break;
   1077             case RIL_SIM_SAP_POWER_RSP.RIL_E_GENERIC_FAILURE:
   1078                 mResultCode = RESULT_ERROR_NO_REASON;
   1079                 break;
   1080             case RIL_SIM_SAP_POWER_RSP.RIL_E_SIM_ABSENT:
   1081                 mResultCode = RESULT_ERROR_CARD_NOT_ACCESSIBLE;
   1082                 break;
   1083             case RIL_SIM_SAP_POWER_RSP.RIL_E_SIM_ALREADY_POWERED_OFF:
   1084                 mResultCode = RESULT_ERROR_CARD_POWERED_OFF;
   1085                 break;
   1086             case RIL_SIM_SAP_POWER_RSP.RIL_E_SIM_ALREADY_POWERED_ON:
   1087                 mResultCode = RESULT_ERROR_CARD_POWERED_ON;
   1088                 break;
   1089             default:
   1090                 mResultCode = RESULT_ERROR_NO_REASON;
   1091                 break;
   1092             }
   1093             break;
   1094         }
   1095         case ID_POWER_SIM_ON_REQ:
   1096         {
   1097             RIL_SIM_SAP_POWER_RSP resMsg =
   1098                     RIL_SIM_SAP_POWER_RSP.parseFrom(msg.getPayload().toByteArray());
   1099             mMsgType = ID_POWER_SIM_ON_RESP;
   1100             switch(resMsg.getResponse()) {
   1101             case RIL_SIM_SAP_POWER_RSP.RIL_E_SUCCESS:
   1102                 mResultCode = RESULT_OK;
   1103                 break;
   1104             case RIL_SIM_SAP_POWER_RSP.RIL_E_GENERIC_FAILURE:
   1105                 mResultCode = RESULT_ERROR_NO_REASON;
   1106                 break;
   1107             case RIL_SIM_SAP_POWER_RSP.RIL_E_SIM_ABSENT:
   1108                 mResultCode = RESULT_ERROR_CARD_NOT_ACCESSIBLE;
   1109                 break;
   1110             case RIL_SIM_SAP_POWER_RSP.RIL_E_SIM_ALREADY_POWERED_OFF:
   1111                 mResultCode = RESULT_ERROR_CARD_POWERED_OFF;
   1112                 break;
   1113             case RIL_SIM_SAP_POWER_RSP.RIL_E_SIM_ALREADY_POWERED_ON:
   1114                 mResultCode = RESULT_ERROR_CARD_POWERED_ON;
   1115                 break;
   1116             default:
   1117                 mResultCode = RESULT_ERROR_NO_REASON;
   1118                 break;
   1119             }
   1120             break;
   1121         }
   1122         case ID_RESET_SIM_REQ:
   1123         {
   1124             RIL_SIM_SAP_RESET_SIM_RSP resMsg =
   1125                     RIL_SIM_SAP_RESET_SIM_RSP.parseFrom(msg.getPayload().toByteArray());
   1126             mMsgType = ID_RESET_SIM_RESP;
   1127             switch(resMsg.getResponse()) {
   1128             case RIL_SIM_SAP_RESET_SIM_RSP.RIL_E_SUCCESS:
   1129                 mResultCode = RESULT_OK;
   1130                 break;
   1131             case RIL_SIM_SAP_RESET_SIM_RSP.RIL_E_GENERIC_FAILURE:
   1132                 mResultCode = RESULT_ERROR_NO_REASON;
   1133                 break;
   1134             case RIL_SIM_SAP_RESET_SIM_RSP.RIL_E_SIM_ABSENT:
   1135                 mResultCode = RESULT_ERROR_CARD_NOT_ACCESSIBLE;
   1136                 break;
   1137             case RIL_SIM_SAP_RESET_SIM_RSP.RIL_E_SIM_ALREADY_POWERED_OFF:
   1138                 mResultCode = RESULT_ERROR_CARD_POWERED_OFF;
   1139                 break;
   1140             default:
   1141                 mResultCode = RESULT_ERROR_NO_REASON;
   1142                 break;
   1143             }
   1144             break;
   1145         }
   1146         case ID_TRANSFER_CARD_READER_STATUS_REQ:
   1147         {
   1148             RIL_SIM_SAP_TRANSFER_CARD_READER_STATUS_RSP resMsg =
   1149                     RIL_SIM_SAP_TRANSFER_CARD_READER_STATUS_RSP.parseFrom(
   1150                             msg.getPayload().toByteArray());
   1151             mMsgType = ID_TRANSFER_CARD_READER_STATUS_RESP;
   1152             switch(resMsg.getResponse()) {
   1153             case RIL_SIM_SAP_TRANSFER_CARD_READER_STATUS_RSP.RIL_E_SUCCESS:
   1154                 mResultCode = RESULT_OK;
   1155                 if(resMsg.hasCardReaderStatus()) {
   1156                     mCardReaderStatus = resMsg.getCardReaderStatus();
   1157                 } else {
   1158                     mResultCode = RESULT_ERROR_DATA_NOT_AVAILABLE;
   1159                 }
   1160                 break;
   1161             case RIL_SIM_SAP_TRANSFER_CARD_READER_STATUS_RSP.RIL_E_GENERIC_FAILURE:
   1162                 mResultCode = RESULT_ERROR_NO_REASON;
   1163                 break;
   1164             case RIL_SIM_SAP_TRANSFER_CARD_READER_STATUS_RSP.RIL_E_SIM_DATA_NOT_AVAILABLE:
   1165                 mResultCode = RESULT_ERROR_DATA_NOT_AVAILABLE;
   1166                 break;
   1167             default:
   1168                 mResultCode = RESULT_ERROR_NO_REASON;
   1169                 break;
   1170             }
   1171             break;
   1172         }
   1173 
   1174         case ID_RIL_SIM_ACCESS_TEST_REQ: // TODO: implement in RILD
   1175             mMsgType = ID_RIL_SIM_ACCESS_TEST_RESP;
   1176             break;
   1177         default:
   1178             Log.e(TAG, "Unknown request type: " + reqType);
   1179 
   1180         }
   1181     }
   1182 
   1183 
   1184 
   1185     /* Map from RIL header error codes to SAP error codes */
   1186     private static int mapRilErrorCode(int rilErrorCode) {
   1187         switch(rilErrorCode) {
   1188         case SapApi.RIL_E_SUCCESS:
   1189             return RESULT_OK;
   1190         case SapApi.RIL_E_CANCELLED:
   1191             return RESULT_ERROR_NO_REASON;
   1192         case SapApi.RIL_E_GENERIC_FAILURE:
   1193             return RESULT_ERROR_NO_REASON;
   1194         case SapApi.RIL_E_RADIO_NOT_AVAILABLE:
   1195             return RESULT_ERROR_CARD_NOT_ACCESSIBLE;
   1196         case SapApi.RIL_E_INVALID_PARAMETER:
   1197             return RESULT_ERROR_NO_REASON;
   1198         case SapApi.RIL_E_REQUEST_NOT_SUPPORTED:
   1199             return RESULT_ERROR_NOT_SUPPORTED;
   1200         default:
   1201             return RESULT_ERROR_NO_REASON;
   1202         }
   1203     }
   1204 
   1205 
   1206 
   1207     public static String getMsgTypeName(int msgType) {
   1208         if(DEBUG || VERBOSE) {
   1209             switch (msgType)
   1210             {
   1211                 case ID_CONNECT_REQ: return "ID_CONNECT_REQ";
   1212                 case ID_CONNECT_RESP: return "ID_CONNECT_RESP";
   1213                 case ID_DISCONNECT_REQ: return "ID_DISCONNECT_REQ";
   1214                 case ID_DISCONNECT_RESP: return "ID_DISCONNECT_RESP";
   1215                 case ID_DISCONNECT_IND: return "ID_DISCONNECT_IND";
   1216                 case ID_TRANSFER_APDU_REQ: return "ID_TRANSFER_APDU_REQ";
   1217                 case ID_TRANSFER_APDU_RESP: return "ID_TRANSFER_APDU_RESP";
   1218                 case ID_TRANSFER_ATR_REQ: return "ID_TRANSFER_ATR_REQ";
   1219                 case ID_TRANSFER_ATR_RESP: return "ID_TRANSFER_ATR_RESP";
   1220                 case ID_POWER_SIM_OFF_REQ: return "ID_POWER_SIM_OFF_REQ";
   1221                 case ID_POWER_SIM_OFF_RESP: return "ID_POWER_SIM_OFF_RESP";
   1222                 case ID_POWER_SIM_ON_REQ: return "ID_POWER_SIM_ON_REQ";
   1223                 case ID_POWER_SIM_ON_RESP: return "ID_POWER_SIM_ON_RESP";
   1224                 case ID_RESET_SIM_REQ: return "ID_RESET_SIM_REQ";
   1225                 case ID_RESET_SIM_RESP: return "ID_RESET_SIM_RESP";
   1226                 case ID_TRANSFER_CARD_READER_STATUS_REQ:
   1227                     return "ID_TRANSFER_CARD_READER_STATUS_REQ";
   1228                 case ID_TRANSFER_CARD_READER_STATUS_RESP:
   1229                     return "ID_TRANSFER_CARD_READER_STATUS_RESP";
   1230                 case ID_STATUS_IND: return "ID_STATUS_IND";
   1231                 case ID_ERROR_RESP: return "ID_ERROR_RESP";
   1232                 case ID_SET_TRANSPORT_PROTOCOL_REQ: return "ID_SET_TRANSPORT_PROTOCOL_REQ";
   1233                 case ID_SET_TRANSPORT_PROTOCOL_RESP: return "ID_SET_TRANSPORT_PROTOCOL_RESP";
   1234                 case ID_RIL_UNSOL_CONNECTED: return "ID_RIL_UNSOL_CONNECTED";
   1235                 case ID_RIL_UNKNOWN: return "ID_RIL_UNKNOWN";
   1236                 case ID_RIL_GET_SIM_STATUS_REQ: return "ID_RIL_GET_SIM_STATUS_REQ";
   1237                 case ID_RIL_SIM_ACCESS_TEST_REQ: return "ID_RIL_SIM_ACCESS_TEST_REQ";
   1238                 case ID_RIL_SIM_ACCESS_TEST_RESP: return "ID_RIL_SIM_ACCESS_TEST_RESP";
   1239                 default: return "Unknown Message Type (" + msgType + ")";
   1240             }
   1241         } else {
   1242             return null;
   1243         }
   1244     }
   1245 }
   1246