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