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