1a4745bddb3a012c826225df313820ccd8a68455dtwyen/* 2a4745bddb3a012c826225df313820ccd8a68455dtwyen * Copyright (C) 2015 The Android Open Source Project 3a4745bddb3a012c826225df313820ccd8a68455dtwyen * 4a4745bddb3a012c826225df313820ccd8a68455dtwyen * Licensed under the Apache License, Version 2.0 (the "License"); 5a4745bddb3a012c826225df313820ccd8a68455dtwyen * you may not use this file except in compliance with the License. 6a4745bddb3a012c826225df313820ccd8a68455dtwyen * You may obtain a copy of the License at 7a4745bddb3a012c826225df313820ccd8a68455dtwyen * 8a4745bddb3a012c826225df313820ccd8a68455dtwyen * http://www.apache.org/licenses/LICENSE-2.0 9a4745bddb3a012c826225df313820ccd8a68455dtwyen * 10a4745bddb3a012c826225df313820ccd8a68455dtwyen * Unless required by applicable law or agreed to in writing, software 11a4745bddb3a012c826225df313820ccd8a68455dtwyen * distributed under the License is distributed on an "AS IS" BASIS, 12a4745bddb3a012c826225df313820ccd8a68455dtwyen * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13a4745bddb3a012c826225df313820ccd8a68455dtwyen * See the License for the specific language governing permissions and 14a4745bddb3a012c826225df313820ccd8a68455dtwyen * limitations under the License. 15a4745bddb3a012c826225df313820ccd8a68455dtwyen */ 16a4745bddb3a012c826225df313820ccd8a68455dtwyen 17a4745bddb3a012c826225df313820ccd8a68455dtwyenpackage com.android.dialer.telecom; 18a4745bddb3a012c826225df313820ccd8a68455dtwyen 19a4745bddb3a012c826225df313820ccd8a68455dtwyenimport android.content.Context; 20a4745bddb3a012c826225df313820ccd8a68455dtwyenimport android.net.Uri; 21a4745bddb3a012c826225df313820ccd8a68455dtwyenimport android.support.annotation.NonNull; 22a4745bddb3a012c826225df313820ccd8a68455dtwyenimport android.support.annotation.Nullable; 23a4745bddb3a012c826225df313820ccd8a68455dtwyenimport android.support.annotation.WorkerThread; 24a4745bddb3a012c826225df313820ccd8a68455dtwyenimport android.telecom.Call; 25a4745bddb3a012c826225df313820ccd8a68455dtwyenimport android.telecom.PhoneAccountHandle; 26a4745bddb3a012c826225df313820ccd8a68455dtwyenimport android.telephony.PhoneNumberUtils; 27a4745bddb3a012c826225df313820ccd8a68455dtwyenimport android.telephony.SubscriptionInfo; 28a4745bddb3a012c826225df313820ccd8a68455dtwyenimport android.text.TextUtils; 29a4745bddb3a012c826225df313820ccd8a68455dtwyenimport com.android.dialer.common.Assert; 30a4745bddb3a012c826225df313820ccd8a68455dtwyenimport com.android.dialer.common.LogUtil; 31a4745bddb3a012c826225df313820ccd8a68455dtwyenimport com.google.common.base.Optional; 32a4745bddb3a012c826225df313820ccd8a68455dtwyenimport java.util.Locale; 33a4745bddb3a012c826225df313820ccd8a68455dtwyen 34a4745bddb3a012c826225df313820ccd8a68455dtwyen/** 35a4745bddb3a012c826225df313820ccd8a68455dtwyen * Class to provide a standard interface for obtaining information from the underlying 36a4745bddb3a012c826225df313820ccd8a68455dtwyen * android.telecom.Call. Much of this should be obtained through the incall.Call, but on occasion we 37a4745bddb3a012c826225df313820ccd8a68455dtwyen * need to interact with the telecom.Call directly (eg. call blocking, before the incall.Call has 38a4745bddb3a012c826225df313820ccd8a68455dtwyen * been created). 39a4745bddb3a012c826225df313820ccd8a68455dtwyen */ 40a4745bddb3a012c826225df313820ccd8a68455dtwyenpublic class TelecomCallUtil { 41a4745bddb3a012c826225df313820ccd8a68455dtwyen 42a4745bddb3a012c826225df313820ccd8a68455dtwyen /** Returns Whether the call handle is an emergency number. */ 43a4745bddb3a012c826225df313820ccd8a68455dtwyen public static boolean isEmergencyCall(@NonNull Call call) { 44a4745bddb3a012c826225df313820ccd8a68455dtwyen Assert.isNotNull(call); 45a4745bddb3a012c826225df313820ccd8a68455dtwyen Uri handle = call.getDetails().getHandle(); 46a4745bddb3a012c826225df313820ccd8a68455dtwyen return PhoneNumberUtils.isEmergencyNumber(handle == null ? "" : handle.getSchemeSpecificPart()); 47a4745bddb3a012c826225df313820ccd8a68455dtwyen } 48a4745bddb3a012c826225df313820ccd8a68455dtwyen 49a4745bddb3a012c826225df313820ccd8a68455dtwyen /** 50a4745bddb3a012c826225df313820ccd8a68455dtwyen * Returns The phone number which the {@code Call} is currently connected, or {@code null} if the 51a4745bddb3a012c826225df313820ccd8a68455dtwyen * number is not available. 52a4745bddb3a012c826225df313820ccd8a68455dtwyen */ 53a4745bddb3a012c826225df313820ccd8a68455dtwyen @Nullable 54a4745bddb3a012c826225df313820ccd8a68455dtwyen public static String getNumber(@Nullable Call call) { 55a4745bddb3a012c826225df313820ccd8a68455dtwyen if (call == null) { 56a4745bddb3a012c826225df313820ccd8a68455dtwyen return null; 57a4745bddb3a012c826225df313820ccd8a68455dtwyen } 58a4745bddb3a012c826225df313820ccd8a68455dtwyen if (call.getDetails().getGatewayInfo() != null) { 59a4745bddb3a012c826225df313820ccd8a68455dtwyen return call.getDetails().getGatewayInfo().getOriginalAddress().getSchemeSpecificPart(); 60a4745bddb3a012c826225df313820ccd8a68455dtwyen } 61a4745bddb3a012c826225df313820ccd8a68455dtwyen Uri handle = getHandle(call); 62a4745bddb3a012c826225df313820ccd8a68455dtwyen return handle == null ? null : handle.getSchemeSpecificPart(); 63a4745bddb3a012c826225df313820ccd8a68455dtwyen } 64a4745bddb3a012c826225df313820ccd8a68455dtwyen 65a4745bddb3a012c826225df313820ccd8a68455dtwyen /** 66a4745bddb3a012c826225df313820ccd8a68455dtwyen * Returns The handle (e.g., phone number) to which the {@code Call} is currently connected, or 67a4745bddb3a012c826225df313820ccd8a68455dtwyen * {@code null} if the number is not available. 68a4745bddb3a012c826225df313820ccd8a68455dtwyen */ 69a4745bddb3a012c826225df313820ccd8a68455dtwyen @Nullable 70a4745bddb3a012c826225df313820ccd8a68455dtwyen public static Uri getHandle(@Nullable Call call) { 71a4745bddb3a012c826225df313820ccd8a68455dtwyen return call == null ? null : call.getDetails().getHandle(); 72a4745bddb3a012c826225df313820ccd8a68455dtwyen } 73a4745bddb3a012c826225df313820ccd8a68455dtwyen 74a4745bddb3a012c826225df313820ccd8a68455dtwyen /** 75e3b74d22b4e92009433e07f29973f53fb90613e1zachh * Normalizes the number of the {@code call} to E.164. The country of the SIM associated with the 76e3b74d22b4e92009433e07f29973f53fb90613e1zachh * call is used to determine the country. 77e3b74d22b4e92009433e07f29973f53fb90613e1zachh * 78e3b74d22b4e92009433e07f29973f53fb90613e1zachh * <p>If the number cannot be formatted (because for example the country cannot be determined), 79e3b74d22b4e92009433e07f29973f53fb90613e1zachh * returns the number with non-dialable digits removed. 80a4745bddb3a012c826225df313820ccd8a68455dtwyen */ 81a4745bddb3a012c826225df313820ccd8a68455dtwyen @WorkerThread 82a4745bddb3a012c826225df313820ccd8a68455dtwyen public static Optional<String> getNormalizedNumber(Context appContext, Call call) { 83a4745bddb3a012c826225df313820ccd8a68455dtwyen Assert.isWorkerThread(); 84e3b74d22b4e92009433e07f29973f53fb90613e1zachh 85a240266106bf99780a48d86883499dbebd20fbdazachh Optional<String> validE164 = getValidE164Number(appContext, call); 86a240266106bf99780a48d86883499dbebd20fbdazachh if (validE164.isPresent()) { 87a240266106bf99780a48d86883499dbebd20fbdazachh return validE164; 88e3b74d22b4e92009433e07f29973f53fb90613e1zachh } 89e3b74d22b4e92009433e07f29973f53fb90613e1zachh String rawNumber = getNumber(call); 90e3b74d22b4e92009433e07f29973f53fb90613e1zachh if (TextUtils.isEmpty(rawNumber)) { 91e3b74d22b4e92009433e07f29973f53fb90613e1zachh return Optional.absent(); 92e3b74d22b4e92009433e07f29973f53fb90613e1zachh } 93e3b74d22b4e92009433e07f29973f53fb90613e1zachh return Optional.of(PhoneNumberUtils.normalizeNumber(rawNumber)); 94e3b74d22b4e92009433e07f29973f53fb90613e1zachh } 95e3b74d22b4e92009433e07f29973f53fb90613e1zachh 96e3b74d22b4e92009433e07f29973f53fb90613e1zachh /** 97a240266106bf99780a48d86883499dbebd20fbdazachh * Formats the number of the {@code call} to E.164 if it is valid. The country of the SIM 98a240266106bf99780a48d86883499dbebd20fbdazachh * associated with the call is used to determine the country. 99e3b74d22b4e92009433e07f29973f53fb90613e1zachh * 100a240266106bf99780a48d86883499dbebd20fbdazachh * <p>If the number cannot be formatted (because for example it is invalid or the country cannot 101a240266106bf99780a48d86883499dbebd20fbdazachh * be determined), returns {@link Optional#absent()}. 102e3b74d22b4e92009433e07f29973f53fb90613e1zachh */ 103e3b74d22b4e92009433e07f29973f53fb90613e1zachh @WorkerThread 104a240266106bf99780a48d86883499dbebd20fbdazachh public static Optional<String> getValidE164Number(Context appContext, Call call) { 105e3b74d22b4e92009433e07f29973f53fb90613e1zachh Assert.isWorkerThread(); 106a4745bddb3a012c826225df313820ccd8a68455dtwyen String rawNumber = getNumber(call); 107a4745bddb3a012c826225df313820ccd8a68455dtwyen if (TextUtils.isEmpty(rawNumber)) { 108a4745bddb3a012c826225df313820ccd8a68455dtwyen return Optional.absent(); 109a4745bddb3a012c826225df313820ccd8a68455dtwyen } 110fb112d870c3a564d2dcb0e72dcdcabb6e0375520twyen Optional<String> countryCode = getCountryCode(appContext, call); 111fb112d870c3a564d2dcb0e72dcdcabb6e0375520twyen if (!countryCode.isPresent()) { 112a240266106bf99780a48d86883499dbebd20fbdazachh LogUtil.w("TelecomCallUtil.getValidE164Number", "couldn't find a country code for call"); 113e3b74d22b4e92009433e07f29973f53fb90613e1zachh return Optional.absent(); 114a4745bddb3a012c826225df313820ccd8a68455dtwyen } 115fb112d870c3a564d2dcb0e72dcdcabb6e0375520twyen return Optional.fromNullable(PhoneNumberUtils.formatNumberToE164(rawNumber, countryCode.get())); 116fb112d870c3a564d2dcb0e72dcdcabb6e0375520twyen } 117fb112d870c3a564d2dcb0e72dcdcabb6e0375520twyen 118fb112d870c3a564d2dcb0e72dcdcabb6e0375520twyen @WorkerThread 119fb112d870c3a564d2dcb0e72dcdcabb6e0375520twyen public static Optional<String> getCountryCode(Context appContext, Call call) { 120fb112d870c3a564d2dcb0e72dcdcabb6e0375520twyen Assert.isWorkerThread(); 121fb112d870c3a564d2dcb0e72dcdcabb6e0375520twyen PhoneAccountHandle phoneAccountHandle = call.getDetails().getAccountHandle(); 122fb112d870c3a564d2dcb0e72dcdcabb6e0375520twyen Optional<SubscriptionInfo> subscriptionInfo = 123fb112d870c3a564d2dcb0e72dcdcabb6e0375520twyen TelecomUtil.getSubscriptionInfo(appContext, phoneAccountHandle); 124fb112d870c3a564d2dcb0e72dcdcabb6e0375520twyen if (subscriptionInfo.isPresent() && subscriptionInfo.get().getCountryIso() != null) { 125fb112d870c3a564d2dcb0e72dcdcabb6e0375520twyen return Optional.of(subscriptionInfo.get().getCountryIso().toUpperCase(Locale.US)); 126fb112d870c3a564d2dcb0e72dcdcabb6e0375520twyen } 127fb112d870c3a564d2dcb0e72dcdcabb6e0375520twyen return Optional.absent(); 128a4745bddb3a012c826225df313820ccd8a68455dtwyen } 129a4745bddb3a012c826225df313820ccd8a68455dtwyen} 130