From 0519dd40ecad27751b24e5aef788ccf7ed07cd85 Mon Sep 17 00:00:00 2001 From: sparvathy Date: Thu, 17 Nov 2022 17:01:47 +0000 Subject: [PATCH] Modified merging of duplicate emergency numbers Changed merging logic in combined list of DB and radio list. Service category and urns are not compared to check duplicate. It is set from one of the duplicate number based on its source as per the precedence of Network/SIM/DB/modem_cfg. Test: atest EmergencyNumberTest & EC in device Bug: 238359415 Change-Id: Icf5686f5b0ea8d3bc29d6c0fbe7be3ef05ccc65c --- .../telephony/emergency/EmergencyNumber.java | 187 ++++++++++++++++-- 1 file changed, 171 insertions(+), 16 deletions(-) diff --git a/telephony/java/android/telephony/emergency/EmergencyNumber.java b/telephony/java/android/telephony/emergency/EmergencyNumber.java index e78a1e107afea..64bcf7171adea 100644 --- a/telephony/java/android/telephony/emergency/EmergencyNumber.java +++ b/telephony/java/android/telephony/emergency/EmergencyNumber.java @@ -25,6 +25,8 @@ import android.os.Parcel; import android.os.Parcelable; import android.telephony.CarrierConfigManager; import android.telephony.PhoneNumberUtils; +import android.util.SparseArray; +import android.util.SparseIntArray; import com.android.telephony.Rlog; @@ -247,6 +249,17 @@ public final class EmergencyNumber implements Parcelable, Comparable mEmergencyUrns; private final int mEmergencyNumberSourceBitmask; private final int mEmergencyCallRouting; + /** + * The source of the EmergencyNumber in the order of precedence. + */ + private static final int[] EMERGENCY_NUMBER_SOURCE_PRECEDENCE; + static { + EMERGENCY_NUMBER_SOURCE_PRECEDENCE = new int[4]; + EMERGENCY_NUMBER_SOURCE_PRECEDENCE[0] = EMERGENCY_NUMBER_SOURCE_NETWORK_SIGNALING; + EMERGENCY_NUMBER_SOURCE_PRECEDENCE[1] = EMERGENCY_NUMBER_SOURCE_SIM; + EMERGENCY_NUMBER_SOURCE_PRECEDENCE[2] = EMERGENCY_NUMBER_SOURCE_DATABASE; + EMERGENCY_NUMBER_SOURCE_PRECEDENCE[3] = EMERGENCY_NUMBER_SOURCE_MODEM_CONFIG; + } /** @hide */ public EmergencyNumber(@NonNull String number, @NonNull String countryIso, @NonNull String mnc, @@ -601,19 +614,44 @@ public final class EmergencyNumber implements Parcelable, Comparable emergencyNumberList) { + mergeSameNumbersInEmergencyNumberList(emergencyNumberList, false); + } + + /** + * In-place merge same emergency numbers in the emergency number list. + * + * A unique EmergencyNumber has a unique combination of ‘number’, ‘mcc’ and 'mnc' fields. + * If mergeServiceCategoriesAndUrns is true ignore comparing of 'urns' and + * 'categories' fields and determine these fields from most precedent number. Else compare + * to get unique combination of EmergencyNumber. + * Multiple Emergency Number Sources should be merged into one bitfield for the + * same EmergencyNumber. + * + * @param emergencyNumberList the emergency number list to process + * @param mergeServiceCategoriesAndUrns {@code true} determine service category and urns + * from most precedent number. {@code false} compare those fields for determing duplicate. + * + * @hide + */ + public static void mergeSameNumbersInEmergencyNumberList( + @NonNull List emergencyNumberList, + boolean mergeServiceCategoriesAndUrns) { if (emergencyNumberList == null) { return; } + Set duplicatedEmergencyNumberPosition = new HashSet<>(); for (int i = 0; i < emergencyNumberList.size(); i++) { for (int j = 0; j < i; j++) { - if (areSameEmergencyNumbers( - emergencyNumberList.get(i), emergencyNumberList.get(j))) { - Rlog.e(LOG_TAG, "Found unexpected duplicate numbers: " - + emergencyNumberList.get(i) + " vs " + emergencyNumberList.get(j)); + if (areSameEmergencyNumbers(emergencyNumberList.get(i), + emergencyNumberList.get(j), mergeServiceCategoriesAndUrns)) { + Rlog.e(LOG_TAG, "Found unexpected duplicate numbers " + + emergencyNumberList.get(i) + + " vs " + emergencyNumberList.get(j)); // Set the merged emergency number in the current position - emergencyNumberList.set(i, mergeSameEmergencyNumbers( - emergencyNumberList.get(i), emergencyNumberList.get(j))); + emergencyNumberList.set(i, + mergeSameEmergencyNumbers(emergencyNumberList.get(i), + emergencyNumberList.get(j), mergeServiceCategoriesAndUrns)); // Mark the emergency number has been merged duplicatedEmergencyNumberPosition.add(j); } @@ -632,18 +670,24 @@ public final class EmergencyNumber implements Parcelable, Comparable mergeEmergencyUrns(@NonNull List firstEmergencyUrns, + @NonNull List secondEmergencyUrns) { + List mergedUrns = new ArrayList(); + mergedUrns.addAll(firstEmergencyUrns); + for (String urn : secondEmergencyUrns) { + if (!firstEmergencyUrns.contains(urn)) { + mergedUrns.add(urn); + } + } + return mergedUrns; + } + + /** + * Get the highest precedence source of the given Emergency number. Then get service catergory + * and urns list fill in the respective map with key as source. + * + * @param num EmergencyNumber to get the source, service category & urns + * @param serviceCategoryArray Array to store the category of the given EmergencyNumber + * with key as highest precedence source + * @param urnsArray Array to store the list of Urns of the given EmergencyNumber + * with key as highest precedence source + * + * @hide + */ + private static void fillServiceCategoryAndUrns(@NonNull EmergencyNumber num, + @NonNull SparseIntArray serviceCategoryArray, + @NonNull SparseArray> urnsArray) { + int numberSrc = num.getEmergencyNumberSourceBitmask(); + for (Integer source : EMERGENCY_NUMBER_SOURCE_PRECEDENCE) { + if ((numberSrc & source) == source) { + if (!num.isInEmergencyServiceCategories(EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED)) { + serviceCategoryArray.put(source, num.getEmergencyServiceCategoryBitmask()); + } + urnsArray.put(source, num.getEmergencyUrns()); + break; + } + } + } + + /** + * Get a merged EmergencyNumber from two same emergency numbers from + * Emergency number list. Two emergency numbers are the same if + * {@link #areSameEmergencyNumbers} returns {@code true}. + * + * @param first first EmergencyNumber to compare + * @param second second EmergencyNumber to compare + * @param mergeServiceCategoriesAndUrns {@code true} then determine service category and urns + * Service catetory : set from most precedence source number(N/W, SIM, DB, modem_cfg) + * Urns : merge from both with first priority from most precedence source number + * {@code false} then call {@link #mergeSameEmergencyNumbers} to merge. + * @return a merged EmergencyNumber or null if they are not the same EmergencyNumber + * + * @hide + */ + public static @NonNull EmergencyNumber mergeSameEmergencyNumbers( + @NonNull EmergencyNumber first, @NonNull EmergencyNumber second, + boolean mergeServiceCategoriesAndUrns) { + if (!mergeServiceCategoriesAndUrns) { + return mergeSameEmergencyNumbers(first, second); + } + + int routing = first.getEmergencyCallRouting(); + int serviceCategory = first.getEmergencyServiceCategoryBitmask(); + List mergedEmergencyUrns = new ArrayList(); + //Maps to store the service category and urns of both the first and second emergency number + // with key as most precedent source + SparseIntArray serviceCategoryArray = new SparseIntArray(2); + SparseArray> urnsArray = new SparseArray(2); + + fillServiceCategoryAndUrns(first, serviceCategoryArray, urnsArray); + fillServiceCategoryAndUrns(second, serviceCategoryArray, urnsArray); + + if (second.isFromSources(EMERGENCY_NUMBER_SOURCE_DATABASE)) { + routing = second.getEmergencyCallRouting(); + } + + // Determine serviceCategory of most precedence number + for (int sourceOfCategory : EMERGENCY_NUMBER_SOURCE_PRECEDENCE) { + if (serviceCategoryArray.indexOfKey(sourceOfCategory) >= 0) { + serviceCategory = serviceCategoryArray.get(sourceOfCategory); + break; + } + } + + // Merge Urns in precedence number + for (int sourceOfUrn : EMERGENCY_NUMBER_SOURCE_PRECEDENCE) { + if (urnsArray.contains(sourceOfUrn)) { + mergedEmergencyUrns = mergeEmergencyUrns(mergedEmergencyUrns, + urnsArray.get(sourceOfUrn)); + } + } + + return new EmergencyNumber(first.getNumber(), first.getCountryIso(), first.getMnc(), + serviceCategory, mergedEmergencyUrns, + first.getEmergencyNumberSourceBitmask() + | second.getEmergencyNumberSourceBitmask(), + routing); + } + /** * Validate Emergency Number address that only contains the dialable character * {@link PhoneNumberUtils#isDialable(char)}