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