Home | History | Annotate | Download | only in util
      1 /*
      2  * Copyright (C) 2012 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.contacts.common.util;
     18 
     19 import static android.provider.ContactsContract.CommonDataKinds.Phone;
     20 
     21 import android.content.Context;
     22 import android.telephony.PhoneNumberUtils;
     23 import android.text.Spannable;
     24 import android.text.SpannableString;
     25 import android.text.style.TtsSpan;
     26 import android.util.Log;
     27 import android.util.Patterns;
     28 
     29 import com.android.contacts.common.R;
     30 
     31 import com.android.i18n.phonenumbers.NumberParseException;
     32 import com.android.i18n.phonenumbers.PhoneNumberUtil;
     33 import com.android.i18n.phonenumbers.Phonenumber.PhoneNumber;
     34 import com.google.common.base.Preconditions;
     35 
     36 /**
     37  * Methods for handling various contact data labels.
     38  */
     39 public class ContactDisplayUtils {
     40 
     41     private static final String TAG = ContactDisplayUtils.class.getSimpleName();
     42 
     43     public static final int INTERACTION_CALL = 1;
     44     public static final int INTERACTION_SMS = 2;
     45 
     46     /**
     47      * Checks if the given data type is a custom type.
     48      *
     49      * @param type Phone data type.
     50      * @return {@literal true} if the type is custom.  {@literal false} if not.
     51      */
     52     public static boolean isCustomPhoneType(Integer type) {
     53         return type == Phone.TYPE_CUSTOM || type == Phone.TYPE_ASSISTANT;
     54     }
     55 
     56     /**
     57      * Gets a display label for a given phone type.
     58      *
     59      * @param type The type of number.
     60      * @param customLabel A custom label to use if the phone is determined to be of custom type
     61      * determined by {@link #isCustomPhoneType(Integer))}
     62      * @param interactionType whether this is a call or sms.  Either {@link #INTERACTION_CALL} or
     63      * {@link #INTERACTION_SMS}.
     64      * @param context The application context.
     65      * @return An appropriate string label
     66      */
     67     public static CharSequence getLabelForCallOrSms(Integer type, CharSequence customLabel,
     68             int interactionType, Context context) {
     69         Preconditions.checkNotNull(context);
     70 
     71         if (isCustomPhoneType(type)) {
     72             return (customLabel == null) ? "" : customLabel;
     73         } else {
     74             int resId;
     75             if (interactionType == INTERACTION_SMS) {
     76                 resId = getSmsLabelResourceId(type);
     77             } else {
     78                 resId = getPhoneLabelResourceId(type);
     79                 if (interactionType != INTERACTION_CALL) {
     80                     Log.e(TAG, "Un-recognized interaction type: " + interactionType +
     81                             ". Defaulting to ContactDisplayUtils.INTERACTION_CALL.");
     82                 }
     83             }
     84 
     85             return context.getResources().getText(resId);
     86         }
     87     }
     88 
     89     /**
     90      * Find a label for calling.
     91      *
     92      * @param type The type of number.
     93      * @return An appropriate string label.
     94      */
     95     public static int getPhoneLabelResourceId(Integer type) {
     96         if (type == null) return R.string.call_other;
     97         switch (type) {
     98             case Phone.TYPE_HOME:
     99                 return R.string.call_home;
    100             case Phone.TYPE_MOBILE:
    101                 return R.string.call_mobile;
    102             case Phone.TYPE_WORK:
    103                 return R.string.call_work;
    104             case Phone.TYPE_FAX_WORK:
    105                 return R.string.call_fax_work;
    106             case Phone.TYPE_FAX_HOME:
    107                 return R.string.call_fax_home;
    108             case Phone.TYPE_PAGER:
    109                 return R.string.call_pager;
    110             case Phone.TYPE_OTHER:
    111                 return R.string.call_other;
    112             case Phone.TYPE_CALLBACK:
    113                 return R.string.call_callback;
    114             case Phone.TYPE_CAR:
    115                 return R.string.call_car;
    116             case Phone.TYPE_COMPANY_MAIN:
    117                 return R.string.call_company_main;
    118             case Phone.TYPE_ISDN:
    119                 return R.string.call_isdn;
    120             case Phone.TYPE_MAIN:
    121                 return R.string.call_main;
    122             case Phone.TYPE_OTHER_FAX:
    123                 return R.string.call_other_fax;
    124             case Phone.TYPE_RADIO:
    125                 return R.string.call_radio;
    126             case Phone.TYPE_TELEX:
    127                 return R.string.call_telex;
    128             case Phone.TYPE_TTY_TDD:
    129                 return R.string.call_tty_tdd;
    130             case Phone.TYPE_WORK_MOBILE:
    131                 return R.string.call_work_mobile;
    132             case Phone.TYPE_WORK_PAGER:
    133                 return R.string.call_work_pager;
    134             case Phone.TYPE_ASSISTANT:
    135                 return R.string.call_assistant;
    136             case Phone.TYPE_MMS:
    137                 return R.string.call_mms;
    138             default:
    139                 return R.string.call_custom;
    140         }
    141 
    142     }
    143 
    144     /**
    145      * Find a label for sending an sms.
    146      *
    147      * @param type The type of number.
    148      * @return An appropriate string label.
    149      */
    150     public static int getSmsLabelResourceId(Integer type) {
    151         if (type == null) return R.string.sms_other;
    152         switch (type) {
    153             case Phone.TYPE_HOME:
    154                 return R.string.sms_home;
    155             case Phone.TYPE_MOBILE:
    156                 return R.string.sms_mobile;
    157             case Phone.TYPE_WORK:
    158                 return R.string.sms_work;
    159             case Phone.TYPE_FAX_WORK:
    160                 return R.string.sms_fax_work;
    161             case Phone.TYPE_FAX_HOME:
    162                 return R.string.sms_fax_home;
    163             case Phone.TYPE_PAGER:
    164                 return R.string.sms_pager;
    165             case Phone.TYPE_OTHER:
    166                 return R.string.sms_other;
    167             case Phone.TYPE_CALLBACK:
    168                 return R.string.sms_callback;
    169             case Phone.TYPE_CAR:
    170                 return R.string.sms_car;
    171             case Phone.TYPE_COMPANY_MAIN:
    172                 return R.string.sms_company_main;
    173             case Phone.TYPE_ISDN:
    174                 return R.string.sms_isdn;
    175             case Phone.TYPE_MAIN:
    176                 return R.string.sms_main;
    177             case Phone.TYPE_OTHER_FAX:
    178                 return R.string.sms_other_fax;
    179             case Phone.TYPE_RADIO:
    180                 return R.string.sms_radio;
    181             case Phone.TYPE_TELEX:
    182                 return R.string.sms_telex;
    183             case Phone.TYPE_TTY_TDD:
    184                 return R.string.sms_tty_tdd;
    185             case Phone.TYPE_WORK_MOBILE:
    186                 return R.string.sms_work_mobile;
    187             case Phone.TYPE_WORK_PAGER:
    188                 return R.string.sms_work_pager;
    189             case Phone.TYPE_ASSISTANT:
    190                 return R.string.sms_assistant;
    191             case Phone.TYPE_MMS:
    192                 return R.string.sms_mms;
    193             default:
    194                 return R.string.sms_custom;
    195         }
    196     }
    197 
    198     /**
    199      * Whether the given text could be a phone number.
    200      *
    201      * Note this will miss many things that are legitimate phone numbers, for example,
    202      * phone numbers with letters.
    203      */
    204     public static boolean isPossiblePhoneNumber(CharSequence text) {
    205         return text == null ? false : Patterns.PHONE.matcher(text.toString()).matches();
    206     }
    207 
    208     /**
    209      * Returns a Spannable for the given phone number with a telephone {@link TtsSpan} set over
    210      * the entire length of the given phone number.
    211      */
    212     public static Spannable getTelephoneTtsSpannable(String phoneNumber) {
    213         if (phoneNumber == null) {
    214             return null;
    215         }
    216         final Spannable spannable = new SpannableString(phoneNumber);
    217         final TtsSpan ttsSpan = getTelephoneTtsSpan(phoneNumber);
    218         spannable.setSpan(ttsSpan, 0, phoneNumber.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
    219         return spannable;
    220     }
    221 
    222     /**
    223      * Returns a Spannable for the given message with a telephone {@link TtsSpan} set for
    224      * the given phone number text wherever it is found within the message.
    225      */
    226     public static Spannable getTelephoneTtsSpannable(String message, String phoneNumber) {
    227         if (message == null) {
    228             return null;
    229         }
    230         final Spannable spannable = new SpannableString(message);
    231         int start = phoneNumber == null ? -1 : message.indexOf(phoneNumber);
    232         while (start >= 0) {
    233             final int end = start + phoneNumber.length();
    234             final TtsSpan ttsSpan = getTelephoneTtsSpan(phoneNumber);
    235             spannable.setSpan(ttsSpan, start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
    236             start = message.indexOf(phoneNumber, end);
    237         }
    238         return spannable;
    239     }
    240 
    241     /**
    242      * Returns a telephone {@link TtsSpan} for the given phone number.
    243      */
    244     public static TtsSpan getTelephoneTtsSpan(String phoneNumberString) {
    245         if (phoneNumberString == null) {
    246             throw new NullPointerException();
    247         }
    248 
    249         // Parse the phone number
    250         final PhoneNumberUtil phoneNumberUtil = PhoneNumberUtil.getInstance();
    251         PhoneNumber phoneNumber = null;
    252         try {
    253             // Don't supply a defaultRegion so this fails for non-international numbers because
    254             // we don't want to TalkBalk to read a country code (e.g. +1) if it is not already
    255             // present
    256             phoneNumber = phoneNumberUtil.parse(phoneNumberString, /* defaultRegion */ null);
    257         } catch (NumberParseException ignored) {
    258         }
    259 
    260         // Build a telephone tts span
    261         final TtsSpan.TelephoneBuilder builder = new TtsSpan.TelephoneBuilder();
    262         if (phoneNumber == null) {
    263             // Strip separators otherwise TalkBack will be silent
    264             // (this behavior was observed with TalkBalk 4.0.2 from their alpha channel)
    265             builder.setNumberParts(PhoneNumberUtils.stripSeparators(phoneNumberString));
    266         } else {
    267             if (phoneNumber.hasCountryCode()) {
    268                 builder.setCountryCode(Integer.toString(phoneNumber.getCountryCode()));
    269             }
    270             builder.setNumberParts(Long.toString(phoneNumber.getNationalNumber()));
    271         }
    272         return builder.build();
    273     }
    274 }
    275