225 lines
8.5 KiB
Java
225 lines
8.5 KiB
Java
/*
|
|
* Copyright (C) 2022 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
package com.android.internal.telephony;
|
|
|
|
import android.text.TextUtils;
|
|
|
|
import com.android.i18n.phonenumbers.NumberParseException;
|
|
import com.android.i18n.phonenumbers.PhoneNumberUtil;
|
|
import com.android.i18n.phonenumbers.PhoneNumberUtil.PhoneNumberFormat;
|
|
import com.android.i18n.phonenumbers.Phonenumber.PhoneNumber;
|
|
import com.android.internal.annotations.VisibleForTesting;
|
|
import com.android.internal.telephony.uicc.AdnRecord;
|
|
import com.android.internal.telephony.uicc.AdnRecordCache;
|
|
import com.android.internal.telephony.uicc.IccConstants;
|
|
import com.android.internal.telephony.uicc.IccRecords;
|
|
import com.android.internal.telephony.uicc.UiccCardApplication;
|
|
import com.android.internal.telephony.uicc.UiccController;
|
|
import com.android.internal.telephony.uicc.UiccProfile;
|
|
import com.android.telephony.Rlog;
|
|
|
|
import java.util.ArrayList;
|
|
import java.util.regex.PatternSyntaxException;
|
|
|
|
/**
|
|
* This is a basic utility class for common functions related to Fixed Dialing Numbers
|
|
* designed as per 3GPP 22.101.
|
|
*/
|
|
public class FdnUtils {
|
|
private static final boolean VDBG = false;
|
|
private static final String LOG_TAG = FdnUtils.class.getSimpleName();
|
|
|
|
/**
|
|
* The following function checks if dialed number is blocked due to FDN.
|
|
*
|
|
* @param phoneId The phone object id for which the FDN check is performed
|
|
* @param dialStr dialed phone number
|
|
* @param defaultCountryIso country ISO for the subscription associated with this phone
|
|
* @return {@code true} if dialStr is blocked due to FDN check.
|
|
*/
|
|
public static boolean isNumberBlockedByFDN(int phoneId, String dialStr,
|
|
String defaultCountryIso) {
|
|
if (!isFdnEnabled(phoneId)) {
|
|
return false;
|
|
}
|
|
|
|
ArrayList<AdnRecord> fdnList = getFdnList(phoneId);
|
|
return !isFDN(dialStr, defaultCountryIso, fdnList);
|
|
}
|
|
|
|
/**
|
|
* Checks if FDN is enabled
|
|
* @param phoneId The phone object id for which the FDN check is performed
|
|
* @return {@code true} if FDN is enabled
|
|
*/
|
|
public static boolean isFdnEnabled(int phoneId) {
|
|
UiccCardApplication app = getUiccCardApplication(phoneId);
|
|
if (app == null || (!app.getIccFdnAvailable())) {
|
|
return false;
|
|
}
|
|
|
|
return app.getIccFdnEnabled();
|
|
}
|
|
|
|
/**
|
|
* If FDN is enabled, check to see if the given supplementary service control strings are
|
|
* blocked due to FDN.
|
|
* @param phoneId The phone object id for which the FDN check is performed
|
|
* @param controlStrings control strings associated with the supplementary service request
|
|
* @param defaultCountryIso country ISO for the subscription associated with this phone
|
|
* @return {@code true} if the FDN list does not contain any of the control strings.
|
|
*/
|
|
public static boolean isSuppServiceRequestBlockedByFdn(int phoneId,
|
|
ArrayList<String> controlStrings, String defaultCountryIso) {
|
|
if (!isFdnEnabled(phoneId)) {
|
|
return false;
|
|
}
|
|
|
|
ArrayList<AdnRecord> fdnList = getFdnList(phoneId);
|
|
for(String controlString : controlStrings) {
|
|
if(isFDN(controlString, defaultCountryIso, fdnList)) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Checks if dialStr is part of FDN list.
|
|
*
|
|
* @param fdnList List of all FDN records associated with a sim card
|
|
* @param dialStr dialed phone number
|
|
* @param defaultCountryIso country ISO for the subscription associated with this phone
|
|
* @return {@code true} if dialStr is present in the fdnList.
|
|
*/
|
|
@VisibleForTesting
|
|
public static boolean isFDN(String dialStr, String defaultCountryIso,
|
|
ArrayList<AdnRecord> fdnList) {
|
|
if (fdnList == null || fdnList.isEmpty() || TextUtils.isEmpty(dialStr)) {
|
|
Rlog.w(LOG_TAG, "isFDN: unexpected null value");
|
|
return false;
|
|
}
|
|
|
|
// Parse the dialStr and convert it to E164 format
|
|
String dialStrE164 = null;
|
|
String dialStrNational = null;
|
|
final PhoneNumberUtil phoneNumberUtil = PhoneNumberUtil.getInstance();
|
|
try {
|
|
PhoneNumber phoneNumber = phoneNumberUtil.parse(dialStr, defaultCountryIso);
|
|
dialStrE164 = phoneNumberUtil.format(phoneNumber, PhoneNumberFormat.E164);
|
|
dialStrNational = String.valueOf(phoneNumber.getNationalNumber());
|
|
} catch (NumberParseException ignored) {
|
|
Rlog.w(LOG_TAG, "isFDN: could not parse dialStr");
|
|
dialStr = extractSMSC(dialStr);
|
|
}
|
|
|
|
/**
|
|
* Returns true if dialStrE164 or dialStrNational or dialStr starts with fdnNumber
|
|
* E.g.1: returns true if fdnNumber="123" and dialStr="12345"
|
|
* E.g.2: does not return true if fdnNumber="1123" and dialStr="12345"
|
|
*/
|
|
for (AdnRecord fdn: fdnList) {
|
|
String fdnNumber = fdn.getNumber();
|
|
if (TextUtils.isEmpty(fdnNumber)) {
|
|
continue;
|
|
}
|
|
|
|
if(!TextUtils.isEmpty(dialStrE164)) {
|
|
if(dialStrE164.startsWith(fdnNumber)) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
if(!TextUtils.isEmpty(dialStrNational)) {
|
|
if (dialStrNational.startsWith(fdnNumber)) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
if (dialStr.startsWith(fdnNumber)) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
if (VDBG) {
|
|
Rlog.i(LOG_TAG, "isFDN: dialed number not present in FDN list");
|
|
}
|
|
return false;
|
|
}
|
|
|
|
private static ArrayList<AdnRecord> getFdnList(int phoneId) {
|
|
UiccCardApplication app = getUiccCardApplication(phoneId);
|
|
if (app == null) {
|
|
return null;
|
|
}
|
|
|
|
IccRecords iccRecords = app.getIccRecords();
|
|
if (iccRecords == null) {
|
|
return null;
|
|
}
|
|
|
|
AdnRecordCache adnRecordCache = iccRecords.getAdnCache();
|
|
if(adnRecordCache == null) {
|
|
return null;
|
|
}
|
|
|
|
return adnRecordCache.getRecordsIfLoaded(IccConstants.EF_FDN);
|
|
}
|
|
|
|
private static UiccCardApplication getUiccCardApplication(int phoneId) {
|
|
UiccProfile uiccProfile = UiccController.getInstance()
|
|
.getUiccProfileForPhone(phoneId);
|
|
if (uiccProfile == null) {
|
|
return null;
|
|
}
|
|
|
|
return uiccProfile.getApplication(UiccController.APP_FAM_3GPP);
|
|
}
|
|
|
|
private static String extractSMSC(String dialStr) {
|
|
try {
|
|
String[] dialStrParts = null;
|
|
if (dialStr.contains(",")) {
|
|
// SMSC can be in the format of ""+123456789123",123"
|
|
// Split into two parts using comma as delimiter
|
|
// and first part of the string is used as smsc address
|
|
dialStrParts = dialStr.split(",");
|
|
} else if (dialStr.contains("@")) {
|
|
// SMSC can be in the format of "+123456789123@ims.mnc.org"
|
|
// Split into two parts using @ as delimiter
|
|
// and first part of the string is used as smsc address
|
|
dialStrParts = dialStr.split("@");
|
|
}
|
|
|
|
if (dialStrParts != null && dialStrParts.length >= 1) {
|
|
if (dialStrParts[0].contains("\"")) {
|
|
// If SMSC is in this format: ""+123456789123",123", after performing above
|
|
// split we get string with double-quotation marks in it
|
|
// dialStrParts[0] = ""+123456789123"".
|
|
// Here, we remove double-quotation marks from the string.
|
|
dialStrParts[0] = dialStrParts[0].replaceAll("\"", "");
|
|
}
|
|
return dialStrParts[0];
|
|
}
|
|
} catch (PatternSyntaxException ex) {
|
|
Rlog.w(LOG_TAG, "extractSMSC: Could not extract number from dialStr " + ex);
|
|
}
|
|
|
|
// Return original dialStr if it is not in any of the formats mentions above.
|
|
return dialStr;
|
|
}
|
|
} |