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