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