Home | History | Annotate | Download | only in cat
      1 /*
      2  * Copyright (C) 2007 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.internal.telephony.cat;
     18 
     19 import android.graphics.Bitmap;
     20 import android.os.Handler;
     21 import android.os.Message;
     22 
     23 import com.android.internal.telephony.GsmAlphabet;
     24 import com.android.internal.telephony.IccFileHandler;
     25 
     26 import java.util.Iterator;
     27 import java.util.List;
     28 
     29 /**
     30  * Factory class, used for decoding raw byte arrays, received from baseband,
     31  * into a CommandParams object.
     32  *
     33  */
     34 class CommandParamsFactory extends Handler {
     35     private static CommandParamsFactory sInstance = null;
     36     private IconLoader mIconLoader;
     37     private CommandParams mCmdParams = null;
     38     private int mIconLoadState = LOAD_NO_ICON;
     39     private RilMessageDecoder mCaller = null;
     40 
     41     // constants
     42     static final int MSG_ID_LOAD_ICON_DONE = 1;
     43 
     44     // loading icons state parameters.
     45     static final int LOAD_NO_ICON           = 0;
     46     static final int LOAD_SINGLE_ICON       = 1;
     47     static final int LOAD_MULTI_ICONS       = 2;
     48 
     49     // Command Qualifier values for refresh command
     50     static final int REFRESH_NAA_INIT_AND_FULL_FILE_CHANGE  = 0x00;
     51     static final int REFRESH_NAA_INIT_AND_FILE_CHANGE       = 0x02;
     52     static final int REFRESH_NAA_INIT                       = 0x03;
     53     static final int REFRESH_UICC_RESET                     = 0x04;
     54 
     55     // Command Qualifier values for PLI command
     56     static final int DTTZ_SETTING                           = 0x03;
     57     static final int LANGUAGE_SETTING                       = 0x04;
     58 
     59     static synchronized CommandParamsFactory getInstance(RilMessageDecoder caller,
     60             IccFileHandler fh) {
     61         if (sInstance != null) {
     62             return sInstance;
     63         }
     64         if (fh != null) {
     65             return new CommandParamsFactory(caller, fh);
     66         }
     67         return null;
     68     }
     69 
     70     private CommandParamsFactory(RilMessageDecoder caller, IccFileHandler fh) {
     71         mCaller = caller;
     72         mIconLoader = IconLoader.getInstance(this, fh);
     73     }
     74 
     75     private CommandDetails processCommandDetails(List<ComprehensionTlv> ctlvs) {
     76         CommandDetails cmdDet = null;
     77 
     78         if (ctlvs != null) {
     79             // Search for the Command Details object.
     80             ComprehensionTlv ctlvCmdDet = searchForTag(
     81                     ComprehensionTlvTag.COMMAND_DETAILS, ctlvs);
     82             if (ctlvCmdDet != null) {
     83                 try {
     84                     cmdDet = ValueParser.retrieveCommandDetails(ctlvCmdDet);
     85                 } catch (ResultException e) {
     86                     CatLog.d(this,
     87                             "processCommandDetails: Failed to procees command details e=" + e);
     88                 }
     89             }
     90         }
     91         return cmdDet;
     92     }
     93 
     94     void make(BerTlv berTlv) {
     95         if (berTlv == null) {
     96             return;
     97         }
     98         // reset global state parameters.
     99         mCmdParams = null;
    100         mIconLoadState = LOAD_NO_ICON;
    101         // only proactive command messages are processed.
    102         if (berTlv.getTag() != BerTlv.BER_PROACTIVE_COMMAND_TAG) {
    103             sendCmdParams(ResultCode.CMD_TYPE_NOT_UNDERSTOOD);
    104             return;
    105         }
    106         boolean cmdPending = false;
    107         List<ComprehensionTlv> ctlvs = berTlv.getComprehensionTlvs();
    108         // process command dtails from the tlv list.
    109         CommandDetails cmdDet = processCommandDetails(ctlvs);
    110         if (cmdDet == null) {
    111             sendCmdParams(ResultCode.CMD_TYPE_NOT_UNDERSTOOD);
    112             return;
    113         }
    114 
    115         // extract command type enumeration from the raw value stored inside
    116         // the Command Details object.
    117         AppInterface.CommandType cmdType = AppInterface.CommandType
    118                 .fromInt(cmdDet.typeOfCommand);
    119         if (cmdType == null) {
    120             // This PROACTIVE COMMAND is presently not handled. Hence set
    121             // result code as BEYOND_TERMINAL_CAPABILITY in TR.
    122             mCmdParams = new CommandParams(cmdDet);
    123             sendCmdParams(ResultCode.BEYOND_TERMINAL_CAPABILITY);
    124             return;
    125         }
    126 
    127         try {
    128             switch (cmdType) {
    129             case SET_UP_MENU:
    130                 cmdPending = processSelectItem(cmdDet, ctlvs);
    131                 break;
    132             case SELECT_ITEM:
    133                 cmdPending = processSelectItem(cmdDet, ctlvs);
    134                 break;
    135             case DISPLAY_TEXT:
    136                 cmdPending = processDisplayText(cmdDet, ctlvs);
    137                 break;
    138              case SET_UP_IDLE_MODE_TEXT:
    139                  cmdPending = processSetUpIdleModeText(cmdDet, ctlvs);
    140                  break;
    141              case GET_INKEY:
    142                 cmdPending = processGetInkey(cmdDet, ctlvs);
    143                 break;
    144              case GET_INPUT:
    145                  cmdPending = processGetInput(cmdDet, ctlvs);
    146                  break;
    147              case SEND_DTMF:
    148              case SEND_SMS:
    149              case SEND_SS:
    150              case SEND_USSD:
    151                  cmdPending = processEventNotify(cmdDet, ctlvs);
    152                  break;
    153              case SET_UP_CALL:
    154                  cmdPending = processSetupCall(cmdDet, ctlvs);
    155                  break;
    156              case REFRESH:
    157                 processRefresh(cmdDet, ctlvs);
    158                 cmdPending = false;
    159                 break;
    160              case LAUNCH_BROWSER:
    161                  cmdPending = processLaunchBrowser(cmdDet, ctlvs);
    162                  break;
    163              case PLAY_TONE:
    164                 cmdPending = processPlayTone(cmdDet, ctlvs);
    165                 break;
    166              case PROVIDE_LOCAL_INFORMATION:
    167                 cmdPending = processProvideLocalInfo(cmdDet, ctlvs);
    168                 break;
    169              case OPEN_CHANNEL:
    170              case CLOSE_CHANNEL:
    171              case RECEIVE_DATA:
    172              case SEND_DATA:
    173                  cmdPending = processBIPClient(cmdDet, ctlvs);
    174                  break;
    175             default:
    176                 // unsupported proactive commands
    177                 mCmdParams = new CommandParams(cmdDet);
    178                 sendCmdParams(ResultCode.BEYOND_TERMINAL_CAPABILITY);
    179                 return;
    180             }
    181         } catch (ResultException e) {
    182             CatLog.d(this, "make: caught ResultException e=" + e);
    183             mCmdParams = new CommandParams(cmdDet);
    184             sendCmdParams(e.result());
    185             return;
    186         }
    187         if (!cmdPending) {
    188             sendCmdParams(ResultCode.OK);
    189         }
    190     }
    191 
    192     @Override
    193     public void handleMessage(Message msg) {
    194         switch (msg.what) {
    195         case MSG_ID_LOAD_ICON_DONE:
    196             sendCmdParams(setIcons(msg.obj));
    197             break;
    198         }
    199     }
    200 
    201     private ResultCode setIcons(Object data) {
    202         Bitmap[] icons = null;
    203         int iconIndex = 0;
    204 
    205         if (data == null) {
    206             return ResultCode.PRFRMD_ICON_NOT_DISPLAYED;
    207         }
    208         switch(mIconLoadState) {
    209         case LOAD_SINGLE_ICON:
    210             mCmdParams.setIcon((Bitmap) data);
    211             break;
    212         case LOAD_MULTI_ICONS:
    213             icons = (Bitmap[]) data;
    214             // set each item icon.
    215             for (Bitmap icon : icons) {
    216                 mCmdParams.setIcon(icon);
    217             }
    218             break;
    219         }
    220         return ResultCode.OK;
    221     }
    222 
    223     private void sendCmdParams(ResultCode resCode) {
    224         mCaller.sendMsgParamsDecoded(resCode, mCmdParams);
    225     }
    226 
    227     /**
    228      * Search for a COMPREHENSION-TLV object with the given tag from a list
    229      *
    230      * @param tag A tag to search for
    231      * @param ctlvs List of ComprehensionTlv objects used to search in
    232      *
    233      * @return A ComprehensionTlv object that has the tag value of {@code tag}.
    234      *         If no object is found with the tag, null is returned.
    235      */
    236     private ComprehensionTlv searchForTag(ComprehensionTlvTag tag,
    237             List<ComprehensionTlv> ctlvs) {
    238         Iterator<ComprehensionTlv> iter = ctlvs.iterator();
    239         return searchForNextTag(tag, iter);
    240     }
    241 
    242     /**
    243      * Search for the next COMPREHENSION-TLV object with the given tag from a
    244      * list iterated by {@code iter}. {@code iter} points to the object next to
    245      * the found object when this method returns. Used for searching the same
    246      * list for similar tags, usually item id.
    247      *
    248      * @param tag A tag to search for
    249      * @param iter Iterator for ComprehensionTlv objects used for search
    250      *
    251      * @return A ComprehensionTlv object that has the tag value of {@code tag}.
    252      *         If no object is found with the tag, null is returned.
    253      */
    254     private ComprehensionTlv searchForNextTag(ComprehensionTlvTag tag,
    255             Iterator<ComprehensionTlv> iter) {
    256         int tagValue = tag.value();
    257         while (iter.hasNext()) {
    258             ComprehensionTlv ctlv = iter.next();
    259             if (ctlv.getTag() == tagValue) {
    260                 return ctlv;
    261             }
    262         }
    263         return null;
    264     }
    265 
    266     /**
    267      * Processes DISPLAY_TEXT proactive command from the SIM card.
    268      *
    269      * @param cmdDet Command Details container object.
    270      * @param ctlvs List of ComprehensionTlv objects following Command Details
    271      *        object and Device Identities object within the proactive command
    272      * @return true if the command is processing is pending and additional
    273      *         asynchronous processing is required.
    274      * @throws ResultException
    275      */
    276     private boolean processDisplayText(CommandDetails cmdDet,
    277             List<ComprehensionTlv> ctlvs)
    278             throws ResultException {
    279 
    280         CatLog.d(this, "process DisplayText");
    281 
    282         TextMessage textMsg = new TextMessage();
    283         IconId iconId = null;
    284 
    285         ComprehensionTlv ctlv = searchForTag(ComprehensionTlvTag.TEXT_STRING,
    286                 ctlvs);
    287         if (ctlv != null) {
    288             textMsg.text = ValueParser.retrieveTextString(ctlv);
    289         }
    290         // If the tlv object doesn't exist or the it is a null object reply
    291         // with command not understood.
    292         if (textMsg.text == null) {
    293             throw new ResultException(ResultCode.CMD_DATA_NOT_UNDERSTOOD);
    294         }
    295 
    296         ctlv = searchForTag(ComprehensionTlvTag.IMMEDIATE_RESPONSE, ctlvs);
    297         if (ctlv != null) {
    298             textMsg.responseNeeded = false;
    299         }
    300         // parse icon identifier
    301         ctlv = searchForTag(ComprehensionTlvTag.ICON_ID, ctlvs);
    302         if (ctlv != null) {
    303             iconId = ValueParser.retrieveIconId(ctlv);
    304             textMsg.iconSelfExplanatory = iconId.selfExplanatory;
    305         }
    306         // parse tone duration
    307         ctlv = searchForTag(ComprehensionTlvTag.DURATION, ctlvs);
    308         if (ctlv != null) {
    309             textMsg.duration = ValueParser.retrieveDuration(ctlv);
    310         }
    311 
    312         // Parse command qualifier parameters.
    313         textMsg.isHighPriority = (cmdDet.commandQualifier & 0x01) != 0;
    314         textMsg.userClear = (cmdDet.commandQualifier & 0x80) != 0;
    315 
    316         mCmdParams = new DisplayTextParams(cmdDet, textMsg);
    317 
    318         if (iconId != null) {
    319             mIconLoadState = LOAD_SINGLE_ICON;
    320             mIconLoader.loadIcon(iconId.recordNumber, this
    321                     .obtainMessage(MSG_ID_LOAD_ICON_DONE));
    322             return true;
    323         }
    324         return false;
    325     }
    326 
    327     /**
    328      * Processes SET_UP_IDLE_MODE_TEXT proactive command from the SIM card.
    329      *
    330      * @param cmdDet Command Details container object.
    331      * @param ctlvs List of ComprehensionTlv objects following Command Details
    332      *        object and Device Identities object within the proactive command
    333      * @return true if the command is processing is pending and additional
    334      *         asynchronous processing is required.
    335      * @throws ResultException
    336      */
    337     private boolean processSetUpIdleModeText(CommandDetails cmdDet,
    338             List<ComprehensionTlv> ctlvs) throws ResultException {
    339 
    340         CatLog.d(this, "process SetUpIdleModeText");
    341 
    342         TextMessage textMsg = new TextMessage();
    343         IconId iconId = null;
    344 
    345         ComprehensionTlv ctlv = searchForTag(ComprehensionTlvTag.TEXT_STRING,
    346                 ctlvs);
    347         if (ctlv != null) {
    348             textMsg.text = ValueParser.retrieveTextString(ctlv);
    349         }
    350         // load icons only when text exist.
    351         if (textMsg.text != null) {
    352             ctlv = searchForTag(ComprehensionTlvTag.ICON_ID, ctlvs);
    353             if (ctlv != null) {
    354                 iconId = ValueParser.retrieveIconId(ctlv);
    355                 textMsg.iconSelfExplanatory = iconId.selfExplanatory;
    356             }
    357         }
    358 
    359         mCmdParams = new DisplayTextParams(cmdDet, textMsg);
    360 
    361         if (iconId != null) {
    362             mIconLoadState = LOAD_SINGLE_ICON;
    363             mIconLoader.loadIcon(iconId.recordNumber, this
    364                     .obtainMessage(MSG_ID_LOAD_ICON_DONE));
    365             return true;
    366         }
    367         return false;
    368     }
    369 
    370     /**
    371      * Processes GET_INKEY proactive command from the SIM card.
    372      *
    373      * @param cmdDet Command Details container object.
    374      * @param ctlvs List of ComprehensionTlv objects following Command Details
    375      *        object and Device Identities object within the proactive command
    376      * @return true if the command is processing is pending and additional
    377      *         asynchronous processing is required.
    378      * @throws ResultException
    379      */
    380     private boolean processGetInkey(CommandDetails cmdDet,
    381             List<ComprehensionTlv> ctlvs) throws ResultException {
    382 
    383         CatLog.d(this, "process GetInkey");
    384 
    385         Input input = new Input();
    386         IconId iconId = null;
    387 
    388         ComprehensionTlv ctlv = searchForTag(ComprehensionTlvTag.TEXT_STRING,
    389                 ctlvs);
    390         if (ctlv != null) {
    391             input.text = ValueParser.retrieveTextString(ctlv);
    392         } else {
    393             throw new ResultException(ResultCode.REQUIRED_VALUES_MISSING);
    394         }
    395         // parse icon identifier
    396         ctlv = searchForTag(ComprehensionTlvTag.ICON_ID, ctlvs);
    397         if (ctlv != null) {
    398             iconId = ValueParser.retrieveIconId(ctlv);
    399         }
    400 
    401         // parse duration
    402         ctlv = searchForTag(ComprehensionTlvTag.DURATION, ctlvs);
    403         if (ctlv != null) {
    404             input.duration = ValueParser.retrieveDuration(ctlv);
    405         }
    406 
    407         input.minLen = 1;
    408         input.maxLen = 1;
    409 
    410         input.digitOnly = (cmdDet.commandQualifier & 0x01) == 0;
    411         input.ucs2 = (cmdDet.commandQualifier & 0x02) != 0;
    412         input.yesNo = (cmdDet.commandQualifier & 0x04) != 0;
    413         input.helpAvailable = (cmdDet.commandQualifier & 0x80) != 0;
    414         input.echo = true;
    415 
    416         mCmdParams = new GetInputParams(cmdDet, input);
    417 
    418         if (iconId != null) {
    419             mIconLoadState = LOAD_SINGLE_ICON;
    420             mIconLoader.loadIcon(iconId.recordNumber, this
    421                     .obtainMessage(MSG_ID_LOAD_ICON_DONE));
    422             return true;
    423         }
    424         return false;
    425     }
    426 
    427     /**
    428      * Processes GET_INPUT proactive command from the SIM card.
    429      *
    430      * @param cmdDet Command Details container object.
    431      * @param ctlvs List of ComprehensionTlv objects following Command Details
    432      *        object and Device Identities object within the proactive command
    433      * @return true if the command is processing is pending and additional
    434      *         asynchronous processing is required.
    435      * @throws ResultException
    436      */
    437     private boolean processGetInput(CommandDetails cmdDet,
    438             List<ComprehensionTlv> ctlvs) throws ResultException {
    439 
    440         CatLog.d(this, "process GetInput");
    441 
    442         Input input = new Input();
    443         IconId iconId = null;
    444 
    445         ComprehensionTlv ctlv = searchForTag(ComprehensionTlvTag.TEXT_STRING,
    446                 ctlvs);
    447         if (ctlv != null) {
    448             input.text = ValueParser.retrieveTextString(ctlv);
    449         } else {
    450             throw new ResultException(ResultCode.REQUIRED_VALUES_MISSING);
    451         }
    452 
    453         ctlv = searchForTag(ComprehensionTlvTag.RESPONSE_LENGTH, ctlvs);
    454         if (ctlv != null) {
    455             try {
    456                 byte[] rawValue = ctlv.getRawValue();
    457                 int valueIndex = ctlv.getValueIndex();
    458                 input.minLen = rawValue[valueIndex] & 0xff;
    459                 input.maxLen = rawValue[valueIndex + 1] & 0xff;
    460             } catch (IndexOutOfBoundsException e) {
    461                 throw new ResultException(ResultCode.CMD_DATA_NOT_UNDERSTOOD);
    462             }
    463         } else {
    464             throw new ResultException(ResultCode.REQUIRED_VALUES_MISSING);
    465         }
    466 
    467         ctlv = searchForTag(ComprehensionTlvTag.DEFAULT_TEXT, ctlvs);
    468         if (ctlv != null) {
    469             input.defaultText = ValueParser.retrieveTextString(ctlv);
    470         }
    471         // parse icon identifier
    472         ctlv = searchForTag(ComprehensionTlvTag.ICON_ID, ctlvs);
    473         if (ctlv != null) {
    474             iconId = ValueParser.retrieveIconId(ctlv);
    475         }
    476 
    477         input.digitOnly = (cmdDet.commandQualifier & 0x01) == 0;
    478         input.ucs2 = (cmdDet.commandQualifier & 0x02) != 0;
    479         input.echo = (cmdDet.commandQualifier & 0x04) == 0;
    480         input.packed = (cmdDet.commandQualifier & 0x08) != 0;
    481         input.helpAvailable = (cmdDet.commandQualifier & 0x80) != 0;
    482 
    483         mCmdParams = new GetInputParams(cmdDet, input);
    484 
    485         if (iconId != null) {
    486             mIconLoadState = LOAD_SINGLE_ICON;
    487             mIconLoader.loadIcon(iconId.recordNumber, this
    488                     .obtainMessage(MSG_ID_LOAD_ICON_DONE));
    489             return true;
    490         }
    491         return false;
    492     }
    493 
    494     /**
    495      * Processes REFRESH proactive command from the SIM card.
    496      *
    497      * @param cmdDet Command Details container object.
    498      * @param ctlvs List of ComprehensionTlv objects following Command Details
    499      *        object and Device Identities object within the proactive command
    500      */
    501     private boolean processRefresh(CommandDetails cmdDet,
    502             List<ComprehensionTlv> ctlvs) {
    503 
    504         CatLog.d(this, "process Refresh");
    505 
    506         // REFRESH proactive command is rerouted by the baseband and handled by
    507         // the telephony layer. IDLE TEXT should be removed for a REFRESH command
    508         // with "initialization" or "reset"
    509         switch (cmdDet.commandQualifier) {
    510         case REFRESH_NAA_INIT_AND_FULL_FILE_CHANGE:
    511         case REFRESH_NAA_INIT_AND_FILE_CHANGE:
    512         case REFRESH_NAA_INIT:
    513         case REFRESH_UICC_RESET:
    514             mCmdParams = new DisplayTextParams(cmdDet, null);
    515             break;
    516         }
    517         return false;
    518     }
    519 
    520     /**
    521      * Processes SELECT_ITEM proactive command from the SIM card.
    522      *
    523      * @param cmdDet Command Details container object.
    524      * @param ctlvs List of ComprehensionTlv objects following Command Details
    525      *        object and Device Identities object within the proactive command
    526      * @return true if the command is processing is pending and additional
    527      *         asynchronous processing is required.
    528      * @throws ResultException
    529      */
    530     private boolean processSelectItem(CommandDetails cmdDet,
    531             List<ComprehensionTlv> ctlvs) throws ResultException {
    532 
    533         CatLog.d(this, "process SelectItem");
    534 
    535         Menu menu = new Menu();
    536         IconId titleIconId = null;
    537         ItemsIconId itemsIconId = null;
    538         Iterator<ComprehensionTlv> iter = ctlvs.iterator();
    539 
    540         ComprehensionTlv ctlv = searchForTag(ComprehensionTlvTag.ALPHA_ID,
    541                 ctlvs);
    542         if (ctlv != null) {
    543             menu.title = ValueParser.retrieveAlphaId(ctlv);
    544         }
    545 
    546         while (true) {
    547             ctlv = searchForNextTag(ComprehensionTlvTag.ITEM, iter);
    548             if (ctlv != null) {
    549                 menu.items.add(ValueParser.retrieveItem(ctlv));
    550             } else {
    551                 break;
    552             }
    553         }
    554 
    555         // We must have at least one menu item.
    556         if (menu.items.size() == 0) {
    557             throw new ResultException(ResultCode.REQUIRED_VALUES_MISSING);
    558         }
    559 
    560         ctlv = searchForTag(ComprehensionTlvTag.ITEM_ID, ctlvs);
    561         if (ctlv != null) {
    562             // CAT items are listed 1...n while list start at 0, need to
    563             // subtract one.
    564             menu.defaultItem = ValueParser.retrieveItemId(ctlv) - 1;
    565         }
    566 
    567         ctlv = searchForTag(ComprehensionTlvTag.ICON_ID, ctlvs);
    568         if (ctlv != null) {
    569             mIconLoadState = LOAD_SINGLE_ICON;
    570             titleIconId = ValueParser.retrieveIconId(ctlv);
    571             menu.titleIconSelfExplanatory = titleIconId.selfExplanatory;
    572         }
    573 
    574         ctlv = searchForTag(ComprehensionTlvTag.ITEM_ICON_ID_LIST, ctlvs);
    575         if (ctlv != null) {
    576             mIconLoadState = LOAD_MULTI_ICONS;
    577             itemsIconId = ValueParser.retrieveItemsIconId(ctlv);
    578             menu.itemsIconSelfExplanatory = itemsIconId.selfExplanatory;
    579         }
    580 
    581         boolean presentTypeSpecified = (cmdDet.commandQualifier & 0x01) != 0;
    582         if (presentTypeSpecified) {
    583             if ((cmdDet.commandQualifier & 0x02) == 0) {
    584                 menu.presentationType = PresentationType.DATA_VALUES;
    585             } else {
    586                 menu.presentationType = PresentationType.NAVIGATION_OPTIONS;
    587             }
    588         }
    589         menu.softKeyPreferred = (cmdDet.commandQualifier & 0x04) != 0;
    590         menu.helpAvailable = (cmdDet.commandQualifier & 0x80) != 0;
    591 
    592         mCmdParams = new SelectItemParams(cmdDet, menu, titleIconId != null);
    593 
    594         // Load icons data if needed.
    595         switch(mIconLoadState) {
    596         case LOAD_NO_ICON:
    597             return false;
    598         case LOAD_SINGLE_ICON:
    599             mIconLoader.loadIcon(titleIconId.recordNumber, this
    600                     .obtainMessage(MSG_ID_LOAD_ICON_DONE));
    601             break;
    602         case LOAD_MULTI_ICONS:
    603             int[] recordNumbers = itemsIconId.recordNumbers;
    604             if (titleIconId != null) {
    605                 // Create a new array for all the icons (title and items).
    606                 recordNumbers = new int[itemsIconId.recordNumbers.length + 1];
    607                 recordNumbers[0] = titleIconId.recordNumber;
    608                 System.arraycopy(itemsIconId.recordNumbers, 0, recordNumbers,
    609                         1, itemsIconId.recordNumbers.length);
    610             }
    611             mIconLoader.loadIcons(recordNumbers, this
    612                     .obtainMessage(MSG_ID_LOAD_ICON_DONE));
    613             break;
    614         }
    615         return true;
    616     }
    617 
    618     /**
    619      * Processes EVENT_NOTIFY message from baseband.
    620      *
    621      * @param cmdDet Command Details container object.
    622      * @param ctlvs List of ComprehensionTlv objects following Command Details
    623      *        object and Device Identities object within the proactive command
    624      * @return true if the command is processing is pending and additional
    625      *         asynchronous processing is required.
    626      */
    627     private boolean processEventNotify(CommandDetails cmdDet,
    628             List<ComprehensionTlv> ctlvs) throws ResultException {
    629 
    630         CatLog.d(this, "process EventNotify");
    631 
    632         TextMessage textMsg = new TextMessage();
    633         IconId iconId = null;
    634 
    635         ComprehensionTlv ctlv = searchForTag(ComprehensionTlvTag.ALPHA_ID,
    636                 ctlvs);
    637         textMsg.text = ValueParser.retrieveAlphaId(ctlv);
    638 
    639         ctlv = searchForTag(ComprehensionTlvTag.ICON_ID, ctlvs);
    640         if (ctlv != null) {
    641             iconId = ValueParser.retrieveIconId(ctlv);
    642             textMsg.iconSelfExplanatory = iconId.selfExplanatory;
    643         }
    644 
    645         textMsg.responseNeeded = false;
    646         mCmdParams = new DisplayTextParams(cmdDet, textMsg);
    647 
    648         if (iconId != null) {
    649             mIconLoadState = LOAD_SINGLE_ICON;
    650             mIconLoader.loadIcon(iconId.recordNumber, this
    651                     .obtainMessage(MSG_ID_LOAD_ICON_DONE));
    652             return true;
    653         }
    654         return false;
    655     }
    656 
    657     /**
    658      * Processes SET_UP_EVENT_LIST proactive command from the SIM card.
    659      *
    660      * @param cmdDet Command Details object retrieved.
    661      * @param ctlvs List of ComprehensionTlv objects following Command Details
    662      *        object and Device Identities object within the proactive command
    663      * @return true if the command is processing is pending and additional
    664      *         asynchronous processing is required.
    665      */
    666     private boolean processSetUpEventList(CommandDetails cmdDet,
    667             List<ComprehensionTlv> ctlvs) {
    668 
    669         CatLog.d(this, "process SetUpEventList");
    670         //
    671         // ComprehensionTlv ctlv = searchForTag(ComprehensionTlvTag.EVENT_LIST,
    672         // ctlvs);
    673         // if (ctlv != null) {
    674         // try {
    675         // byte[] rawValue = ctlv.getRawValue();
    676         // int valueIndex = ctlv.getValueIndex();
    677         // int valueLen = ctlv.getLength();
    678         //
    679         // } catch (IndexOutOfBoundsException e) {}
    680         // }
    681         return true;
    682     }
    683 
    684     /**
    685      * Processes LAUNCH_BROWSER proactive command from the SIM card.
    686      *
    687      * @param cmdDet Command Details container object.
    688      * @param ctlvs List of ComprehensionTlv objects following Command Details
    689      *        object and Device Identities object within the proactive command
    690      * @return true if the command is processing is pending and additional
    691      *         asynchronous processing is required.
    692      * @throws ResultException
    693      */
    694     private boolean processLaunchBrowser(CommandDetails cmdDet,
    695             List<ComprehensionTlv> ctlvs) throws ResultException {
    696 
    697         CatLog.d(this, "process LaunchBrowser");
    698 
    699         TextMessage confirmMsg = new TextMessage();
    700         IconId iconId = null;
    701         String url = null;
    702 
    703         ComprehensionTlv ctlv = searchForTag(ComprehensionTlvTag.URL, ctlvs);
    704         if (ctlv != null) {
    705             try {
    706                 byte[] rawValue = ctlv.getRawValue();
    707                 int valueIndex = ctlv.getValueIndex();
    708                 int valueLen = ctlv.getLength();
    709                 if (valueLen > 0) {
    710                     url = GsmAlphabet.gsm8BitUnpackedToString(rawValue,
    711                             valueIndex, valueLen);
    712                 } else {
    713                     url = null;
    714                 }
    715             } catch (IndexOutOfBoundsException e) {
    716                 throw new ResultException(ResultCode.CMD_DATA_NOT_UNDERSTOOD);
    717             }
    718         }
    719 
    720         // parse alpha identifier.
    721         ctlv = searchForTag(ComprehensionTlvTag.ALPHA_ID, ctlvs);
    722         confirmMsg.text = ValueParser.retrieveAlphaId(ctlv);
    723 
    724         // parse icon identifier
    725         ctlv = searchForTag(ComprehensionTlvTag.ICON_ID, ctlvs);
    726         if (ctlv != null) {
    727             iconId = ValueParser.retrieveIconId(ctlv);
    728             confirmMsg.iconSelfExplanatory = iconId.selfExplanatory;
    729         }
    730 
    731         // parse command qualifier value.
    732         LaunchBrowserMode mode;
    733         switch (cmdDet.commandQualifier) {
    734         case 0x00:
    735         default:
    736             mode = LaunchBrowserMode.LAUNCH_IF_NOT_ALREADY_LAUNCHED;
    737             break;
    738         case 0x02:
    739             mode = LaunchBrowserMode.USE_EXISTING_BROWSER;
    740             break;
    741         case 0x03:
    742             mode = LaunchBrowserMode.LAUNCH_NEW_BROWSER;
    743             break;
    744         }
    745 
    746         mCmdParams = new LaunchBrowserParams(cmdDet, confirmMsg, url, mode);
    747 
    748         if (iconId != null) {
    749             mIconLoadState = LOAD_SINGLE_ICON;
    750             mIconLoader.loadIcon(iconId.recordNumber, this
    751                     .obtainMessage(MSG_ID_LOAD_ICON_DONE));
    752             return true;
    753         }
    754         return false;
    755     }
    756 
    757      /**
    758      * Processes PLAY_TONE proactive command from the SIM card.
    759      *
    760      * @param cmdDet Command Details container object.
    761      * @param ctlvs List of ComprehensionTlv objects following Command Details
    762      *        object and Device Identities object within the proactive command
    763      * @return true if the command is processing is pending and additional
    764      *         asynchronous processing is required.t
    765      * @throws ResultException
    766      */
    767     private boolean processPlayTone(CommandDetails cmdDet,
    768             List<ComprehensionTlv> ctlvs) throws ResultException {
    769 
    770         CatLog.d(this, "process PlayTone");
    771 
    772         Tone tone = null;
    773         TextMessage textMsg = new TextMessage();
    774         Duration duration = null;
    775         IconId iconId = null;
    776 
    777         ComprehensionTlv ctlv = searchForTag(ComprehensionTlvTag.TONE, ctlvs);
    778         if (ctlv != null) {
    779             // Nothing to do for null objects.
    780             if (ctlv.getLength() > 0) {
    781                 try {
    782                     byte[] rawValue = ctlv.getRawValue();
    783                     int valueIndex = ctlv.getValueIndex();
    784                     int toneVal = rawValue[valueIndex];
    785                     tone = Tone.fromInt(toneVal);
    786                 } catch (IndexOutOfBoundsException e) {
    787                     throw new ResultException(
    788                             ResultCode.CMD_DATA_NOT_UNDERSTOOD);
    789                 }
    790             }
    791         }
    792         // parse alpha identifier
    793         ctlv = searchForTag(ComprehensionTlvTag.ALPHA_ID, ctlvs);
    794         if (ctlv != null) {
    795             textMsg.text = ValueParser.retrieveAlphaId(ctlv);
    796         }
    797         // parse tone duration
    798         ctlv = searchForTag(ComprehensionTlvTag.DURATION, ctlvs);
    799         if (ctlv != null) {
    800             duration = ValueParser.retrieveDuration(ctlv);
    801         }
    802         // parse icon identifier
    803         ctlv = searchForTag(ComprehensionTlvTag.ICON_ID, ctlvs);
    804         if (ctlv != null) {
    805             iconId = ValueParser.retrieveIconId(ctlv);
    806             textMsg.iconSelfExplanatory = iconId.selfExplanatory;
    807         }
    808 
    809         boolean vibrate = (cmdDet.commandQualifier & 0x01) != 0x00;
    810 
    811         textMsg.responseNeeded = false;
    812         mCmdParams = new PlayToneParams(cmdDet, textMsg, tone, duration, vibrate);
    813 
    814         if (iconId != null) {
    815             mIconLoadState = LOAD_SINGLE_ICON;
    816             mIconLoader.loadIcon(iconId.recordNumber, this
    817                     .obtainMessage(MSG_ID_LOAD_ICON_DONE));
    818             return true;
    819         }
    820         return false;
    821     }
    822 
    823     /**
    824      * Processes SETUP_CALL proactive command from the SIM card.
    825      *
    826      * @param cmdDet Command Details object retrieved from the proactive command
    827      *        object
    828      * @param ctlvs List of ComprehensionTlv objects following Command Details
    829      *        object and Device Identities object within the proactive command
    830      * @return true if the command is processing is pending and additional
    831      *         asynchronous processing is required.
    832      */
    833     private boolean processSetupCall(CommandDetails cmdDet,
    834             List<ComprehensionTlv> ctlvs) throws ResultException {
    835         CatLog.d(this, "process SetupCall");
    836 
    837         Iterator<ComprehensionTlv> iter = ctlvs.iterator();
    838         ComprehensionTlv ctlv = null;
    839         // User confirmation phase message.
    840         TextMessage confirmMsg = new TextMessage();
    841         // Call set up phase message.
    842         TextMessage callMsg = new TextMessage();
    843         IconId confirmIconId = null;
    844         IconId callIconId = null;
    845 
    846         // get confirmation message string.
    847         ctlv = searchForNextTag(ComprehensionTlvTag.ALPHA_ID, iter);
    848         confirmMsg.text = ValueParser.retrieveAlphaId(ctlv);
    849 
    850         ctlv = searchForTag(ComprehensionTlvTag.ICON_ID, ctlvs);
    851         if (ctlv != null) {
    852             confirmIconId = ValueParser.retrieveIconId(ctlv);
    853             confirmMsg.iconSelfExplanatory = confirmIconId.selfExplanatory;
    854         }
    855 
    856         // get call set up message string.
    857         ctlv = searchForNextTag(ComprehensionTlvTag.ALPHA_ID, iter);
    858         if (ctlv != null) {
    859             callMsg.text = ValueParser.retrieveAlphaId(ctlv);
    860         }
    861 
    862         ctlv = searchForTag(ComprehensionTlvTag.ICON_ID, ctlvs);
    863         if (ctlv != null) {
    864             callIconId = ValueParser.retrieveIconId(ctlv);
    865             callMsg.iconSelfExplanatory = callIconId.selfExplanatory;
    866         }
    867 
    868         mCmdParams = new CallSetupParams(cmdDet, confirmMsg, callMsg);
    869 
    870         if (confirmIconId != null || callIconId != null) {
    871             mIconLoadState = LOAD_MULTI_ICONS;
    872             int[] recordNumbers = new int[2];
    873             recordNumbers[0] = confirmIconId != null
    874                     ? confirmIconId.recordNumber : -1;
    875             recordNumbers[1] = callIconId != null ? callIconId.recordNumber
    876                     : -1;
    877 
    878             mIconLoader.loadIcons(recordNumbers, this
    879                     .obtainMessage(MSG_ID_LOAD_ICON_DONE));
    880             return true;
    881         }
    882         return false;
    883     }
    884 
    885     private boolean processProvideLocalInfo(CommandDetails cmdDet, List<ComprehensionTlv> ctlvs)
    886             throws ResultException {
    887         CatLog.d(this, "process ProvideLocalInfo");
    888         switch (cmdDet.commandQualifier) {
    889             case DTTZ_SETTING:
    890                 CatLog.d(this, "PLI [DTTZ_SETTING]");
    891                 mCmdParams = new CommandParams(cmdDet);
    892                 break;
    893             case LANGUAGE_SETTING:
    894                 CatLog.d(this, "PLI [LANGUAGE_SETTING]");
    895                 mCmdParams = new CommandParams(cmdDet);
    896                 break;
    897             default:
    898                 CatLog.d(this, "PLI[" + cmdDet.commandQualifier + "] Command Not Supported");
    899                 mCmdParams = new CommandParams(cmdDet);
    900                 throw new ResultException(ResultCode.BEYOND_TERMINAL_CAPABILITY);
    901         }
    902         return false;
    903     }
    904 
    905     private boolean processBIPClient(CommandDetails cmdDet,
    906                                      List<ComprehensionTlv> ctlvs) throws ResultException {
    907         AppInterface.CommandType commandType =
    908                                     AppInterface.CommandType.fromInt(cmdDet.typeOfCommand);
    909         if (commandType != null) {
    910             CatLog.d(this, "process "+ commandType.name());
    911         }
    912 
    913         TextMessage textMsg = new TextMessage();
    914         IconId iconId = null;
    915         ComprehensionTlv ctlv = null;
    916         boolean has_alpha_id = false;
    917 
    918         // parse alpha identifier
    919         ctlv = searchForTag(ComprehensionTlvTag.ALPHA_ID, ctlvs);
    920         if (ctlv != null) {
    921             textMsg.text = ValueParser.retrieveAlphaId(ctlv);
    922             CatLog.d(this, "alpha TLV text=" + textMsg.text);
    923             has_alpha_id = true;
    924         }
    925 
    926         // parse icon identifier
    927         ctlv = searchForTag(ComprehensionTlvTag.ICON_ID, ctlvs);
    928         if (ctlv != null) {
    929             iconId = ValueParser.retrieveIconId(ctlv);
    930             textMsg.iconSelfExplanatory = iconId.selfExplanatory;
    931         }
    932 
    933         textMsg.responseNeeded = false;
    934         mCmdParams = new BIPClientParams(cmdDet, textMsg, has_alpha_id);
    935 
    936         if (iconId != null) {
    937             mIconLoadState = LOAD_SINGLE_ICON;
    938             mIconLoader.loadIcon(iconId.recordNumber, this.obtainMessage(MSG_ID_LOAD_ICON_DONE));
    939             return true;
    940         }
    941         return false;
    942     }
    943 }
    944