content: /*
   * Copyright (C) 2018 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 android.telephony.emergency;
  
  import android.annotation.IntDef;
  import android.annotation.NonNull;
  import android.hardware.radio.V1_4.EmergencyNumberSource;
  import android.hardware.radio.V1_4.EmergencyServiceCategory;
  import android.os.Parcel;
  import android.os.Parcelable;
  import android.telephony.CarrierConfigManager;
  import android.telephony.PhoneNumberUtils;
  import android.telephony.Rlog;
  
  import java.lang.annotation.Retention;
  import java.lang.annotation.RetentionPolicy;
  import java.util.ArrayList;
  import java.util.Collections;
  import java.util.HashSet;
  import java.util.List;
  import java.util.Objects;
  import java.util.Set;
  
  /**
   * A parcelable class that wraps and retrieves the information of number, service category(s) and
   * country code for a specific emergency number.
   */
  public final class EmergencyNumber implements Parcelable, Comparable<EmergencyNumber> {
  
      private static final String LOG_TAG = "EmergencyNumber";
  
      /**
       * Defining Emergency Service Category as follows:
       *  - General emergency call, all categories;
       *  - Police;
       *  - Ambulance;
       *  - Fire Brigade;
       *  - Marine Guard;
       *  - Mountain Rescue;
       *  - Manually Initiated eCall (MIeC);
       *  - Automatically Initiated eCall (AIeC);
       *
       * Category UNSPECIFIED (General emergency call, all categories) indicates that no specific
       * services are associated with this emergency number; if the emergency number is specified,
       * it has one or more defined emergency service categories.
       *
       * Reference: 3gpp 22.101, Section 10 - Emergency Calls
       *
       * @hide
       */
      @IntDef(flag = true, prefix = { "EMERGENCY_SERVICE_CATEGORY_" }, value = {
              EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED,
              EMERGENCY_SERVICE_CATEGORY_POLICE,
              EMERGENCY_SERVICE_CATEGORY_AMBULANCE,
              EMERGENCY_SERVICE_CATEGORY_FIRE_BRIGADE,
              EMERGENCY_SERVICE_CATEGORY_MARINE_GUARD,
              EMERGENCY_SERVICE_CATEGORY_MOUNTAIN_RESCUE,
              EMERGENCY_SERVICE_CATEGORY_MIEC,
              EMERGENCY_SERVICE_CATEGORY_AIEC
      })
      @Retention(RetentionPolicy.SOURCE)
      public @interface EmergencyServiceCategories {}
  
      /**
       * Emergency Service Category UNSPECIFIED (General emergency call, all categories) bit-field
       * indicates that no specific services are associated with this emergency number; if the
       * emergency number is specified, it has one or more defined emergency service categories.
       *
       * Reference: 3gpp 22.101, Section 10 - Emergency Calls
       */
      public static final int EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED =
              EmergencyServiceCategory.UNSPECIFIED;
      /**
       * Bit-field that indicates Emergency Service Category for Police.
       *
       * Reference: 3gpp 22.101, Section 10 - Emergency Calls
       */
      public static final int EMERGENCY_SERVICE_CATEGORY_POLICE = EmergencyServiceCategory.POLICE;
      /**
       * Bit-field that indicates Emergency Service Category for Ambulance.
       *
       * Reference: 3gpp 22.101, Section 10 - Emergency Calls
       */
      public static final int EMERGENCY_SERVICE_CATEGORY_AMBULANCE =
              EmergencyServiceCategory.AMBULANCE;
      /**
       * Bit-field that indicates Emergency Service Category for Fire Brigade.
       *
       * Reference: 3gpp 22.101, Section 10 - Emergency Calls
       */
      public static final int EMERGENCY_SERVICE_CATEGORY_FIRE_BRIGADE =
              EmergencyServiceCategory.FIRE_BRIGADE;
      /**
       * Bit-field that indicates Emergency Service Category for Marine Guard.
       *
       * Reference: 3gpp 22.101, Section 10 - Emergency Calls
       */
      public static final int EMERGENCY_SERVICE_CATEGORY_MARINE_GUARD =
              EmergencyServiceCategory.MARINE_GUARD;
      /**
       * Bit-field that indicates Emergency Service Category for Mountain Rescue.
       *
       * Reference: 3gpp 22.101, Section 10 - Emergency Calls
       */
      public static final int EMERGENCY_SERVICE_CATEGORY_MOUNTAIN_RESCUE =
              EmergencyServiceCategory.MOUNTAIN_RESCUE;
      /**
       * Bit-field that indicates Emergency Service Category for Manually Initiated eCall (MIeC)
       *
       * Reference: 3gpp 22.101, Section 10 - Emergency Calls
       */
      public static final int EMERGENCY_SERVICE_CATEGORY_MIEC = EmergencyServiceCategory.MIEC;
      /**
       * Bit-field that indicates Emergency Service Category for Automatically Initiated eCall (AIeC)
       *
       * Reference: 3gpp 22.101, Section 10 - Emergency Calls
       */
      public static final int EMERGENCY_SERVICE_CATEGORY_AIEC = EmergencyServiceCategory.AIEC;
  
      private static final Set<Integer> EMERGENCY_SERVICE_CATEGORY_SET;
      static {
          EMERGENCY_SERVICE_CATEGORY_SET = new HashSet<Integer>();
          EMERGENCY_SERVICE_CATEGORY_SET.add(EMERGENCY_SERVICE_CATEGORY_POLICE);
          EMERGENCY_SERVICE_CATEGORY_SET.add(EMERGENCY_SERVICE_CATEGORY_AMBULANCE);
          EMERGENCY_SERVICE_CATEGORY_SET.add(EMERGENCY_SERVICE_CATEGORY_FIRE_BRIGADE);
          EMERGENCY_SERVICE_CATEGORY_SET.add(EMERGENCY_SERVICE_CATEGORY_MARINE_GUARD);
          EMERGENCY_SERVICE_CATEGORY_SET.add(EMERGENCY_SERVICE_CATEGORY_MOUNTAIN_RESCUE);
          EMERGENCY_SERVICE_CATEGORY_SET.add(EMERGENCY_SERVICE_CATEGORY_MIEC);
          EMERGENCY_SERVICE_CATEGORY_SET.add(EMERGENCY_SERVICE_CATEGORY_AIEC);
      }
  
      /**
       * The source to tell where the corresponding @1.4::EmergencyNumber comes from.
       *
       * The emergency number has one or more defined emergency number sources.
       *
       * Reference: 3gpp 22.101, Section 10 - Emergency Calls
       *
       * @hide
       */
      @IntDef(flag = true, prefix = { "EMERGENCY_NUMBER_SOURCE_" }, value = {
              EMERGENCY_NUMBER_SOURCE_NETWORK_SIGNALING,
              EMERGENCY_NUMBER_SOURCE_SIM,
              EMERGENCY_NUMBER_SOURCE_DATABASE,
              EMERGENCY_NUMBER_SOURCE_MODEM_CONFIG,
              EMERGENCY_NUMBER_SOURCE_DEFAULT
      })
      @Retention(RetentionPolicy.SOURCE)
      public @interface EmergencyNumberSources {}
  
      /**
       * Bit-field which indicates the number is from the network signaling.
       *
       * Reference: 3gpp 22.101, Section 10 - Emergency Calls
       */
      public static final int EMERGENCY_NUMBER_SOURCE_NETWORK_SIGNALING =
              EmergencyNumberSource.NETWORK_SIGNALING;
      /**
       * Bit-field which indicates the number is from the sim.
       *
       * Reference: 3gpp 22.101, Section 10 - Emergency Calls
       */
      public static final int EMERGENCY_NUMBER_SOURCE_SIM = EmergencyNumberSource.SIM;
      /**
       * Bit-field which indicates the number is from the platform-maintained database.
       */
      public static final int EMERGENCY_NUMBER_SOURCE_DATABASE =  1 << 4;
      /**
       * Bit-field which indicates the number is from test mode.
       *
       * @hide
       */
      public static final int EMERGENCY_NUMBER_SOURCE_TEST =  1 << 5;
      /** Bit-field which indicates the number is from the modem config. */
      public static final int EMERGENCY_NUMBER_SOURCE_MODEM_CONFIG =
              EmergencyNumberSource.MODEM_CONFIG;
      /**
       * Bit-field which indicates the number is available as default.
       *
       * 112, 911 must always be available; additionally, 000, 08, 110, 999, 118 and 119 must be
       * available when sim is not present.
       *
       * Reference: 3gpp 22.101, Section 10 - Emergency Calls
       */
      public static final int EMERGENCY_NUMBER_SOURCE_DEFAULT = EmergencyNumberSource.DEFAULT;
  
      private static final Set<Integer> EMERGENCY_NUMBER_SOURCE_SET;
      static {
          EMERGENCY_NUMBER_SOURCE_SET = new HashSet<Integer>();
          EMERGENCY_NUMBER_SOURCE_SET.add(EMERGENCY_NUMBER_SOURCE_NETWORK_SIGNALING);
          EMERGENCY_NUMBER_SOURCE_SET.add(EMERGENCY_NUMBER_SOURCE_SIM);
          EMERGENCY_NUMBER_SOURCE_SET.add(EMERGENCY_NUMBER_SOURCE_DATABASE);
          EMERGENCY_NUMBER_SOURCE_SET.add(EMERGENCY_NUMBER_SOURCE_MODEM_CONFIG);
          EMERGENCY_NUMBER_SOURCE_SET.add(EMERGENCY_NUMBER_SOURCE_DEFAULT);
      }
  
      /**
       * Indicated the framework does not know whether an emergency call should be placed using
       * emergency or normal call routing. This means the underlying radio or IMS implementation is
       * free to determine for itself how to route the call.
       */
      public static final int EMERGENCY_CALL_ROUTING_UNKNOWN = 0;
      /**
       * Indicates the radio or IMS implementation must handle the call through emergency routing.
       */
      public static final int EMERGENCY_CALL_ROUTING_EMERGENCY = 1;
      /**
       * Indicates the radio or IMS implementation must handle the call through normal call routing.
       */
      public static final int EMERGENCY_CALL_ROUTING_NORMAL = 2;
  
      /**
       * The routing to tell how to handle the call for the corresponding emergency number.
       *
       * @hide
       */
      @IntDef(flag = false, prefix = { "EMERGENCY_CALL_ROUTING_" }, value = {
              EMERGENCY_CALL_ROUTING_UNKNOWN,
              EMERGENCY_CALL_ROUTING_EMERGENCY,
              EMERGENCY_CALL_ROUTING_NORMAL
      })
      @Retention(RetentionPolicy.SOURCE)
      public @interface EmergencyCallRouting {}
  
  
      private final String mNumber;
      private final String mCountryIso;
      private final String mMnc;
      private final int mEmergencyServiceCategoryBitmask;
      private final List<String> mEmergencyUrns;
      private final int mEmergencyNumberSourceBitmask;
      private final int mEmergencyCallRouting;
  
      /** @hide */
      public EmergencyNumber(@NonNull String number, @NonNull String countryIso, @NonNull String mnc,
                             @EmergencyServiceCategories int emergencyServiceCategories,
                             @NonNull List<String> emergencyUrns,
                             @EmergencyNumberSources int emergencyNumberSources,
                             @EmergencyCallRouting int emergencyCallRouting) {
          this.mNumber = number;
          this.mCountryIso = countryIso;
          this.mMnc = mnc;
          this.mEmergencyServiceCategoryBitmask = emergencyServiceCategories;
          this.mEmergencyUrns = emergencyUrns;
          this.mEmergencyNumberSourceBitmask = emergencyNumberSources;
          this.mEmergencyCallRouting = emergencyCallRouting;
      }
  
      /** @hide */
      public EmergencyNumber(Parcel source) {
          mNumber = source.readString();
          mCountryIso = source.readString();
          mMnc = source.readString();
          mEmergencyServiceCategoryBitmask = source.readInt();
          mEmergencyUrns = source.createStringArrayList();
          mEmergencyNumberSourceBitmask = source.readInt();
          mEmergencyCallRouting = source.readInt();
      }
  
      @Override
      /** @hide */
      public void writeToParcel(Parcel dest, int flags) {
          dest.writeString(mNumber);
          dest.writeString(mCountryIso);
          dest.writeString(mMnc);
          dest.writeInt(mEmergencyServiceCategoryBitmask);
          dest.writeStringList(mEmergencyUrns);
          dest.writeInt(mEmergencyNumberSourceBitmask);
          dest.writeInt(mEmergencyCallRouting);
      }
  
      public static final @android.annotation.NonNull Parcelable.Creator<EmergencyNumber> CREATOR =
              new Parcelable.Creator<EmergencyNumber>() {
                  @Override
                  public EmergencyNumber createFromParcel(Parcel in) {
                      return new EmergencyNumber(in);
                  }
  
                  @Override
                  public EmergencyNumber[] newArray(int size) {
                      return new EmergencyNumber[size];
                  }
              };
  
      /**
       * Get the dialing number of the emergency number.
       *
       * The character in the number string is only the dial pad
       * character('0'-'9', '*', '+', or '#'). For example: 911.
       *
       * If the number starts with carrier prefix, the carrier prefix is configured in
       * {@link CarrierConfigManager#KEY_EMERGENCY_NUMBER_PREFIX_STRING_ARRAY}.
       *
       * @return the dialing number.
       */
      public @NonNull String getNumber() {
          return mNumber;
      }
  
      /**
       * Get the country code string (lowercase character) in ISO 3166 format of the emergency number.
       *
       * @return the country code string (lowercase character) in ISO 3166 format.
       */
      public @NonNull String getCountryIso() {
          return mCountryIso;
      }
  
      /**
       * Get the Mobile Network Code of the emergency number.
       *
       * @return the Mobile Network Code of the emergency number.
       */
      public @NonNull String getMnc() {
          return mMnc;
      }
  
      /**
       * Returns the bitmask of emergency service categories of the emergency number.
       *
       * @return bitmask of the emergency service categories
       *
       * @hide
       */
      public @EmergencyServiceCategories int getEmergencyServiceCategoryBitmask() {
          return mEmergencyServiceCategoryBitmask;
      }
  
      /**
       * Returns the bitmask of emergency service categories of the emergency number for
       * internal dialing.
       *
       * @return bitmask of the emergency service categories
       *
       * @hide
       */
      public @EmergencyServiceCategories int getEmergencyServiceCategoryBitmaskInternalDial() {
          if (mEmergencyNumberSourceBitmask == EMERGENCY_NUMBER_SOURCE_DATABASE) {
              return EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED;
          }
          return mEmergencyServiceCategoryBitmask;
      }
  
      /**
       * Returns the emergency service categories of the emergency number.
       *
       * Note: if the emergency number is in {@link #EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED}, only
       * {@link #EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED} is returned and it means the number is in
       * all categories.
       *
       * @return a list of the emergency service categories
       */
      public @NonNull List<Integer> getEmergencyServiceCategories() {
          List<Integer> categories = new ArrayList<>();
          if (serviceUnspecified()) {
              categories.add(EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED);
              return categories;
          }
          for (Integer category : EMERGENCY_SERVICE_CATEGORY_SET) {
              if (isInEmergencyServiceCategories(category)) {
                  categories.add(category);
              }
          }
          return categories;
      }
  
      /**
       * Returns the list of emergency Uniform Resources Names (URN) of the emergency number.
       *
       * For example, {@code urn:service:sos} is the generic URN for contacting emergency services
       * of all type.
       *
       * Reference: 3gpp 24.503, Section 5.1.6.8.1 - General;
       *            RFC 5031
       *
       * @return list of emergency Uniform Resources Names (URN) or an empty list if the emergency
       *         number does not have a specified emergency Uniform Resource Name.
       */
      public @NonNull List<String> getEmergencyUrns() {
          return Collections.unmodifiableList(mEmergencyUrns);
      }
  
      /**
       * Checks if the emergency service category is unspecified for the emergency number
       * {@link #EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED}.
       *
       * @return {@code true} if the emergency service category is unspecified for the emergency
       * number {@link #EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED}; {@code false} otherwise.
       */
      private boolean serviceUnspecified() {
          return mEmergencyServiceCategoryBitmask == EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED;
      }
  
      /**
       * Checks if the emergency number is in the supplied emergency service category(s).
       *
       * @param categories - the supplied emergency service categories
       *
       * @return {@code true} if the emergency number is in the specified emergency service
       * category(s) or if its emergency service category is
       * {@link #EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED}; {@code false} otherwise.
       */
      public boolean isInEmergencyServiceCategories(@EmergencyServiceCategories int categories) {
          if (categories == EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED) {
              return serviceUnspecified();
          }
          if (serviceUnspecified()) {
              return true;
          }
          return (mEmergencyServiceCategoryBitmask & categories) == categories;
      }
  
      /**
       * Returns the bitmask of the sources of the emergency number.
       *
       * @return bitmask of the emergency number sources
       *
       * @hide
       */
      public @EmergencyNumberSources int getEmergencyNumberSourceBitmask() {
          return mEmergencyNumberSourceBitmask;
      }
  
      /**
       * Returns a list of sources of the emergency number.
       *
       * @return a list of emergency number sources
       */
      public @NonNull List<Integer> getEmergencyNumberSources() {
          List<Integer> sources = new ArrayList<>();
          for (Integer source : EMERGENCY_NUMBER_SOURCE_SET) {
              if ((mEmergencyNumberSourceBitmask & source) == source) {
                  sources.add(source);
              }
          }
          return sources;
      }
  
      /**
       * Checks if the emergency number is from the specified emergency number source(s).
       *
       * @return {@code true} if the emergency number is from the specified emergency number
       * source(s); {@code false} otherwise.
       *
       * @param sources - the supplied emergency number sources
       */
      public boolean isFromSources(@EmergencyNumberSources int sources) {
          return (mEmergencyNumberSourceBitmask & sources) == sources;
      }
  
      /**
       * Returns the emergency call routing information.
       *
       * <p>Some regions require some emergency numbers which are not routed using typical emergency
       * call processing, but are instead placed as regular phone calls. The emergency call routing
       * field provides information about how an emergency call will be routed when it is placed.
       *
       * @return the emergency call routing requirement
       */
      public @EmergencyCallRouting int getEmergencyCallRouting() {
          return mEmergencyCallRouting;
      }
  
      @Override
      /** @hide */
      public int describeContents() {
          return 0;
      }
  
      @Override
      public String toString() {
          return "EmergencyNumber:" + "Number-" + mNumber + "|CountryIso-" + mCountryIso
                  + "|Mnc-" + mMnc
                  + "|ServiceCategories-" + Integer.toBinaryString(mEmergencyServiceCategoryBitmask)
                  + "|Urns-" + mEmergencyUrns
                  + "|Sources-" + Integer.toBinaryString(mEmergencyNumberSourceBitmask)
                  + "|Routing-" + Integer.toBinaryString(mEmergencyCallRouting);
      }
  
      @Override
      public boolean equals(Object o) {
          if (!EmergencyNumber.class.isInstance(o)) {
              return false;
          }
          EmergencyNumber other = (EmergencyNumber) o;
          return mNumber.equals(other.mNumber)
                  && mCountryIso.equals(other.mCountryIso)
                  && mMnc.equals(other.mMnc)
                  && mEmergencyServiceCategoryBitmask == other.mEmergencyServiceCategoryBitmask
                  && mEmergencyUrns.equals(other.mEmergencyUrns)
                  && mEmergencyNumberSourceBitmask == other.mEmergencyNumberSourceBitmask
                  && mEmergencyCallRouting == other.mEmergencyCallRouting;
      }
  
      @Override
      public int hashCode() {
          return Objects.hash(mNumber, mCountryIso, mMnc, mEmergencyServiceCategoryBitmask,
                  mEmergencyUrns, mEmergencyNumberSourceBitmask, mEmergencyCallRouting);
      }
  
      /**
       * Calculate the score for display priority.
       *
       * A higher display priority score means the emergency number has a higher display priority.
       * The score is higher if the source is defined for a higher display priority.
       *
       * The priority of sources are defined as follows:
       *     EMERGENCY_NUMBER_SOURCE_NETWORK_SIGNALING >
       *     EMERGENCY_NUMBER_SOURCE_SIM >
       *     EMERGENCY_NUMBER_SOURCE_DATABASE >
       *     EMERGENCY_NUMBER_SOURCE_DEFAULT >
       *     EMERGENCY_NUMBER_SOURCE_MODEM_CONFIG
       *
       */
      private int getDisplayPriorityScore() {
          int score = 0;
          if (this.isFromSources(EMERGENCY_NUMBER_SOURCE_NETWORK_SIGNALING)) {
              score += 1 << 4;
          }
          if (this.isFromSources(EMERGENCY_NUMBER_SOURCE_SIM)) {
              score += 1 << 3;
          }
          if (this.isFromSources(EMERGENCY_NUMBER_SOURCE_DATABASE)) {
              score += 1 << 2;
          }
          if (this.isFromSources(EMERGENCY_NUMBER_SOURCE_DEFAULT)) {
              score += 1 << 1;
          }
          if (this.isFromSources(EMERGENCY_NUMBER_SOURCE_MODEM_CONFIG)) {
              score += 1 << 0;
          }
          return score;
      }
  
      /**
       * Compare the display priority for this emergency number and the supplied emergency number.
       *
       * @param emergencyNumber the supplied emergency number
       * @return a negative value if the supplied emergency number has a lower display priority;
       *         a positive value if the supplied emergency number has a higher display priority;
       *         0 if both have equal display priority.
       */
      @Override
      public int compareTo(@NonNull EmergencyNumber emergencyNumber) {
          if (this.getDisplayPriorityScore()
                  > emergencyNumber.getDisplayPriorityScore()) {
              return -1;
          } else if (this.getDisplayPriorityScore()
                  < emergencyNumber.getDisplayPriorityScore()) {
              return 1;
          } else if (this.getNumber().compareTo(emergencyNumber.getNumber()) != 0) {
              return this.getNumber().compareTo(emergencyNumber.getNumber());
          } else if (this.getCountryIso().compareTo(emergencyNumber.getCountryIso()) != 0) {
              return this.getCountryIso().compareTo(emergencyNumber.getCountryIso());
          } else if (this.getMnc().compareTo(emergencyNumber.getMnc()) != 0) {
              return this.getMnc().compareTo(emergencyNumber.getMnc());
          } else if (this.getEmergencyServiceCategoryBitmask()
                  != emergencyNumber.getEmergencyServiceCategoryBitmask()) {
              return this.getEmergencyServiceCategoryBitmask()
                      > emergencyNumber.getEmergencyServiceCategoryBitmask() ? -1 : 1;
          } else if (this.getEmergencyUrns().toString().compareTo(
                  emergencyNumber.getEmergencyUrns().toString()) != 0) {
              return this.getEmergencyUrns().toString().compareTo(
                      emergencyNumber.getEmergencyUrns().toString());
          } else if (this.getEmergencyCallRouting()
                  != emergencyNumber.getEmergencyCallRouting()) {
              return this.getEmergencyCallRouting()
                      > emergencyNumber.getEmergencyCallRouting() ? -1 : 1;
          } else {
              return 0;
          }
      }
  
      /**
       * In-place merge same emergency numbers in the emergency number list.
       *
       * A unique EmergencyNumber has a unique combination of ‘number’, ‘mcc’, 'mnc' and
       * 'categories' fields. Multiple Emergency Number Sources should be merged into one bitfield
       * for the same EmergencyNumber.
       *
       * @param emergencyNumberList the emergency number list to process
       *
       * @hide
       */
      public static void mergeSameNumbersInEmergencyNumberList(
              List<EmergencyNumber> emergencyNumberList) {
          if (emergencyNumberList == null) {
              return;
          }
          Set<Integer> 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));
                      // Set the merged emergency number in the current position
                      emergencyNumberList.set(i, mergeSameEmergencyNumbers(
                              emergencyNumberList.get(i), emergencyNumberList.get(j)));
                      // Mark the emergency number has been merged
                      duplicatedEmergencyNumberPosition.add(j);
                  }
              }
          }
  
          // Remove the marked emergency number in the original list
          for (int i = emergencyNumberList.size() - 1; i >= 0; i--) {
              if (duplicatedEmergencyNumberPosition.contains(i)) {
                  emergencyNumberList.remove(i);
              }
          }
          Collections.sort(emergencyNumberList);
      }
  
      /**
       * Check if two emergency numbers are the same.
       *
       * A unique EmergencyNumber has a unique combination of ‘number’, ‘mcc’, 'mnc' and
       * 'categories', and 'routing' fields. Multiple Emergency Number Sources should be
       * merged into one bitfield for the same EmergencyNumber.
       *
       * @param first first EmergencyNumber to compare
       * @param second second EmergencyNumber to compare
       * @return true if they are the same EmergencyNumbers; false otherwise.
       *
       * @hide
       */
      public static boolean areSameEmergencyNumbers(@NonNull EmergencyNumber first,
                                                    @NonNull EmergencyNumber second) {
          if (!first.getNumber().equals(second.getNumber())) {
              return false;
          }
          if (!first.getCountryIso().equals(second.getCountryIso())) {
              return false;
          }
          if (!first.getMnc().equals(second.getMnc())) {
              return false;
          }
          if (first.getEmergencyServiceCategoryBitmask()
                  != second.getEmergencyServiceCategoryBitmask()) {
              return false;
          }
          if (!first.getEmergencyUrns().equals(second.getEmergencyUrns())) {
              return false;
          }
          if (first.getEmergencyCallRouting() != second.getEmergencyCallRouting()) {
              return false;
          }
          // Never merge two numbers if one of them is from test mode but the other one is not;
          // This supports to remove a number from the test mode.
          if (first.isFromSources(EMERGENCY_NUMBER_SOURCE_TEST)
                  ^ second.isFromSources(EMERGENCY_NUMBER_SOURCE_TEST)) {
              return false;
          }
          return true;
      }
  
      /**
       * Get a merged EmergencyNumber from two same emergency numbers. Two emergency numbers are
       * the same if {@link #areSameEmergencyNumbers} returns {@code true}.
       *
       * @param first first EmergencyNumber to compare
       * @param second second EmergencyNumber to compare
       * @return a merged EmergencyNumber or null if they are not the same EmergencyNumber
       *
       * @hide
       */
      public static EmergencyNumber mergeSameEmergencyNumbers(@NonNull EmergencyNumber first,
                                                              @NonNull EmergencyNumber second) {
          if (areSameEmergencyNumbers(first, second)) {
              return new EmergencyNumber(first.getNumber(), first.getCountryIso(), first.getMnc(),
                      first.getEmergencyServiceCategoryBitmask(),
                      first.getEmergencyUrns(),
                      first.getEmergencyNumberSourceBitmask()
                              | second.getEmergencyNumberSourceBitmask(),
                      first.getEmergencyCallRouting());
          }
          return null;
      }
  
      /**
       * Validate Emergency Number address that only contains the dialable character
       * {@link PhoneNumberUtils#isDialable(char)}
       *
       * @hide
       */
      public static boolean validateEmergencyNumberAddress(String address) {
          if (address == null) {
              return false;
          }
          for (char c : address.toCharArray()) {
              if (!PhoneNumberUtils.isDialable(c)) {
                  return false;
              }
          }
          return true;
      }
  }
  