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