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.content.res.Resources;
21 import android.content.res.Resources.NotFoundException;
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.UnsupportedEncodingException;
28 import java.util.ArrayList;
29 import java.util.List;
30 
31 abstract class ValueParser {
32 
33     /**
34      * Search for a Command Details object from a list.
35      *
36      * @param ctlv List of ComprehensionTlv objects used for search
37      * @return An CtlvCommandDetails object found from the objects. If no
38      *         Command Details object is found, ResultException is thrown.
39      * @throws ResultException
40      */
retrieveCommandDetails(ComprehensionTlv ctlv)41     static CommandDetails retrieveCommandDetails(ComprehensionTlv ctlv)
42             throws ResultException {
43 
44         CommandDetails cmdDet = new CommandDetails();
45         byte[] rawValue = ctlv.getRawValue();
46         int valueIndex = ctlv.getValueIndex();
47         try {
48             cmdDet.compRequired = ctlv.isComprehensionRequired();
49             cmdDet.commandNumber = rawValue[valueIndex] & 0xff;
50             cmdDet.typeOfCommand = rawValue[valueIndex + 1] & 0xff;
51             cmdDet.commandQualifier = rawValue[valueIndex + 2] & 0xff;
52             return cmdDet;
53         } catch (IndexOutOfBoundsException e) {
54             throw new ResultException(ResultCode.CMD_DATA_NOT_UNDERSTOOD);
55         }
56     }
57 
58     /**
59      * Search for a Device Identities object from a list.
60      *
61      * @param ctlv List of ComprehensionTlv objects used for search
62      * @return An CtlvDeviceIdentities object found from the objects. If no
63      *         Command Details object is found, ResultException is thrown.
64      * @throws ResultException
65      */
66     @UnsupportedAppUsage
retrieveDeviceIdentities(ComprehensionTlv ctlv)67     static DeviceIdentities retrieveDeviceIdentities(ComprehensionTlv ctlv)
68             throws ResultException {
69 
70         DeviceIdentities devIds = new DeviceIdentities();
71         byte[] rawValue = ctlv.getRawValue();
72         int valueIndex = ctlv.getValueIndex();
73         try {
74             devIds.sourceId = rawValue[valueIndex] & 0xff;
75             devIds.destinationId = rawValue[valueIndex + 1] & 0xff;
76             return devIds;
77         } catch (IndexOutOfBoundsException e) {
78             throw new ResultException(ResultCode.REQUIRED_VALUES_MISSING);
79         }
80     }
81 
82     /**
83      * Retrieves Duration information from the Duration COMPREHENSION-TLV
84      * object.
85      *
86      * @param ctlv A Text Attribute COMPREHENSION-TLV object
87      * @return A Duration object
88      * @throws ResultException
89      */
retrieveDuration(ComprehensionTlv ctlv)90     static Duration retrieveDuration(ComprehensionTlv ctlv) throws ResultException {
91         int timeInterval = 0;
92         TimeUnit timeUnit = TimeUnit.SECOND;
93 
94         byte[] rawValue = ctlv.getRawValue();
95         int valueIndex = ctlv.getValueIndex();
96 
97         try {
98             timeUnit = TimeUnit.values()[(rawValue[valueIndex] & 0xff)];
99             timeInterval = rawValue[valueIndex + 1] & 0xff;
100         } catch (IndexOutOfBoundsException e) {
101             throw new ResultException(ResultCode.CMD_DATA_NOT_UNDERSTOOD);
102         }
103         return new Duration(timeInterval, timeUnit);
104     }
105 
106     /**
107      * Retrieves Item information from the COMPREHENSION-TLV object.
108      *
109      * @param ctlv A Text Attribute COMPREHENSION-TLV object
110      * @return An Item
111      * @throws ResultException
112      */
retrieveItem(ComprehensionTlv ctlv)113     static Item retrieveItem(ComprehensionTlv ctlv) throws ResultException {
114         Item item = null;
115 
116         byte[] rawValue = ctlv.getRawValue();
117         int valueIndex = ctlv.getValueIndex();
118         int length = ctlv.getLength();
119 
120         if (length != 0) {
121             int textLen = length - 1;
122 
123             try {
124                 int id = rawValue[valueIndex] & 0xff;
125                 String text = IccUtils.adnStringFieldToString(rawValue,
126                         valueIndex + 1, textLen);
127                 item = new Item(id, text);
128             } catch (IndexOutOfBoundsException e) {
129                 throw new ResultException(ResultCode.CMD_DATA_NOT_UNDERSTOOD);
130             }
131         }
132 
133         return item;
134     }
135 
136     /**
137      * Retrieves Item id information from the COMPREHENSION-TLV object.
138      *
139      * @param ctlv A Text Attribute COMPREHENSION-TLV object
140      * @return An Item id
141      * @throws ResultException
142      */
retrieveItemId(ComprehensionTlv ctlv)143     static int retrieveItemId(ComprehensionTlv ctlv) throws ResultException {
144         int id = 0;
145 
146         byte[] rawValue = ctlv.getRawValue();
147         int valueIndex = ctlv.getValueIndex();
148 
149         try {
150             id = rawValue[valueIndex] & 0xff;
151         } catch (IndexOutOfBoundsException e) {
152             throw new ResultException(ResultCode.CMD_DATA_NOT_UNDERSTOOD);
153         }
154 
155         return id;
156     }
157 
158     /**
159      * Retrieves icon id from an Icon Identifier COMPREHENSION-TLV object
160      *
161      * @param ctlv An Icon Identifier COMPREHENSION-TLV object
162      * @return IconId instance
163      * @throws ResultException
164      */
retrieveIconId(ComprehensionTlv ctlv)165     static IconId retrieveIconId(ComprehensionTlv ctlv) throws ResultException {
166         IconId id = new IconId();
167 
168         byte[] rawValue = ctlv.getRawValue();
169         int valueIndex = ctlv.getValueIndex();
170         try {
171             id.selfExplanatory = (rawValue[valueIndex++] & 0xff) == 0x00;
172             id.recordNumber = rawValue[valueIndex] & 0xff;
173         } catch (IndexOutOfBoundsException e) {
174             throw new ResultException(ResultCode.CMD_DATA_NOT_UNDERSTOOD);
175         }
176 
177         return id;
178     }
179 
180     /**
181      * Retrieves item icons id from an Icon Identifier List COMPREHENSION-TLV
182      * object
183      *
184      * @param ctlv An Item Icon List Identifier COMPREHENSION-TLV object
185      * @return ItemsIconId instance
186      * @throws ResultException
187      */
retrieveItemsIconId(ComprehensionTlv ctlv)188     static ItemsIconId retrieveItemsIconId(ComprehensionTlv ctlv)
189             throws ResultException {
190         CatLog.d("ValueParser", "retrieveItemsIconId:");
191         ItemsIconId id = new ItemsIconId();
192 
193         byte[] rawValue = ctlv.getRawValue();
194         int valueIndex = ctlv.getValueIndex();
195         int numOfItems = ctlv.getLength() - 1;
196         id.recordNumbers = new int[numOfItems];
197 
198         try {
199             // get icon self-explanatory
200             id.selfExplanatory = (rawValue[valueIndex++] & 0xff) == 0x00;
201 
202             for (int index = 0; index < numOfItems;) {
203                 id.recordNumbers[index++] = rawValue[valueIndex++];
204             }
205         } catch (IndexOutOfBoundsException e) {
206             throw new ResultException(ResultCode.CMD_DATA_NOT_UNDERSTOOD);
207         }
208         return id;
209     }
210 
211     /**
212      * Retrieves text attribute information from the Text Attribute
213      * COMPREHENSION-TLV object.
214      *
215      * @param ctlv A Text Attribute COMPREHENSION-TLV object
216      * @return A list of TextAttribute objects
217      * @throws ResultException
218      */
219     @UnsupportedAppUsage
retrieveTextAttribute(ComprehensionTlv ctlv)220     static List<TextAttribute> retrieveTextAttribute(ComprehensionTlv ctlv)
221             throws ResultException {
222         ArrayList<TextAttribute> lst = new ArrayList<TextAttribute>();
223 
224         byte[] rawValue = ctlv.getRawValue();
225         int valueIndex = ctlv.getValueIndex();
226         int length = ctlv.getLength();
227 
228         if (length != 0) {
229             // Each attribute is consisted of four bytes
230             int itemCount = length / 4;
231 
232             try {
233                 for (int i = 0; i < itemCount; i++, valueIndex += 4) {
234                     int start = rawValue[valueIndex] & 0xff;
235                     int textLength = rawValue[valueIndex + 1] & 0xff;
236                     int format = rawValue[valueIndex + 2] & 0xff;
237                     int colorValue = rawValue[valueIndex + 3] & 0xff;
238 
239                     int alignValue = format & 0x03;
240                     TextAlignment align = TextAlignment.fromInt(alignValue);
241 
242                     int sizeValue = (format >> 2) & 0x03;
243                     FontSize size = FontSize.fromInt(sizeValue);
244                     if (size == null) {
245                         // Font size value is not defined. Use default.
246                         size = FontSize.NORMAL;
247                     }
248 
249                     boolean bold = (format & 0x10) != 0;
250                     boolean italic = (format & 0x20) != 0;
251                     boolean underlined = (format & 0x40) != 0;
252                     boolean strikeThrough = (format & 0x80) != 0;
253 
254                     TextColor color = TextColor.fromInt(colorValue);
255 
256                     TextAttribute attr = new TextAttribute(start, textLength,
257                             align, size, bold, italic, underlined,
258                             strikeThrough, color);
259                     lst.add(attr);
260                 }
261 
262                 return lst;
263 
264             } catch (IndexOutOfBoundsException e) {
265                 throw new ResultException(ResultCode.CMD_DATA_NOT_UNDERSTOOD);
266             }
267         }
268         return null;
269     }
270 
271 
272     /**
273      * Retrieves alpha identifier from an Alpha Identifier COMPREHENSION-TLV
274      * object.
275      *
276      * @param ctlv An Alpha Identifier COMPREHENSION-TLV object
277      * @return String corresponding to the alpha identifier
278      * @throws ResultException
279      */
280     @UnsupportedAppUsage
retrieveAlphaId(ComprehensionTlv ctlv)281     static String retrieveAlphaId(ComprehensionTlv ctlv) 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             boolean noAlphaUsrCnf = false;
305             Resources resource = Resources.getSystem();
306             try {
307                 noAlphaUsrCnf = resource.getBoolean(
308                         com.android.internal.R.bool.config_stkNoAlphaUsrCnf);
309             } catch (NotFoundException e) {
310                 noAlphaUsrCnf = false;
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
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