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 
22 import com.android.internal.telephony.GsmAlphabet;
23 import com.android.internal.telephony.cat.Duration.TimeUnit;
24 import com.android.internal.telephony.uicc.IccUtils;
25 
26 import java.io.UnsupportedEncodingException;
27 import java.util.ArrayList;
28 import java.util.List;
29 
30 abstract class ValueParser {
31 
32     /**
33      * Search for a Command Details object from a list.
34      *
35      * @param ctlv List of ComprehensionTlv objects used for search
36      * @return An CtlvCommandDetails object found from the objects. If no
37      *         Command Details object is found, ResultException is thrown.
38      * @throws ResultException
39      */
retrieveCommandDetails(ComprehensionTlv ctlv)40     static CommandDetails retrieveCommandDetails(ComprehensionTlv ctlv)
41             throws ResultException {
42 
43         CommandDetails cmdDet = new CommandDetails();
44         byte[] rawValue = ctlv.getRawValue();
45         int valueIndex = ctlv.getValueIndex();
46         try {
47             cmdDet.compRequired = ctlv.isComprehensionRequired();
48             cmdDet.commandNumber = rawValue[valueIndex] & 0xff;
49             cmdDet.typeOfCommand = rawValue[valueIndex + 1] & 0xff;
50             cmdDet.commandQualifier = rawValue[valueIndex + 2] & 0xff;
51             return cmdDet;
52         } catch (IndexOutOfBoundsException e) {
53             throw new ResultException(ResultCode.CMD_DATA_NOT_UNDERSTOOD);
54         }
55     }
56 
57     /**
58      * Search for a Device Identities object from a list.
59      *
60      * @param ctlv List of ComprehensionTlv objects used for search
61      * @return An CtlvDeviceIdentities object found from the objects. If no
62      *         Command Details object is found, ResultException is thrown.
63      * @throws ResultException
64      */
65     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
retrieveDeviceIdentities(ComprehensionTlv ctlv)66     static DeviceIdentities retrieveDeviceIdentities(ComprehensionTlv ctlv)
67             throws ResultException {
68 
69         DeviceIdentities devIds = new DeviceIdentities();
70         byte[] rawValue = ctlv.getRawValue();
71         int valueIndex = ctlv.getValueIndex();
72         try {
73             devIds.sourceId = rawValue[valueIndex] & 0xff;
74             devIds.destinationId = rawValue[valueIndex + 1] & 0xff;
75             return devIds;
76         } catch (IndexOutOfBoundsException e) {
77             throw new ResultException(ResultCode.REQUIRED_VALUES_MISSING);
78         }
79     }
80 
81     /**
82      * Retrieves Duration information from the Duration COMPREHENSION-TLV
83      * object.
84      *
85      * @param ctlv A Text Attribute COMPREHENSION-TLV object
86      * @return A Duration object
87      * @throws ResultException
88      */
retrieveDuration(ComprehensionTlv ctlv)89     static Duration retrieveDuration(ComprehensionTlv ctlv) throws ResultException {
90         int timeInterval = 0;
91         TimeUnit timeUnit = TimeUnit.SECOND;
92 
93         byte[] rawValue = ctlv.getRawValue();
94         int valueIndex = ctlv.getValueIndex();
95 
96         try {
97             timeUnit = TimeUnit.values()[(rawValue[valueIndex] & 0xff)];
98             timeInterval = rawValue[valueIndex + 1] & 0xff;
99         } catch (IndexOutOfBoundsException e) {
100             throw new ResultException(ResultCode.CMD_DATA_NOT_UNDERSTOOD);
101         }
102         return new Duration(timeInterval, timeUnit);
103     }
104 
105     /**
106      * Retrieves Item information from the COMPREHENSION-TLV object.
107      *
108      * @param ctlv A Text Attribute COMPREHENSION-TLV object
109      * @return An Item
110      * @throws ResultException
111      */
retrieveItem(ComprehensionTlv ctlv)112     static Item retrieveItem(ComprehensionTlv ctlv) throws ResultException {
113         Item item = null;
114 
115         byte[] rawValue = ctlv.getRawValue();
116         int valueIndex = ctlv.getValueIndex();
117         int length = ctlv.getLength();
118 
119         if (length != 0) {
120             int textLen = length - 1;
121 
122             try {
123                 int id = rawValue[valueIndex] & 0xff;
124                 String text = IccUtils.adnStringFieldToString(rawValue,
125                         valueIndex + 1, textLen);
126                 item = new Item(id, text);
127             } catch (IndexOutOfBoundsException e) {
128                 throw new ResultException(ResultCode.CMD_DATA_NOT_UNDERSTOOD);
129             }
130         }
131 
132         return item;
133     }
134 
135     /**
136      * Retrieves Item id information from the COMPREHENSION-TLV object.
137      *
138      * @param ctlv A Text Attribute COMPREHENSION-TLV object
139      * @return An Item id
140      * @throws ResultException
141      */
retrieveItemId(ComprehensionTlv ctlv)142     static int retrieveItemId(ComprehensionTlv ctlv) throws ResultException {
143         int id = 0;
144 
145         byte[] rawValue = ctlv.getRawValue();
146         int valueIndex = ctlv.getValueIndex();
147 
148         try {
149             id = rawValue[valueIndex] & 0xff;
150         } catch (IndexOutOfBoundsException e) {
151             throw new ResultException(ResultCode.CMD_DATA_NOT_UNDERSTOOD);
152         }
153 
154         return id;
155     }
156 
157     /**
158      * Retrieves icon id from an Icon Identifier COMPREHENSION-TLV object
159      *
160      * @param ctlv An Icon Identifier COMPREHENSION-TLV object
161      * @return IconId instance
162      * @throws ResultException
163      */
retrieveIconId(ComprehensionTlv ctlv)164     static IconId retrieveIconId(ComprehensionTlv ctlv) throws ResultException {
165         IconId id = new IconId();
166 
167         byte[] rawValue = ctlv.getRawValue();
168         int valueIndex = ctlv.getValueIndex();
169         try {
170             id.selfExplanatory = (rawValue[valueIndex++] & 0xff) == 0x00;
171             id.recordNumber = rawValue[valueIndex] & 0xff;
172         } catch (IndexOutOfBoundsException e) {
173             throw new ResultException(ResultCode.CMD_DATA_NOT_UNDERSTOOD);
174         }
175 
176         return id;
177     }
178 
179     /**
180      * Retrieves item icons id from an Icon Identifier List COMPREHENSION-TLV
181      * object
182      *
183      * @param ctlv An Item Icon List Identifier COMPREHENSION-TLV object
184      * @return ItemsIconId instance
185      * @throws ResultException
186      */
retrieveItemsIconId(ComprehensionTlv ctlv)187     static ItemsIconId retrieveItemsIconId(ComprehensionTlv ctlv)
188             throws ResultException {
189         CatLog.d("ValueParser", "retrieveItemsIconId:");
190         ItemsIconId id = new ItemsIconId();
191 
192         byte[] rawValue = ctlv.getRawValue();
193         int valueIndex = ctlv.getValueIndex();
194         int numOfItems = ctlv.getLength() - 1;
195         id.recordNumbers = new int[numOfItems];
196 
197         try {
198             // get icon self-explanatory
199             id.selfExplanatory = (rawValue[valueIndex++] & 0xff) == 0x00;
200 
201             for (int index = 0; index < numOfItems;) {
202                 id.recordNumbers[index++] = rawValue[valueIndex++];
203             }
204         } catch (IndexOutOfBoundsException e) {
205             throw new ResultException(ResultCode.CMD_DATA_NOT_UNDERSTOOD);
206         }
207         return id;
208     }
209 
210     /**
211      * Retrieves text attribute information from the Text Attribute
212      * COMPREHENSION-TLV object.
213      *
214      * @param ctlv A Text Attribute COMPREHENSION-TLV object
215      * @return A list of TextAttribute objects
216      * @throws ResultException
217      */
218     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
retrieveTextAttribute(ComprehensionTlv ctlv)219     static List<TextAttribute> retrieveTextAttribute(ComprehensionTlv ctlv)
220             throws ResultException {
221         ArrayList<TextAttribute> lst = new ArrayList<TextAttribute>();
222 
223         byte[] rawValue = ctlv.getRawValue();
224         int valueIndex = ctlv.getValueIndex();
225         int length = ctlv.getLength();
226 
227         if (length != 0) {
228             // Each attribute is consisted of four bytes
229             int itemCount = length / 4;
230 
231             try {
232                 for (int i = 0; i < itemCount; i++, valueIndex += 4) {
233                     int start = rawValue[valueIndex] & 0xff;
234                     int textLength = rawValue[valueIndex + 1] & 0xff;
235                     int format = rawValue[valueIndex + 2] & 0xff;
236                     int colorValue = rawValue[valueIndex + 3] & 0xff;
237 
238                     int alignValue = format & 0x03;
239                     TextAlignment align = TextAlignment.fromInt(alignValue);
240 
241                     int sizeValue = (format >> 2) & 0x03;
242                     FontSize size = FontSize.fromInt(sizeValue);
243                     if (size == null) {
244                         // Font size value is not defined. Use default.
245                         size = FontSize.NORMAL;
246                     }
247 
248                     boolean bold = (format & 0x10) != 0;
249                     boolean italic = (format & 0x20) != 0;
250                     boolean underlined = (format & 0x40) != 0;
251                     boolean strikeThrough = (format & 0x80) != 0;
252 
253                     TextColor color = TextColor.fromInt(colorValue);
254 
255                     TextAttribute attr = new TextAttribute(start, textLength,
256                             align, size, bold, italic, underlined,
257                             strikeThrough, color);
258                     lst.add(attr);
259                 }
260 
261                 return lst;
262 
263             } catch (IndexOutOfBoundsException e) {
264                 throw new ResultException(ResultCode.CMD_DATA_NOT_UNDERSTOOD);
265             }
266         }
267         return null;
268     }
269 
270 
271     /**
272      * Retrieves alpha identifier from an Alpha Identifier COMPREHENSION-TLV
273      * object.
274      *
275      * @param ctlv An Alpha Identifier COMPREHENSION-TLV object
276      * @return String corresponding to the alpha identifier
277      * @throws ResultException
278      */
279     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
retrieveAlphaId(ComprehensionTlv ctlv, boolean noAlphaUsrCnf)280     static String retrieveAlphaId(ComprehensionTlv ctlv, boolean noAlphaUsrCnf)
281             throws ResultException {
282 
283         if (ctlv != null) {
284             byte[] rawValue = ctlv.getRawValue();
285             int valueIndex = ctlv.getValueIndex();
286             int length = ctlv.getLength();
287             if (length != 0) {
288                 try {
289                     return IccUtils.adnStringFieldToString(rawValue, valueIndex,
290                             length);
291                 } catch (IndexOutOfBoundsException e) {
292                     throw new ResultException(ResultCode.CMD_DATA_NOT_UNDERSTOOD);
293                 }
294             } else {
295                 CatLog.d("ValueParser", "Alpha Id length=" + length);
296                 return null;
297             }
298         } else {
299             /* Per 3GPP specification 102.223,
300              * if the alpha identifier is not provided by the UICC,
301              * the terminal MAY give information to the user
302              * noAlphaUsrCnf defines if you need to show user confirmation or not
303              */
304             return (noAlphaUsrCnf ? null : CatService.STK_DEFAULT);
305         }
306     }
307 
308     /**
309      * Retrieves text from the Text COMPREHENSION-TLV object, and decodes it
310      * into a Java String.
311      *
312      * @param ctlv A Text COMPREHENSION-TLV object
313      * @return A Java String object decoded from the Text object
314      * @throws ResultException
315      */
316     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
retrieveTextString(ComprehensionTlv ctlv)317     static String retrieveTextString(ComprehensionTlv ctlv) throws ResultException {
318         byte[] rawValue = ctlv.getRawValue();
319         int valueIndex = ctlv.getValueIndex();
320         byte codingScheme = 0x00;
321         String text = null;
322         int textLen = ctlv.getLength();
323 
324         // In case the text length is 0, return a null string.
325         if (textLen == 0) {
326             return text;
327         } else {
328             // one byte is coding scheme
329             textLen -= 1;
330         }
331 
332         try {
333             codingScheme = (byte) (rawValue[valueIndex] & 0x0c);
334 
335             if (codingScheme == 0x00) { // GSM 7-bit packed
336                 text = GsmAlphabet.gsm7BitPackedToString(rawValue,
337                         valueIndex + 1, (textLen * 8) / 7);
338             } else if (codingScheme == 0x04) { // GSM 8-bit unpacked
339                 text = GsmAlphabet.gsm8BitUnpackedToString(rawValue,
340                         valueIndex + 1, textLen);
341             } else if (codingScheme == 0x08) { // UCS2
342                 text = new String(rawValue, valueIndex + 1, textLen, "UTF-16");
343             } else {
344                 throw new ResultException(ResultCode.CMD_DATA_NOT_UNDERSTOOD);
345             }
346 
347             return text;
348         } catch (IndexOutOfBoundsException e) {
349             throw new ResultException(ResultCode.CMD_DATA_NOT_UNDERSTOOD);
350         } catch (UnsupportedEncodingException e) {
351             // This should never happen.
352             throw new ResultException(ResultCode.CMD_DATA_NOT_UNDERSTOOD);
353         }
354     }
355 }
356