179 lines
6.4 KiB
Java
179 lines
6.4 KiB
Java
![]() |
/*
|
||
|
* 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;
|
||
|
|
||
|
import android.annotation.NonNull;
|
||
|
import android.annotation.Nullable;
|
||
|
import android.annotation.SystemApi;
|
||
|
import android.os.Parcel;
|
||
|
import android.os.Parcelable;
|
||
|
import android.util.Log;
|
||
|
|
||
|
import java.util.Objects;
|
||
|
import java.util.regex.Pattern;
|
||
|
|
||
|
/**
|
||
|
* This class is used to represent a range of phone numbers. Each range corresponds to a contiguous
|
||
|
* block of phone numbers.
|
||
|
*
|
||
|
* Example:
|
||
|
* {@code
|
||
|
* {
|
||
|
* mCountryCode = "1"
|
||
|
* mPrefix = "650555"
|
||
|
* mLowerBound = "0055"
|
||
|
* mUpperBound = "0899"
|
||
|
* }
|
||
|
* }
|
||
|
* would match 16505550089 and 6505550472, but not 63827593759 or 16505550900
|
||
|
* @hide
|
||
|
*/
|
||
|
@SystemApi
|
||
|
public final class PhoneNumberRange implements Parcelable {
|
||
|
public static final @android.annotation.NonNull Creator<PhoneNumberRange> CREATOR = new Creator<PhoneNumberRange>() {
|
||
|
@Override
|
||
|
public PhoneNumberRange createFromParcel(Parcel in) {
|
||
|
return new PhoneNumberRange(in);
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public PhoneNumberRange[] newArray(int size) {
|
||
|
return new PhoneNumberRange[size];
|
||
|
}
|
||
|
};
|
||
|
|
||
|
private final String mCountryCode;
|
||
|
private final String mPrefix;
|
||
|
private final String mLowerBound;
|
||
|
private final String mUpperBound;
|
||
|
|
||
|
/**
|
||
|
* @param countryCode The country code, omitting the leading "+"
|
||
|
* @param prefix A prefix that all numbers matching the range must have.
|
||
|
* @param lowerBound When concatenated with the prefix, represents the lower bound of phone
|
||
|
* numbers that match this range.
|
||
|
* @param upperBound When concatenated with the prefix, represents the upper bound of phone
|
||
|
* numbers that match this range.
|
||
|
*/
|
||
|
public PhoneNumberRange(@NonNull String countryCode, @NonNull String prefix,
|
||
|
@NonNull String lowerBound, @NonNull String upperBound) {
|
||
|
validateLowerAndUpperBounds(lowerBound, upperBound);
|
||
|
if (!Pattern.matches("[0-9]*", countryCode)) {
|
||
|
throw new IllegalArgumentException("Country code must be all numeric");
|
||
|
}
|
||
|
if (!Pattern.matches("[0-9]*", prefix)) {
|
||
|
throw new IllegalArgumentException("Prefix must be all numeric");
|
||
|
}
|
||
|
mCountryCode = countryCode;
|
||
|
mPrefix = prefix;
|
||
|
mLowerBound = lowerBound;
|
||
|
mUpperBound = upperBound;
|
||
|
}
|
||
|
|
||
|
private PhoneNumberRange(Parcel in) {
|
||
|
mCountryCode = in.readString();
|
||
|
mPrefix = in.readString();
|
||
|
mLowerBound = in.readString();
|
||
|
mUpperBound = in.readString();
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public void writeToParcel(Parcel dest, int flags) {
|
||
|
dest.writeString(mCountryCode);
|
||
|
dest.writeString(mPrefix);
|
||
|
dest.writeString(mLowerBound);
|
||
|
dest.writeString(mUpperBound);
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public int describeContents() {
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public boolean equals(@Nullable Object o) {
|
||
|
if (this == o) return true;
|
||
|
if (o == null || getClass() != o.getClass()) return false;
|
||
|
PhoneNumberRange that = (PhoneNumberRange) o;
|
||
|
return Objects.equals(mCountryCode, that.mCountryCode)
|
||
|
&& Objects.equals(mPrefix, that.mPrefix)
|
||
|
&& Objects.equals(mLowerBound, that.mLowerBound)
|
||
|
&& Objects.equals(mUpperBound, that.mUpperBound);
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public int hashCode() {
|
||
|
return Objects.hash(mCountryCode, mPrefix, mLowerBound, mUpperBound);
|
||
|
}
|
||
|
|
||
|
@NonNull
|
||
|
@Override
|
||
|
public String toString() {
|
||
|
return "PhoneNumberRange{"
|
||
|
+ "mCountryCode='" + mCountryCode + '\''
|
||
|
+ ", mPrefix='" + mPrefix + '\''
|
||
|
+ ", mLowerBound='" + mLowerBound + '\''
|
||
|
+ ", mUpperBound='" + mUpperBound + '\''
|
||
|
+ '}';
|
||
|
}
|
||
|
|
||
|
private void validateLowerAndUpperBounds(String lowerBound, String upperBound) {
|
||
|
if (lowerBound.length() != upperBound.length()) {
|
||
|
throw new IllegalArgumentException("Lower and upper bounds must have the same length");
|
||
|
}
|
||
|
if (!Pattern.matches("[0-9]*", lowerBound)) {
|
||
|
throw new IllegalArgumentException("Lower bound must be all numeric");
|
||
|
}
|
||
|
if (!Pattern.matches("[0-9]*", upperBound)) {
|
||
|
throw new IllegalArgumentException("Upper bound must be all numeric");
|
||
|
}
|
||
|
if (Integer.parseInt(lowerBound) > Integer.parseInt(upperBound)) {
|
||
|
throw new IllegalArgumentException("Lower bound must be lower than upper bound");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Checks to see if the provided phone number matches this range.
|
||
|
* @param number A phone number, with or without separators or a country code.
|
||
|
* @return {@code true} if the number matches, {@code false} otherwise.
|
||
|
*/
|
||
|
public boolean matches(@NonNull String number) {
|
||
|
// Check the prefix, make sure it matches either with or without the country code.
|
||
|
String normalizedNumber = number.replaceAll("[^0-9]", "");
|
||
|
String prefixWithCountryCode = mCountryCode + mPrefix;
|
||
|
String numberPostfix;
|
||
|
if (normalizedNumber.startsWith(prefixWithCountryCode)) {
|
||
|
numberPostfix = normalizedNumber.substring(prefixWithCountryCode.length());
|
||
|
} else if (normalizedNumber.startsWith(mPrefix)) {
|
||
|
numberPostfix = normalizedNumber.substring(mPrefix.length());
|
||
|
} else {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
// Next check the postfix to make sure it lies within the bounds.
|
||
|
try {
|
||
|
int lower = Integer.parseInt(mLowerBound);
|
||
|
int upper = Integer.parseInt(mUpperBound);
|
||
|
int numberToCheck = Integer.parseInt(numberPostfix);
|
||
|
return numberToCheck <= upper && numberToCheck >= lower;
|
||
|
} catch (NumberFormatException e) {
|
||
|
Log.e(PhoneNumberRange.class.getSimpleName(), "Invalid bounds or number.", e);
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
}
|