• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2015, Motorola Mobility LLC
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *     - Redistributions of source code must retain the above copyright
8  *       notice, this list of conditions and the following disclaimer.
9  *     - Redistributions in binary form must reproduce the above copyright
10  *       notice, this list of conditions and the following disclaimer in the
11  *       documentation and/or other materials provided with the distribution.
12  *     - Neither the name of Motorola Mobility nor the
13  *       names of its contributors may be used to endorse or promote products
14  *       derived from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
18  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MOTOROLA MOBILITY LLC BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
26  * DAMAGE.
27  */
28 
29 package com.android.ims.internal;
30 
31 import android.content.Context;
32 import android.os.Build;
33 import android.telephony.PhoneNumberUtils;
34 import android.telephony.TelephonyManager;
35 import android.text.TextUtils;
36 import android.util.Log;
37 
38 import java.util.List;
39 import java.util.ArrayList;
40 
41 /**
42  * @hide
43  */
44 public class ContactNumberUtils {
45     /**
46      * Sample code:
47      *
48      * ContactNumberUtils mNumberUtils = ContactNumberUtils.getDefault();
49      * mNumberUtils.setContext(this);
50      *
51      * number = mNumberUtils.format(number);
52      * int result = mNumberUtils.validate(number);
53      * if (ContactNumberUtils.NUMBER_VALID == result) {
54      * }
55      */
getDefault()56     public static ContactNumberUtils getDefault() {
57         if(sInstance == null) {
58             sInstance = new ContactNumberUtils();
59         }
60 
61         return sInstance;
62     }
63 
setContext(Context context)64     public void setContext(Context context) {
65         mContext = context;
66     }
67 
68     /**
69      * Format contact number to the common format
70      *
71      * @param phoneNumber read from contact db.
72      * @return formatted contact number.
73      */
format(final String phoneNumber)74     public String format(final String phoneNumber) {
75         String number = phoneNumber;
76         if (TextUtils.isEmpty(number)) {
77             return null;
78         }
79 
80         if(number.startsWith("*67") || number.startsWith("*82")) {
81             number = number.substring(3);
82             if (TextUtils.isEmpty(number)) {
83                 return null;
84             }
85         }
86 
87         number = PhoneNumberUtils.stripSeparators(number);
88 
89         int len = number.length();
90         if (len == NUMBER_LENGTH_NO_AREA_CODE) {
91             number = addAreaCode(number);
92         }
93 
94         number = PhoneNumberUtils.normalizeNumber(number);
95 
96         len = number.length();
97         if (len == NUMBER_LENGTH_NORMAL) {
98             if (!number.startsWith("+1")) {
99                 number = "+1" + number;
100             }
101         } else if (len == NUMBER_LENGTH_NORMAL + 1) {
102             if (number.startsWith("1")) {
103                 number = "+" + number;
104             }
105         } else if(len >= NUMBER_LENGTH_NORMAL + 2) {
106             if ((len >= NUMBER_LENGTH_NORMAL + 4) && (number.startsWith("011"))) {
107                 number = "+" + number.substring(3);
108             }
109 
110             if (!number.startsWith("+")) {
111                 if (number.startsWith("1")) {
112                     number = "+" + number;;
113                 } else {
114                     number = "+1" + number;
115                 }
116             }
117         }
118 
119         if(number.length() > NUMBER_LENGTH_MAX) {
120             return null;
121         }
122 
123         return number;
124     }
125 
126     /**
127      * Contact nubmer error code.
128      */
129     public static int NUMBER_VALID = 0;
130     public static int NUMBER_EMERGENCY = 1;
131     public static int NUMBER_SHORT_CODE = 2;
132     public static int NUMBER_PRELOADED_ENTRY = 3;
133     public static int NUMBER_FREE_PHONE = 4;
134     public static int NUMBER_INVALID = 5;
135 
136     /**
137      * Check if it is a valid contact number for presence
138      *
139      * @param phoneNumber read from contact db.
140      * @return contact number error code.
141      */
validate(final String phoneNumber)142     public int validate(final String phoneNumber) {
143         String number = phoneNumber;
144         if (TextUtils.isEmpty(number)) {
145             return NUMBER_INVALID;
146         }
147 
148         if(number.startsWith("*67") || number.startsWith("*82")) {
149             number = number.substring(3);
150             if (TextUtils.isEmpty(number)) {
151                 return NUMBER_INVALID;
152             }
153         }
154 
155         if(number.contains("*")) {
156             return NUMBER_PRELOADED_ENTRY;
157         }
158 
159         number = PhoneNumberUtils.stripSeparators(number);
160         if (!number.equals(PhoneNumberUtils.convertKeypadLettersToDigits(number))) {
161             return NUMBER_INVALID;
162         }
163 
164         if (PhoneNumberUtils.isEmergencyNumber(number)) {
165             return NUMBER_EMERGENCY;
166         // TODO: To handle short code
167         //} else if ((mContext != null) && PhoneNumberUtils.isN11Number(mContext, number)) {
168         //    return NUMBER_SHORT_CODE;
169         } else if (number.startsWith("#")) {
170             return NUMBER_PRELOADED_ENTRY;
171         } else if (isInExcludedList(number)) {
172             return NUMBER_FREE_PHONE;
173         }
174 
175         int len = number.length();
176         if (len < NUMBER_LENGTH_NORMAL) {
177             return NUMBER_INVALID;
178         }
179 
180         number = format(number);
181         if (number.startsWith("+")) {
182             len = number.length();
183             // make sure the number after stripped the national number still be 10 digits
184             if (len >= NUMBER_LENGTH_NORMAL + 2) {
185                 return NUMBER_VALID;
186             }
187         }
188 
189         return NUMBER_INVALID;
190     }
191 
192 
193     /**
194      * Some utility functions for presence service only.
195      * @hide
196      */
format(List<String> numbers)197     public String[] format(List<String> numbers) {
198         if ((numbers == null) || (numbers.size() == 0)) {
199             return null;
200         }
201 
202         int size = numbers.size();
203         String[] outContactsArray = new String[size];
204         for (int i = 0; i < size; i++) {
205             String number = numbers.get(i);
206             outContactsArray[i] = format(number);
207             if (DEBUG) {
208                 Log.d(TAG, "outContactsArray[" + i + "] = " + outContactsArray[i]);
209             }
210         }
211 
212         return outContactsArray;
213     }
214 
format(String[] numbers)215     public String[] format(String[] numbers) {
216         if ((numbers == null) || (numbers.length == 0)) {
217             return null;
218         }
219 
220         int length = numbers.length;
221         String[] outContactsArray = new String[length];
222         for (int i = 0; i < length; i++) {
223             String number = numbers[i];
224             outContactsArray[i] = format(number);
225             if (DEBUG) {
226                 Log.d(TAG, "outContactsArray[" + i + "] = " + outContactsArray[i]);
227             }
228         }
229 
230         return outContactsArray;
231     }
validate(List<String> numbers)232     public int validate(List<String> numbers) {
233         if ((numbers == null) || (numbers.size() == 0)) {
234             return NUMBER_INVALID;
235         }
236 
237         int size = numbers.size();
238         for (int i = 0; i < size; i++) {
239             String number = numbers.get(i);
240             int result = validate(number);
241             if (result != NUMBER_VALID) {
242                 return result;
243             }
244         }
245 
246         return NUMBER_VALID;
247     }
248 
validate(String[] numbers)249     public int validate(String[] numbers) {
250         if ((numbers == null) || (numbers.length == 0)) {
251             return NUMBER_INVALID;
252         }
253 
254         int length = numbers.length;
255         for (int i = 0; i < length; i++) {
256             String number = numbers[i];
257             int result = validate(number);
258             if (result != NUMBER_VALID) {
259                 return result;
260             }
261         }
262 
263         return NUMBER_VALID;
264     }
265 
266     /**
267      * The logger related.
268      */
269     private static final boolean DEBUG = Build.IS_DEBUGGABLE;
270     private static final String TAG = "ContactNumberUtils";
271 
272     /**
273      * Contact number length.
274      */
275     // As per E164 the maximum number length should be 15.
276     // But as per implemention of libphonenumber it found longer length in Germany.
277     // So we use the same length as libphonenumber.
278     private int NUMBER_LENGTH_MAX = 17;
279     private int NUMBER_LENGTH_NORMAL = 10;
280     private int NUMBER_LENGTH_NO_AREA_CODE = 7;
281 
282     /**
283      * Save the singleton instance.
284      */
285     private static ContactNumberUtils sInstance = null;
286     private Context mContext = null;
287 
288     /**
289      * Constructor
290      */
ContactNumberUtils()291     private ContactNumberUtils() {
292         if (DEBUG) {
293             Log.d(TAG, "ContactNumberUtils constructor");
294         }
295     }
296 
297     /**
298      * Add device's own area code to the number which length is 7.
299      */
addAreaCode(String number)300     private String addAreaCode(String number) {
301         if (mContext == null) {
302             if (DEBUG) {
303                 Log.e(TAG, "mContext is null, please update context.");
304             }
305             return number;
306         }
307 
308         String mdn = null;
309         TelephonyManager tm = (TelephonyManager)
310                 mContext.getSystemService(Context.TELEPHONY_SERVICE);
311         mdn = tm.getLine1Number();
312 
313         if ((mdn == null) || (mdn.length() == 0) ||  mdn.startsWith("00000")) {
314             return number;
315         }
316 
317         mdn = PhoneNumberUtils.stripSeparators(mdn);
318         if (mdn.length() >= NUMBER_LENGTH_NORMAL) {
319             mdn = mdn.substring(mdn.length() - NUMBER_LENGTH_NORMAL);
320         }
321         mdn = mdn.substring(0, 3);
322 
323         number = mdn + number;
324         return number;
325     }
326 
327     /**
328      * The excluded number list.
329      */
330     private static ArrayList<String> sExcludes = null;
331 
isInExcludedList(String number)332     private boolean isInExcludedList(String number){
333         if (sExcludes == null) {
334             sExcludes = new ArrayList<String>();
335             sExcludes.add("800");
336             sExcludes.add("822");
337             sExcludes.add("833");
338             sExcludes.add("844");
339             sExcludes.add("855");
340             sExcludes.add("866");
341             sExcludes.add("877");
342             sExcludes.add("880882");
343             sExcludes.add("888");
344             sExcludes.add("900");
345             sExcludes.add("911");
346         }
347 
348         String tempNumber = format(number);
349         if(TextUtils.isEmpty(tempNumber)) {
350             return true; //exclude empty/null string.
351         }
352 
353         if(tempNumber.startsWith("1")) {
354             tempNumber = tempNumber.substring(1);
355         } else if(tempNumber.startsWith("+1")) {
356             tempNumber = tempNumber.substring(2);
357         }
358 
359         if(TextUtils.isEmpty(tempNumber)) {
360             return true; //exclude empty/null string.
361         }
362 
363         for (String num : sExcludes) {
364             if(tempNumber.startsWith(num)) {
365                 return true;
366             }
367         }
368 
369         return false;
370     }
371 }
372 
373