1 /* 2 * Copyright (C) 2006-2007 Google Inc. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 * use this file except in compliance with the License. You may obtain a copy of 6 * 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, WITHOUT 12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 * License for the specific language governing permissions and limitations under 14 * the License. 15 */ 16 17 package com.android.internal.telephony.cat; 18 19 import android.compat.annotation.UnsupportedAppUsage; 20 import android.os.Build; 21 import android.telephony.SmsMessage; 22 23 import com.android.internal.telephony.GsmAlphabet; 24 import com.android.internal.telephony.cat.Duration.TimeUnit; 25 import com.android.internal.telephony.uicc.IccUtils; 26 27 import java.io.ByteArrayOutputStream; 28 import java.io.UnsupportedEncodingException; 29 import java.util.ArrayList; 30 import java.util.Arrays; 31 import java.util.List; 32 33 34 /** 35 * Util class that parses different entities from the ctlvs ComprehensionTlv List 36 * @hide 37 */ 38 public abstract class ValueParser { 39 40 /** 41 * Search for a Command Details object from a list. 42 * 43 * @param ctlv List of ComprehensionTlv objects used for search 44 * @return An CtlvCommandDetails object found from the objects. If no 45 * Command Details object is found, ResultException is thrown. 46 * @throws ResultException 47 */ retrieveCommandDetails(ComprehensionTlv ctlv)48 static CommandDetails retrieveCommandDetails(ComprehensionTlv ctlv) 49 throws ResultException { 50 51 CommandDetails cmdDet = new CommandDetails(); 52 byte[] rawValue = ctlv.getRawValue(); 53 int valueIndex = ctlv.getValueIndex(); 54 try { 55 cmdDet.compRequired = ctlv.isComprehensionRequired(); 56 cmdDet.commandNumber = rawValue[valueIndex] & 0xff; 57 cmdDet.typeOfCommand = rawValue[valueIndex + 1] & 0xff; 58 cmdDet.commandQualifier = rawValue[valueIndex + 2] & 0xff; 59 return cmdDet; 60 } catch (IndexOutOfBoundsException e) { 61 throw new ResultException(ResultCode.CMD_DATA_NOT_UNDERSTOOD); 62 } 63 } 64 65 /** 66 * Search for a Device Identities object from a list. 67 * 68 * @param ctlv List of ComprehensionTlv objects used for search 69 * @return An CtlvDeviceIdentities object found from the objects. If no 70 * Command Details object is found, ResultException is thrown. 71 * @throws ResultException 72 */ 73 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) retrieveDeviceIdentities(ComprehensionTlv ctlv)74 static DeviceIdentities retrieveDeviceIdentities(ComprehensionTlv ctlv) 75 throws ResultException { 76 77 DeviceIdentities devIds = new DeviceIdentities(); 78 byte[] rawValue = ctlv.getRawValue(); 79 int valueIndex = ctlv.getValueIndex(); 80 try { 81 devIds.sourceId = rawValue[valueIndex] & 0xff; 82 devIds.destinationId = rawValue[valueIndex + 1] & 0xff; 83 return devIds; 84 } catch (IndexOutOfBoundsException e) { 85 throw new ResultException(ResultCode.REQUIRED_VALUES_MISSING); 86 } 87 } 88 89 /** 90 * Retrieves Duration information from the Duration COMPREHENSION-TLV 91 * object. 92 * 93 * @param ctlv A Text Attribute COMPREHENSION-TLV object 94 * @return A Duration object 95 * @throws ResultException 96 */ retrieveDuration(ComprehensionTlv ctlv)97 static Duration retrieveDuration(ComprehensionTlv ctlv) throws ResultException { 98 int timeInterval = 0; 99 TimeUnit timeUnit = TimeUnit.SECOND; 100 101 byte[] rawValue = ctlv.getRawValue(); 102 int valueIndex = ctlv.getValueIndex(); 103 104 try { 105 timeUnit = TimeUnit.values()[(rawValue[valueIndex] & 0xff)]; 106 timeInterval = rawValue[valueIndex + 1] & 0xff; 107 } catch (IndexOutOfBoundsException e) { 108 throw new ResultException(ResultCode.CMD_DATA_NOT_UNDERSTOOD); 109 } 110 return new Duration(timeInterval, timeUnit); 111 } 112 113 /** 114 * Retrieves Item information from the COMPREHENSION-TLV object. 115 * 116 * @param ctlv A Text Attribute COMPREHENSION-TLV object 117 * @return An Item 118 * @throws ResultException 119 */ retrieveItem(ComprehensionTlv ctlv)120 static Item retrieveItem(ComprehensionTlv ctlv) throws ResultException { 121 Item item = null; 122 123 byte[] rawValue = ctlv.getRawValue(); 124 int valueIndex = ctlv.getValueIndex(); 125 int length = ctlv.getLength(); 126 127 if (length != 0) { 128 int textLen = length - 1; 129 130 try { 131 int id = rawValue[valueIndex] & 0xff; 132 String text = IccUtils.adnStringFieldToString(rawValue, 133 valueIndex + 1, textLen); 134 item = new Item(id, text); 135 } catch (IndexOutOfBoundsException e) { 136 throw new ResultException(ResultCode.CMD_DATA_NOT_UNDERSTOOD); 137 } 138 } 139 140 return item; 141 } 142 143 /** 144 * Retrieves Item id information from the COMPREHENSION-TLV object. 145 * 146 * @param ctlv A Text Attribute COMPREHENSION-TLV object 147 * @return An Item id 148 * @throws ResultException 149 */ retrieveItemId(ComprehensionTlv ctlv)150 static int retrieveItemId(ComprehensionTlv ctlv) throws ResultException { 151 int id = 0; 152 153 byte[] rawValue = ctlv.getRawValue(); 154 int valueIndex = ctlv.getValueIndex(); 155 156 try { 157 id = rawValue[valueIndex] & 0xff; 158 } catch (IndexOutOfBoundsException e) { 159 throw new ResultException(ResultCode.CMD_DATA_NOT_UNDERSTOOD); 160 } 161 162 return id; 163 } 164 165 /** 166 * Retrieves icon id from an Icon Identifier COMPREHENSION-TLV object 167 * 168 * @param ctlv An Icon Identifier COMPREHENSION-TLV object 169 * @return IconId instance 170 * @throws ResultException 171 */ retrieveIconId(ComprehensionTlv ctlv)172 static IconId retrieveIconId(ComprehensionTlv ctlv) throws ResultException { 173 IconId id = new IconId(); 174 175 byte[] rawValue = ctlv.getRawValue(); 176 int valueIndex = ctlv.getValueIndex(); 177 try { 178 id.selfExplanatory = (rawValue[valueIndex++] & 0xff) == 0x00; 179 id.recordNumber = rawValue[valueIndex] & 0xff; 180 } catch (IndexOutOfBoundsException e) { 181 throw new ResultException(ResultCode.CMD_DATA_NOT_UNDERSTOOD); 182 } 183 184 return id; 185 } 186 187 /** 188 * Retrieves item icons id from an Icon Identifier List COMPREHENSION-TLV 189 * object 190 * 191 * @param ctlv An Item Icon List Identifier COMPREHENSION-TLV object 192 * @return ItemsIconId instance 193 * @throws ResultException 194 */ retrieveItemsIconId(ComprehensionTlv ctlv)195 static ItemsIconId retrieveItemsIconId(ComprehensionTlv ctlv) 196 throws ResultException { 197 CatLog.d("ValueParser", "retrieveItemsIconId:"); 198 ItemsIconId id = new ItemsIconId(); 199 200 byte[] rawValue = ctlv.getRawValue(); 201 int valueIndex = ctlv.getValueIndex(); 202 int numOfItems = ctlv.getLength() - 1; 203 id.recordNumbers = new int[numOfItems]; 204 205 try { 206 // get icon self-explanatory 207 id.selfExplanatory = (rawValue[valueIndex++] & 0xff) == 0x00; 208 209 for (int index = 0; index < numOfItems;) { 210 id.recordNumbers[index++] = rawValue[valueIndex++]; 211 } 212 } catch (IndexOutOfBoundsException e) { 213 throw new ResultException(ResultCode.CMD_DATA_NOT_UNDERSTOOD); 214 } 215 return id; 216 } 217 218 /** 219 * Retrieves text attribute information from the Text Attribute 220 * COMPREHENSION-TLV object. 221 * 222 * @param ctlv A Text Attribute COMPREHENSION-TLV object 223 * @return A list of TextAttribute objects 224 * @throws ResultException 225 */ 226 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) retrieveTextAttribute(ComprehensionTlv ctlv)227 static List<TextAttribute> retrieveTextAttribute(ComprehensionTlv ctlv) 228 throws ResultException { 229 ArrayList<TextAttribute> lst = new ArrayList<TextAttribute>(); 230 231 byte[] rawValue = ctlv.getRawValue(); 232 int valueIndex = ctlv.getValueIndex(); 233 int length = ctlv.getLength(); 234 235 if (length != 0) { 236 // Each attribute is consisted of four bytes 237 int itemCount = length / 4; 238 239 try { 240 for (int i = 0; i < itemCount; i++, valueIndex += 4) { 241 int start = rawValue[valueIndex] & 0xff; 242 int textLength = rawValue[valueIndex + 1] & 0xff; 243 int format = rawValue[valueIndex + 2] & 0xff; 244 int colorValue = rawValue[valueIndex + 3] & 0xff; 245 246 int alignValue = format & 0x03; 247 TextAlignment align = TextAlignment.fromInt(alignValue); 248 249 int sizeValue = (format >> 2) & 0x03; 250 FontSize size = FontSize.fromInt(sizeValue); 251 if (size == null) { 252 // Font size value is not defined. Use default. 253 size = FontSize.NORMAL; 254 } 255 256 boolean bold = (format & 0x10) != 0; 257 boolean italic = (format & 0x20) != 0; 258 boolean underlined = (format & 0x40) != 0; 259 boolean strikeThrough = (format & 0x80) != 0; 260 261 TextColor color = TextColor.fromInt(colorValue); 262 263 TextAttribute attr = new TextAttribute(start, textLength, 264 align, size, bold, italic, underlined, 265 strikeThrough, color); 266 lst.add(attr); 267 } 268 269 return lst; 270 271 } catch (IndexOutOfBoundsException e) { 272 throw new ResultException(ResultCode.CMD_DATA_NOT_UNDERSTOOD); 273 } 274 } 275 return null; 276 } 277 278 279 /** 280 * Retrieves alpha identifier from an Alpha Identifier COMPREHENSION-TLV 281 * object. 282 * 283 * @param ctlv An Alpha Identifier COMPREHENSION-TLV object 284 * @return String corresponding to the alpha identifier 285 * @throws ResultException 286 */ 287 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) retrieveAlphaId(ComprehensionTlv ctlv, boolean noAlphaUsrCnf)288 static String retrieveAlphaId(ComprehensionTlv ctlv, boolean noAlphaUsrCnf) 289 throws ResultException { 290 291 if (ctlv != null) { 292 byte[] rawValue = ctlv.getRawValue(); 293 int valueIndex = ctlv.getValueIndex(); 294 int length = ctlv.getLength(); 295 if (length != 0) { 296 try { 297 return IccUtils.adnStringFieldToString(rawValue, valueIndex, 298 length); 299 } catch (IndexOutOfBoundsException e) { 300 throw new ResultException(ResultCode.CMD_DATA_NOT_UNDERSTOOD); 301 } 302 } else { 303 CatLog.d("ValueParser", "Alpha Id length=" + length); 304 return null; 305 } 306 } else { 307 /* Per 3GPP specification 102.223, 308 * if the alpha identifier is not provided by the UICC, 309 * the terminal MAY give information to the user 310 * noAlphaUsrCnf defines if you need to show user confirmation or not 311 */ 312 return (noAlphaUsrCnf ? null : CatService.STK_DEFAULT); 313 } 314 } 315 316 /** 317 * Retrieves text from the Text COMPREHENSION-TLV object, and decodes it 318 * into a Java String. 319 * 320 * @param ctlv A Text COMPREHENSION-TLV object 321 * @return A Java String object decoded from the Text object 322 * @throws ResultException 323 */ 324 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) retrieveTextString(ComprehensionTlv ctlv)325 static String retrieveTextString(ComprehensionTlv ctlv) throws ResultException { 326 byte[] rawValue = ctlv.getRawValue(); 327 int valueIndex = ctlv.getValueIndex(); 328 byte codingScheme = 0x00; 329 String text = null; 330 int textLen = ctlv.getLength(); 331 332 // In case the text length is 0, return a null string. 333 if (textLen == 0) { 334 return text; 335 } else { 336 // one byte is coding scheme 337 textLen -= 1; 338 } 339 340 try { 341 codingScheme = (byte) (rawValue[valueIndex] & 0x0c); 342 343 if (codingScheme == 0x00) { // GSM 7-bit packed 344 text = GsmAlphabet.gsm7BitPackedToString(rawValue, 345 valueIndex + 1, (textLen * 8) / 7); 346 } else if (codingScheme == 0x04) { // GSM 8-bit unpacked 347 text = GsmAlphabet.gsm8BitUnpackedToString(rawValue, 348 valueIndex + 1, textLen); 349 } else if (codingScheme == 0x08) { // UCS2 350 text = new String(rawValue, valueIndex + 1, textLen, "UTF-16"); 351 } else { 352 throw new ResultException(ResultCode.CMD_DATA_NOT_UNDERSTOOD); 353 } 354 355 return text; 356 } catch (IndexOutOfBoundsException e) { 357 throw new ResultException(ResultCode.CMD_DATA_NOT_UNDERSTOOD); 358 } catch (UnsupportedEncodingException e) { 359 // This should never happen. 360 throw new ResultException(ResultCode.CMD_DATA_NOT_UNDERSTOOD); 361 } 362 } 363 364 /** 365 * Retrieve's the tpdu from the ctlv and creates the SmsMessage from pdu. 366 * @param ctlv ComprehensionTlv value 367 * @return message SmsMessage to retrieve the destAddress and Text 368 * @throws ResultException 369 * @hide 370 */ retrieveTpduAsSmsMessage(ComprehensionTlv ctlv)371 public static SmsMessage retrieveTpduAsSmsMessage(ComprehensionTlv ctlv) 372 throws ResultException { 373 if (ctlv != null) { 374 byte[] rawValue = ctlv.getRawValue(); 375 int valueIndex = ctlv.getValueIndex(); 376 int length = ctlv.getLength(); 377 if (length != 0) { 378 try { 379 byte[] pdu = Arrays.copyOfRange(rawValue, valueIndex, (valueIndex + length)); 380 ByteArrayOutputStream bo = new ByteArrayOutputStream(pdu.length + 1); 381 /* Framework's TPdu Parser expects the TPdu be prepended with SC-Address. 382 * else the parser will throw an exception. So prepending TPdu with 0, 383 * which indicates that there is no SC address and its length is 0. 384 * This way Parser will skip parsing for SC-Address 385 */ 386 bo.write(0x00); 387 bo.write(pdu, 0, pdu.length); 388 byte[] frameworkPdu = bo.toByteArray(); 389 //ToDO handle for 3GPP2 format bug: b/243123533 390 SmsMessage message = SmsMessage.createFromPdu(frameworkPdu, 391 SmsMessage.FORMAT_3GPP); 392 return message; 393 } catch (IndexOutOfBoundsException e) { 394 throw new ResultException(ResultCode.CMD_DATA_NOT_UNDERSTOOD); 395 } 396 } 397 } 398 return null; 399 } 400 401 } 402