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