1214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer/* 2214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer * Copyright (c) 2016, The Android Open Source Project 3214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer * 4214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer * Licensed under the Apache License, Version 2.0 (the "License"); 5214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer * you may not use this file except in compliance with the License. 6214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer * You may obtain a copy of the License at 7214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer * 8214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer * http://www.apache.org/licenses/LICENSE-2.0 9214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer * 10214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer * Unless required by applicable law or agreed to in writing, software 11214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer * distributed under the License is distributed on an "AS IS" BASIS, 12214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer * See the License for the specific language governing permissions and 14214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer * limitations under the License. 15214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer */ 16214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyerpackage com.android.car.stream.telecom; 17214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer 18214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyerimport android.content.ContentResolver; 19214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyerimport android.content.ContentUris; 20214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyerimport android.content.Context; 21214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyerimport android.content.res.Resources; 22214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyerimport android.database.Cursor; 23214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyerimport android.graphics.Bitmap; 24214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyerimport android.graphics.BitmapFactory; 25214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyerimport android.graphics.Rect; 26214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyerimport android.net.Uri; 27214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyerimport android.provider.ContactsContract; 28214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyerimport android.support.annotation.Nullable; 29214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyerimport android.support.annotation.WorkerThread; 30214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyerimport android.telecom.Call; 31214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyerimport android.telecom.GatewayInfo; 32214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyerimport android.telephony.PhoneNumberUtils; 33214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyerimport android.telephony.TelephonyManager; 34214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyerimport android.text.TextUtils; 35214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyerimport android.util.LruCache; 36214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyerimport com.android.car.apps.common.CircleBitmapDrawable; 37214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyerimport com.android.car.apps.common.LetterTileDrawable; 38214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyerimport com.android.car.stream.R; 39214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer 40214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyerimport java.io.InputStream; 41214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyerimport java.util.HashMap; 42214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyerimport java.util.Locale; 43214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer 44214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer/** 45214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer * Telecom related utility methods. 46214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer */ 47214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyerpublic class TelecomUtils { 48214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer private static final int LRU_CACHE_SIZE = 4194304; /** 4 mb **/ 49214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer 50214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer private static final String[] CONTACT_ID_PROJECTION = new String[] { 51214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer ContactsContract.PhoneLookup.DISPLAY_NAME, 52214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer ContactsContract.PhoneLookup.TYPE, 53214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer ContactsContract.PhoneLookup.LABEL, 54214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer ContactsContract.PhoneLookup._ID 55214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer }; 56214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer 57214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer private static String sVoicemailNumber; 58214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer 59214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer private static LruCache<String, Bitmap> sContactPhotoNumberCache; 60214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer private static LruCache<Long, Bitmap> sContactPhotoIdCache; 61214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer private static HashMap<String, String> sContactNameCache; 62214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer private static HashMap<String, Integer> sContactIdCache; 63214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer private static HashMap<String, String> sFormattedNumberCache; 64214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer private static HashMap<String, String> sDisplayNameCache; 65214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer 66214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer /** 67214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer * Create a round bitmap icon to represent the call. If a contact photo does not exist, 68214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer * a letter tile will be used instead. 69214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer */ 70214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer public static Bitmap createStreamCardSecondaryIcon(Context context, String number) { 71214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer Resources res = context.getResources(); 72214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer Bitmap largeIcon 73214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer = TelecomUtils.getContactPhotoFromNumber(context.getContentResolver(), number); 74214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer if (largeIcon == null) { 75214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer LetterTileDrawable ltd = new LetterTileDrawable(res); 76214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer String name = TelecomUtils.getDisplayName(context, number); 77214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer ltd.setContactDetails(name, number); 78214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer ltd.setIsCircular(true); 79214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer int size = res.getDimensionPixelSize(R.dimen.stream_card_secondary_icon_dimen); 80214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer largeIcon = ltd.toBitmap(size); 81214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer } 82214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer 83214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer return new CircleBitmapDrawable(res, largeIcon) 84214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer .toBitmap(res.getDimensionPixelSize(R.dimen.stream_card_secondary_icon_dimen)); 85214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer } 86214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer 87214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer 88214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer /** 89214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer * Fetch contact photo by number from local cache. 90214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer * 91214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer * @param number 92214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer * @return Contact photo if it's in the cache, otherwise null. 93214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer */ 94214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer @Nullable 95214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer public static Bitmap getCachedContactPhotoFromNumber(String number) { 96214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer if (number == null) { 97214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer return null; 98214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer } 99214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer 100214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer if (sContactPhotoNumberCache == null) { 101214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer sContactPhotoNumberCache = new LruCache<String, Bitmap>(LRU_CACHE_SIZE) { 102214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer @Override 103214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer protected int sizeOf(String key, Bitmap value) { 104214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer return value.getByteCount(); 105214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer } 106214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer }; 107214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer } 108214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer return sContactPhotoNumberCache.get(number); 109214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer } 110214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer 111214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer @WorkerThread 112214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer public static Bitmap getContactPhotoFromNumber(ContentResolver contentResolver, String number) { 113214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer if (number == null) { 114214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer return null; 115214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer } 116214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer 117214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer Bitmap photo = getCachedContactPhotoFromNumber(number); 118214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer if (photo != null) { 119214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer return photo; 120214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer } 121214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer 122214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer int id = getContactIdFromNumber(contentResolver, number); 123214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer if (id == 0) { 124214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer return null; 125214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer } 126214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer photo = getContactPhotoFromId(contentResolver, id); 127214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer if (photo != null) { 128214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer sContactPhotoNumberCache.put(number, photo); 129214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer } 130214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer return photo; 131214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer } 132214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer 133214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer /** 134214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer * Return the contact id for the given contact id 135214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer * @param id the contact id to get the photo for 136214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer * @return the contact photo if it is found, null otherwise. 137214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer */ 138214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer public static Bitmap getContactPhotoFromId(ContentResolver contentResolver, long id) { 139214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer if (sContactPhotoIdCache == null) { 140214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer sContactPhotoIdCache = new LruCache<Long, Bitmap>(LRU_CACHE_SIZE) { 141214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer @Override 142214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer protected int sizeOf(Long key, Bitmap value) { 143214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer return value.getByteCount(); 144214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer } 145214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer }; 146214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer } else if (sContactPhotoIdCache.get(id) != null) { 147214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer return sContactPhotoIdCache.get(id); 148214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer } 149214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer 150214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer Uri photoUri = ContentUris.withAppendedId(ContactsContract.Contacts.CONTENT_URI, id); 151214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer InputStream photoDataStream = ContactsContract.Contacts.openContactPhotoInputStream( 152214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer contentResolver, photoUri, true); 153214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer 154214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer BitmapFactory.Options options = new BitmapFactory.Options(); 155214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer options.inPreferQualityOverSpeed = true; 156214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer // Scaling will be handled by later. We shouldn't scale multiple times to avoid 157214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer // quality lost due to multiple potential scaling up and down. 158214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer options.inScaled = false; 159214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer 160214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer Rect nullPadding = null; 161214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer Bitmap photo = BitmapFactory.decodeStream(photoDataStream, nullPadding, options); 162214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer if (photo != null) { 163214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer photo.setDensity(Bitmap.DENSITY_NONE); 164214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer sContactPhotoIdCache.put(id, photo); 165214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer } 166214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer return photo; 167214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer } 168214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer 169214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer /** 170214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer * Return the contact id for the given phone number. 171214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer * @param number Caller phone number 172214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer * @return the contact id if it is found, 0 otherwise. 173214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer */ 174214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer public static int getContactIdFromNumber(ContentResolver cr, String number) { 175214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer if (number == null || number.isEmpty()) { 176214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer return 0; 177214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer } 178214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer if (sContactIdCache == null) { 179214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer sContactIdCache = new HashMap<>(); 180214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer } else if (sContactIdCache.containsKey(number)) { 181214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer return sContactIdCache.get(number); 182214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer } 183214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer 184214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer Uri uri = Uri.withAppendedPath( 185214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer ContactsContract.PhoneLookup.CONTENT_FILTER_URI, 186214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer Uri.encode(number)); 187214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer Cursor cursor = cr.query(uri, CONTACT_ID_PROJECTION, null, null, null); 188214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer 189214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer try { 190214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer if (cursor != null && cursor.moveToFirst()) { 191214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer int id = cursor.getInt(cursor.getColumnIndex(ContactsContract.PhoneLookup._ID)); 192214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer sContactIdCache.put(number, id); 193214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer return id; 194214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer } 195214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer } 196214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer finally { 197214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer if (cursor != null) { 198214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer cursor.close(); 199214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer } 200214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer } 201214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer return 0; 202214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer } 203214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer 204214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer public static String getDisplayName(Context context, String number) { 205214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer return getDisplayName(context, number, (Uri)null); 206214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer } 207214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer 208214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer public static String getDisplayName(Context context, Call call) { 209214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer // A call might get created before its children are added. In that case, the display name 210214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer // would go from "Unknown" to "Conference call" therefore we don't want to cache it. 211214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer if (call.getChildren() != null && call.getChildren().size() > 0) { 212214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer return context.getString(R.string.conference_call); 213214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer } 214214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer return getDisplayName(context, getNumber(call), getGatewayInfoOriginalAddress(call)); 215214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer } 216214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer 217214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer private static Uri getGatewayInfoOriginalAddress(Call call) { 218214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer if (call == null || call.getDetails() == null) { 219214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer return null; 220214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer } 221214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer GatewayInfo gatewayInfo = call.getDetails().getGatewayInfo(); 222214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer 223214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer if (gatewayInfo != null && gatewayInfo.getOriginalAddress() != null) { 224214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer return gatewayInfo.getGatewayAddress(); 225214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer } 226214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer return null; 227214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer } 228214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer 229214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer /** 230214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer * Return the phone number of the call. This CAN return null under certain circumstances such 231214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer * as if the incoming number is hidden. 232214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer */ 233214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer public static String getNumber(Call call) { 234214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer if (call == null || call.getDetails() == null) { 235214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer return null; 236214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer } 237214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer 238214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer Uri gatewayInfoOriginalAddress = getGatewayInfoOriginalAddress(call); 239214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer if (gatewayInfoOriginalAddress != null) { 240214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer return gatewayInfoOriginalAddress.getSchemeSpecificPart(); 241214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer } 242214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer 243214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer if (call.getDetails().getHandle() != null) { 244214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer return call.getDetails().getHandle().getSchemeSpecificPart(); 245214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer } 246214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer return null; 247214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer } 248214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer 249214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer private static String getContactNameFromNumber(ContentResolver cr, String number) { 250214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer if (sContactNameCache == null) { 251214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer sContactNameCache = new HashMap<>(); 252214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer } else if (sContactNameCache.containsKey(number)) { 253214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer return sContactNameCache.get(number); 254214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer } 255214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer 256214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer Uri uri = Uri.withAppendedPath( 257214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer ContactsContract.PhoneLookup.CONTENT_FILTER_URI, Uri.encode(number)); 258214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer 259214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer Cursor cursor = null; 260214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer String name = null; 261214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer try { 262214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer cursor = cr.query(uri, 263214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer new String[] {ContactsContract.PhoneLookup.DISPLAY_NAME}, null, null, null); 264214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer if (cursor != null && cursor.moveToFirst()) { 265214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer name = cursor.getString(0); 266214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer sContactNameCache.put(number, name); 267214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer } 268214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer } finally { 269214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer if (cursor != null) { 270214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer cursor.close(); 271214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer } 272214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer } 273214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer return name; 274214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer } 275214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer 276214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer private static String getDisplayName( 277214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer Context context, String number, Uri gatewayOriginalAddress) { 278214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer if (sDisplayNameCache == null) { 279214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer sDisplayNameCache = new HashMap<>(); 280214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer } else { 281214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer if (sDisplayNameCache.containsKey(number)) { 282214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer return sDisplayNameCache.get(number); 283214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer } 284214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer } 285214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer 286214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer if (TextUtils.isEmpty(number)) { 287214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer return context.getString(R.string.unknown); 288214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer } 289214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer ContentResolver cr = context.getContentResolver(); 290214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer String name; 291214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer if (number.equals(getVoicemailNumber(context))) { 292214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer name = context.getString(R.string.voicemail); 293214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer } else { 294214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer name = getContactNameFromNumber(cr, number); 295214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer } 296214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer 297214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer if (name == null) { 298214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer name = getFormattedNumber(context, number); 299214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer } 300214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer if (name == null && gatewayOriginalAddress != null) { 301214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer name = gatewayOriginalAddress.getSchemeSpecificPart(); 302214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer } 303214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer if (name == null) { 304214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer name = context.getString(R.string.unknown); 305214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer } 306214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer sDisplayNameCache.put(number, name); 307214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer return name; 308214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer } 309214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer 310214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer public static String getVoicemailNumber(Context context) { 311214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer if (sVoicemailNumber == null) { 312214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer TelephonyManager tm = 313214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); 314214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer sVoicemailNumber = tm.getVoiceMailNumber(); 315214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer } 316214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer return sVoicemailNumber; 317214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer } 318214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer 319214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer public static String getFormattedNumber(Context context, @Nullable String number) { 320214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer if (TextUtils.isEmpty(number)) { 321214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer return ""; 322214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer } 323214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer 324214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer if (sFormattedNumberCache == null) { 325214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer sFormattedNumberCache = new HashMap<>(); 326214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer } else { 327214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer if (sFormattedNumberCache.containsKey(number)) { 328214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer return sFormattedNumberCache.get(number); 329214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer } 330214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer } 331214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer 332214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer String countryIso = getSimRegionCode(context); 333214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer String e164 = PhoneNumberUtils.formatNumberToE164(number, countryIso); 334214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer String formattedNumber = PhoneNumberUtils.formatNumber(number, e164, countryIso); 335214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer formattedNumber = TextUtils.isEmpty(formattedNumber) ? number : formattedNumber; 336214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer sFormattedNumberCache.put(number, formattedNumber); 337214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer return formattedNumber; 338214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer } 339214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer 340214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer /** 341214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer * Wrapper around TelephonyManager.getSimCountryIso() that will fallback to locale or USA ISOs 342214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer * if it finds bogus data. 343214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer */ 344214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer private static String getSimRegionCode(Context context) { 345214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer TelephonyManager telephonyManager = 346214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); 347214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer 348214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer // This can be null on some phones (and is null on robolectric default TelephonyManager) 349214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer String countryIso = telephonyManager.getSimCountryIso(); 350214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer if (TextUtils.isEmpty(countryIso) || countryIso.length() != 2) { 351214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer countryIso = Locale.getDefault().getCountry(); 352214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer if (countryIso == null || countryIso.length() != 2) { 353214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer countryIso = "US"; 354214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer } 355214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer } 356214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer 357214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer return countryIso.toUpperCase(Locale.US); 358214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer } 359214c10ceef4ba736d8a7b3cbef06c27826822946Rakesh Iyer}