Home | History | Annotate | Download | only in internal
      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      */
     56     public static ContactNumberUtils getDefault() {
     57         if(sInstance == null) {
     58             sInstance = new ContactNumberUtils();
     59         }
     60 
     61         return sInstance;
     62     }
     63 
     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      */
     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      */
    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      */
    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 
    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     }
    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 
    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      */
    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      */
    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 
    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