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