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}