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