• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2006 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;
18 
19 import android.os.Parcel;
20 import android.os.Parcelable;
21 import android.telephony.PhoneNumberUtils;
22 import android.util.Log;
23 
24 import com.android.internal.telephony.GsmAlphabet;
25 
26 import java.util.Arrays;
27 
28 
29 /**
30  *
31  * Used to load or store ADNs (Abbreviated Dialing Numbers).
32  *
33  * {@hide}
34  *
35  */
36 public class AdnRecord implements Parcelable {
37     static final String LOG_TAG = "GSM";
38 
39     //***** Instance Variables
40 
41     String alphaTag = "";
42     String number = "";
43     String[] emails;
44     int extRecord = 0xff;
45     int efid;                   // or 0 if none
46     int recordNumber;           // or 0 if none
47 
48 
49     //***** Constants
50 
51     // In an ADN record, everything but the alpha identifier
52     // is in a footer that's 14 bytes
53     static final int FOOTER_SIZE_BYTES = 14;
54 
55     // Maximum size of the un-extended number field
56     static final int MAX_NUMBER_SIZE_BYTES = 11;
57 
58     static final int EXT_RECORD_LENGTH_BYTES = 13;
59     static final int EXT_RECORD_TYPE_ADDITIONAL_DATA = 2;
60     static final int EXT_RECORD_TYPE_MASK = 3;
61     static final int MAX_EXT_CALLED_PARTY_LENGTH = 0xa;
62 
63     // ADN offset
64     static final int ADN_BCD_NUMBER_LENGTH = 0;
65     static final int ADN_TON_AND_NPI = 1;
66     static final int ADN_DAILING_NUMBER_START = 2;
67     static final int ADN_DAILING_NUMBER_END = 11;
68     static final int ADN_CAPABILITY_ID = 12;
69     static final int ADN_EXTENSION_ID = 13;
70 
71     //***** Static Methods
72 
73     public static final Parcelable.Creator<AdnRecord> CREATOR
74             = new Parcelable.Creator<AdnRecord>() {
75         public AdnRecord createFromParcel(Parcel source) {
76             int efid;
77             int recordNumber;
78             String alphaTag;
79             String number;
80             String[] emails;
81 
82             efid = source.readInt();
83             recordNumber = source.readInt();
84             alphaTag = source.readString();
85             number = source.readString();
86             emails = source.readStringArray();
87 
88             return new AdnRecord(efid, recordNumber, alphaTag, number, emails);
89         }
90 
91         public AdnRecord[] newArray(int size) {
92             return new AdnRecord[size];
93         }
94     };
95 
96 
97     //***** Constructor
AdnRecord(byte[] record)98     public AdnRecord (byte[] record) {
99         this(0, 0, record);
100     }
101 
AdnRecord(int efid, int recordNumber, byte[] record)102     public AdnRecord (int efid, int recordNumber, byte[] record) {
103         this.efid = efid;
104         this.recordNumber = recordNumber;
105         parseRecord(record);
106     }
107 
AdnRecord(String alphaTag, String number)108     public AdnRecord (String alphaTag, String number) {
109         this(0, 0, alphaTag, number);
110     }
111 
AdnRecord(String alphaTag, String number, String[] emails)112     public AdnRecord (String alphaTag, String number, String[] emails) {
113         this(0, 0, alphaTag, number, emails);
114     }
115 
AdnRecord(int efid, int recordNumber, String alphaTag, String number, String[] emails)116     public AdnRecord (int efid, int recordNumber, String alphaTag, String number, String[] emails) {
117         this.efid = efid;
118         this.recordNumber = recordNumber;
119         this.alphaTag = alphaTag;
120         this.number = number;
121         this.emails = emails;
122     }
123 
AdnRecord(int efid, int recordNumber, String alphaTag, String number)124     public AdnRecord(int efid, int recordNumber, String alphaTag, String number) {
125         this.efid = efid;
126         this.recordNumber = recordNumber;
127         this.alphaTag = alphaTag;
128         this.number = number;
129         this.emails = null;
130     }
131 
132     //***** Instance Methods
133 
getAlphaTag()134     public String getAlphaTag() {
135         return alphaTag;
136     }
137 
getNumber()138     public String getNumber() {
139         return number;
140     }
141 
getEmails()142     public String[] getEmails() {
143         return emails;
144     }
145 
setEmails(String[] emails)146     public void setEmails(String[] emails) {
147         this.emails = emails;
148     }
149 
toString()150     public String toString() {
151         return "ADN Record '" + alphaTag + "' '" + number + " " + emails + "'";
152     }
153 
isEmpty()154     public boolean isEmpty() {
155         return alphaTag.equals("") && number.equals("") && emails == null;
156     }
157 
hasExtendedRecord()158     public boolean hasExtendedRecord() {
159         return extRecord != 0 && extRecord != 0xff;
160     }
161 
isEqual(AdnRecord adn)162     public boolean isEqual(AdnRecord adn) {
163         return ( alphaTag.equals(adn.getAlphaTag()) &&
164                 number.equals(adn.getNumber()) &&
165                 Arrays.equals(emails, adn.getEmails()));
166     }
167     //***** Parcelable Implementation
168 
describeContents()169     public int describeContents() {
170         return 0;
171     }
172 
writeToParcel(Parcel dest, int flags)173     public void writeToParcel(Parcel dest, int flags) {
174         dest.writeInt(efid);
175         dest.writeInt(recordNumber);
176         dest.writeString(alphaTag);
177         dest.writeString(number);
178         dest.writeStringArray(emails);
179     }
180 
181     /**
182      * Build adn hex byte array based on record size
183      * The format of byte array is defined in 51.011 10.5.1
184      *
185      * @param recordSize is the size X of EF record
186      * @return hex byte[recordSize] to be written to EF record
187      *          return nulll for wrong format of dialing nubmer or tag
188      */
buildAdnString(int recordSize)189     public byte[] buildAdnString(int recordSize) {
190         byte[] bcdNumber;
191         byte[] byteTag;
192         byte[] adnString = null;
193         int footerOffset = recordSize - FOOTER_SIZE_BYTES;
194 
195         if (number == null || number.equals("") ||
196                 alphaTag == null || alphaTag.equals("")) {
197 
198             Log.w(LOG_TAG, "[buildAdnString] Empty alpha tag or number");
199             adnString = new byte[recordSize];
200             for (int i = 0; i < recordSize; i++) {
201                 adnString[i] = (byte) 0xFF;
202             }
203         } else if (number.length()
204                 > (ADN_DAILING_NUMBER_END - ADN_DAILING_NUMBER_START + 1) * 2) {
205             Log.w(LOG_TAG,
206                     "[buildAdnString] Max length of dailing number is 20");
207         } else if (alphaTag.length() > footerOffset) {
208             Log.w(LOG_TAG,
209                     "[buildAdnString] Max length of tag is " + footerOffset);
210         } else {
211 
212             adnString = new byte[recordSize];
213             for (int i = 0; i < recordSize; i++) {
214                 adnString[i] = (byte) 0xFF;
215             }
216 
217             bcdNumber = PhoneNumberUtils.numberToCalledPartyBCD(number);
218 
219             System.arraycopy(bcdNumber, 0, adnString,
220                     footerOffset + ADN_TON_AND_NPI, bcdNumber.length);
221 
222             adnString[footerOffset + ADN_BCD_NUMBER_LENGTH]
223                     = (byte) (bcdNumber.length);
224             adnString[footerOffset + ADN_CAPABILITY_ID]
225                     = (byte) 0xFF; // Capacility Id
226             adnString[footerOffset + ADN_EXTENSION_ID]
227                     = (byte) 0xFF; // Extension Record Id
228 
229             byteTag = GsmAlphabet.stringToGsm8BitPacked(alphaTag);
230             System.arraycopy(byteTag, 0, adnString, 0, byteTag.length);
231 
232         }
233 
234         return adnString;
235     }
236 
237     /**
238      * See TS 51.011 10.5.10
239      */
240     public void
appendExtRecord(byte[] extRecord)241     appendExtRecord (byte[] extRecord) {
242         try {
243             if (extRecord.length != EXT_RECORD_LENGTH_BYTES) {
244                 return;
245             }
246 
247             if ((extRecord[0] & EXT_RECORD_TYPE_MASK)
248                     != EXT_RECORD_TYPE_ADDITIONAL_DATA) {
249                 return;
250             }
251 
252             if ((0xff & extRecord[1]) > MAX_EXT_CALLED_PARTY_LENGTH) {
253                 // invalid or empty record
254                 return;
255             }
256 
257             number += PhoneNumberUtils.calledPartyBCDFragmentToString(
258                                         extRecord, 2, 0xff & extRecord[1]);
259 
260             // We don't support ext record chaining.
261 
262         } catch (RuntimeException ex) {
263             Log.w(LOG_TAG, "Error parsing AdnRecord ext record", ex);
264         }
265     }
266 
267     //***** Private Methods
268 
269     /**
270      * alphaTag and number are set to null on invalid format
271      */
272     private void
parseRecord(byte[] record)273     parseRecord(byte[] record) {
274         try {
275             alphaTag = IccUtils.adnStringFieldToString(
276                             record, 0, record.length - FOOTER_SIZE_BYTES);
277 
278             int footerOffset = record.length - FOOTER_SIZE_BYTES;
279 
280             int numberLength = 0xff & record[footerOffset];
281 
282             if (numberLength > MAX_NUMBER_SIZE_BYTES) {
283                 // Invalid number length
284                 number = "";
285                 return;
286             }
287 
288             // Please note 51.011 10.5.1:
289             //
290             // "If the Dialling Number/SSC String does not contain
291             // a dialling number, e.g. a control string deactivating
292             // a service, the TON/NPI byte shall be set to 'FF' by
293             // the ME (see note 2)."
294 
295             number = PhoneNumberUtils.calledPartyBCDToString(
296                             record, footerOffset + 1, numberLength);
297 
298 
299             extRecord = 0xff & record[record.length - 1];
300 
301             emails = null;
302 
303         } catch (RuntimeException ex) {
304             Log.w(LOG_TAG, "Error parsing AdnRecord", ex);
305             number = "";
306             alphaTag = "";
307             emails = null;
308         }
309     }
310 }
311