Merge branch 'charlesmchen/swiftPhoneNumberUtil'
This commit is contained in:
commit
b1a2393064
2
Pods
2
Pods
@ -1 +1 @@
|
||||
Subproject commit 174145d81c55573e85e5ab22a59dd824f04ca685
|
||||
Subproject commit 8254c8fc47202f689fe18c4ccfee03a814390ea5
|
||||
@ -361,15 +361,15 @@ extension DeleteAccountConfirmationViewController: CountryCodeViewControllerDele
|
||||
if let localE164 = PhoneNumber(fromE164: localNumber), let localCountryCode = localE164.getCountryCode()?.intValue {
|
||||
callingCodeInt = localCountryCode
|
||||
} else {
|
||||
callingCodeInt = PhoneNumberUtil.sharedThreadLocal().nbPhoneNumberUtil.getCountryCode(
|
||||
callingCodeInt = phoneNumberUtil.getCountryCode(
|
||||
forRegion: PhoneNumber.defaultCountryCode()
|
||||
)?.intValue
|
||||
).intValue
|
||||
}
|
||||
|
||||
var callingCode: String?
|
||||
if let callingCodeInt = callingCodeInt {
|
||||
callingCode = COUNTRY_CODE_PREFIX + "\(callingCodeInt)"
|
||||
countryCode = PhoneNumberUtil.sharedThreadLocal().probableCountryCode(forCallingCode: callingCode!)
|
||||
countryCode = phoneNumberUtil.probableCountryCode(forCallingCode: callingCode!)
|
||||
}
|
||||
|
||||
updateCountry(callingCode: callingCode, countryCode: countryCode)
|
||||
|
||||
@ -28,7 +28,7 @@ public class OnboardingCountryState: NSObject {
|
||||
countryCode = lastRegisteredCountryCode
|
||||
}
|
||||
|
||||
let callingCodeNumber: NSNumber = PhoneNumberUtil.sharedThreadLocal().nbPhoneNumberUtil.getCountryCode(forRegion: countryCode)
|
||||
let callingCodeNumber: NSNumber = phoneNumberUtil.getCountryCode(forRegion: countryCode)
|
||||
let callingCode = "\(COUNTRY_CODE_PREFIX)\(callingCodeNumber)"
|
||||
|
||||
var countryName = NSLocalizedString("UNKNOWN_COUNTRY_NAME", comment: "Label for unknown countries.")
|
||||
|
||||
@ -353,8 +353,7 @@ public class OnboardingPhoneNumberViewController: OnboardingBaseViewController {
|
||||
return nil
|
||||
}
|
||||
let callingCode = "\(COUNTRY_CODE_PREFIX)\(callingCodeNumeric)"
|
||||
let countryCodes: [String] =
|
||||
PhoneNumberUtil.sharedThreadLocal().countryCodes(fromCallingCode: callingCode)
|
||||
let countryCodes: [String] = phoneNumberUtil.countryCodes(fromCallingCode: callingCode)
|
||||
guard let countryCode = countryCodes.first else {
|
||||
owsFailDebug("Could not resume re-registration; unknown countryCode.")
|
||||
return nil
|
||||
|
||||
@ -114,7 +114,8 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
id<PaymentsCurrencies> paymentsCurrencies = [PaymentsCurrenciesImpl new];
|
||||
SpamChallengeResolver *spamChallengeResolver = [SpamChallengeResolver new];
|
||||
AvatarBuilder *avatarBuilder = [AvatarBuilder new];
|
||||
|
||||
PhoneNumberUtil *phoneNumberUtil = [PhoneNumberUtil new];
|
||||
|
||||
[Environment setShared:[[Environment alloc] initWithIncomingContactSyncJobQueue:incomingContactSyncJobQueue
|
||||
incomingGroupSyncJobQueue:incomingGroupSyncJobQueue
|
||||
launchJobs:launchJobs
|
||||
@ -173,7 +174,8 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
payments:payments
|
||||
paymentsCurrencies:paymentsCurrencies
|
||||
spamChallengeResolver:spamChallengeResolver
|
||||
senderKeyStore:senderKeyStore]];
|
||||
senderKeyStore:senderKeyStore
|
||||
phoneNumberUtil:phoneNumberUtil]];
|
||||
|
||||
appSpecificSingletonBlock();
|
||||
|
||||
|
||||
@ -33,8 +33,6 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
withSpecifiedCountryCodeString:(NSString *)countryCodeString;
|
||||
+ (NSString *)bestEffortLocalizedPhoneNumberWithE164:(NSString *)phoneNumber;
|
||||
|
||||
+ (NSString *)regionCodeFromCountryCodeString:(NSString *)countryCodeString;
|
||||
|
||||
- (NSURL *)toSystemDialerURL;
|
||||
- (NSString *)toE164;
|
||||
- (nullable NSNumber *)getCountryCode;
|
||||
|
||||
@ -44,22 +44,20 @@ static NSString *const RPDefaultsKeyPhoneNumberCanonical = @"RPDefaultsKeyPhoneN
|
||||
OWSAssertDebug(text != nil);
|
||||
OWSAssertDebug(regionCode != nil);
|
||||
|
||||
PhoneNumberUtil *phoneUtil = [PhoneNumberUtil sharedThreadLocal];
|
||||
|
||||
NSError *parseError = nil;
|
||||
NBPhoneNumber *number = [phoneUtil parse:text defaultRegion:regionCode error:&parseError];
|
||||
NBPhoneNumber *number = [self.phoneNumberUtil parse:text defaultRegion:regionCode error:&parseError];
|
||||
|
||||
if (parseError) {
|
||||
OWSLogVerbose(@"parseError: %@", parseError);
|
||||
return nil;
|
||||
}
|
||||
|
||||
if (![phoneUtil.nbPhoneNumberUtil isPossibleNumber:number]) {
|
||||
if (![self.phoneNumberUtil isPossibleNumber:number]) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
NSError *toE164Error;
|
||||
NSString *e164 = [phoneUtil format:number numberFormat:NBEPhoneNumberFormatE164 error:&toE164Error];
|
||||
NSString *e164 = [self.phoneNumberUtil format:number numberFormat:NBEPhoneNumberFormatE164 error:&toE164Error];
|
||||
if (toE164Error) {
|
||||
OWSLogDebug(@"Issue while formatting number: %@", [toE164Error description]);
|
||||
return nil;
|
||||
@ -80,7 +78,7 @@ static NSString *const RPDefaultsKeyPhoneNumberCanonical = @"RPDefaultsKeyPhoneN
|
||||
|
||||
NSString *_Nullable countryCode = nil;
|
||||
#if TARGET_OS_IPHONE
|
||||
countryCode = [[PhoneNumberUtil sharedThreadLocal].nbPhoneNumberUtil countryCodeByCarrier];
|
||||
countryCode = [self.phoneNumberUtil countryCodeByCarrier];
|
||||
|
||||
if ([countryCode isEqualToString:@"ZZ"]) {
|
||||
countryCode = [locale objectForKey:NSLocaleCountryCode];
|
||||
@ -212,11 +210,9 @@ static NSString *const RPDefaultsKeyPhoneNumberCanonical = @"RPDefaultsKeyPhoneN
|
||||
return formattedPhoneNumber;
|
||||
}
|
||||
|
||||
+ (NSString *)regionCodeFromCountryCodeString:(NSString *)countryCodeString {
|
||||
NBPhoneNumberUtil *phoneUtil = [PhoneNumberUtil sharedThreadLocal].nbPhoneNumberUtil;
|
||||
NSString *regionCode =
|
||||
[phoneUtil getRegionCodeForCountryCode:@([[countryCodeString substringFromIndex:1] integerValue])];
|
||||
return regionCode;
|
||||
+ (nullable NSString *)regionCodeFromCountryCodeString:(NSString *)countryCodeString {
|
||||
NSNumber *countryCallingCode = @([[countryCodeString substringFromIndex:1] integerValue]);
|
||||
return [self.phoneNumberUtil getRegionCodeForCountryCode:countryCallingCode];
|
||||
}
|
||||
|
||||
+ (nullable PhoneNumber *)tryParsePhoneNumberFromUserSpecifiedText:(NSString *)text {
|
||||
@ -260,7 +256,7 @@ static NSString *const RPDefaultsKeyPhoneNumberCanonical = @"RPDefaultsKeyPhoneN
|
||||
if (localCallingCode != nil) {
|
||||
NSString *localCallingCodePrefix = [NSString stringWithFormat:@"+%@", localCallingCode];
|
||||
NSString *localCountryCode =
|
||||
[PhoneNumberUtil.sharedThreadLocal probableCountryCodeForCallingCode:localCallingCodePrefix];
|
||||
[self.phoneNumberUtil probableCountryCodeForCallingCode:localCallingCodePrefix];
|
||||
if (localCountryCode && ![localCountryCode isEqualToString:[self defaultCountryCode]]) {
|
||||
NBMetadataHelper *helper = [[NBMetadataHelper alloc] init];
|
||||
NBPhoneMetaData *localNumberRegionMetadata = [helper getMetadataForRegion:localCountryCode];
|
||||
@ -396,7 +392,7 @@ static NSString *const RPDefaultsKeyPhoneNumberCanonical = @"RPDefaultsKeyPhoneN
|
||||
// Italian phone number but use French region/language for their
|
||||
// phone. They're likely to have both Italian and French contacts.
|
||||
NSString *localCountryCode =
|
||||
[PhoneNumberUtil.sharedThreadLocal probableCountryCodeForCallingCode:callingCodePrefix];
|
||||
[self.phoneNumberUtil probableCountryCodeForCallingCode:callingCodePrefix];
|
||||
if (localCountryCode && ![localCountryCode isEqualToString:[self defaultCountryCode]]) {
|
||||
tryParsingWithCountryCode([callingCodePrefix stringByAppendingString:text], localCountryCode);
|
||||
}
|
||||
@ -587,9 +583,9 @@ static NSString *const RPDefaultsKeyPhoneNumberCanonical = @"RPDefaultsKeyPhoneN
|
||||
- (nullable NSString *)nationalNumber
|
||||
{
|
||||
NSError *error;
|
||||
NSString *nationalNumber = [[PhoneNumberUtil sharedThreadLocal] format:self.phoneNumber
|
||||
numberFormat:NBEPhoneNumberFormatNATIONAL
|
||||
error:&error];
|
||||
NSString *nationalNumber = [self.phoneNumberUtil format:self.phoneNumber
|
||||
numberFormat:NBEPhoneNumberFormatNATIONAL
|
||||
error:&error];
|
||||
if (error) {
|
||||
OWSLogVerbose(@"error parsing number into national format: %@", error);
|
||||
return nil;
|
||||
@ -600,7 +596,7 @@ static NSString *const RPDefaultsKeyPhoneNumberCanonical = @"RPDefaultsKeyPhoneN
|
||||
|
||||
- (BOOL)isValid
|
||||
{
|
||||
return [[PhoneNumberUtil sharedThreadLocal].nbPhoneNumberUtil isValidNumber:self.phoneNumber];
|
||||
return [self.phoneNumberUtil isValidNumber:self.phoneNumber];
|
||||
}
|
||||
|
||||
- (NSString *)description {
|
||||
|
||||
@ -2,29 +2,22 @@
|
||||
// Copyright (c) 2021 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import <SignalServiceKit/PhoneNumber.h>
|
||||
#import <libPhoneNumber_iOS/NBPhoneNumberUtil.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@class PhoneNumberUtilWrapper;
|
||||
|
||||
@interface PhoneNumberUtil : NSObject
|
||||
|
||||
@property (nonatomic, retain) NBPhoneNumberUtil *nbPhoneNumberUtil;
|
||||
|
||||
+ (instancetype)new NS_UNAVAILABLE;
|
||||
- (instancetype)init NS_UNAVAILABLE;
|
||||
|
||||
+ (instancetype)sharedThreadLocal;
|
||||
// This property should only be accessed by Swift.
|
||||
@property (nonatomic, readonly) PhoneNumberUtilWrapper *phoneNumberUtilWrapper;
|
||||
|
||||
+ (BOOL)name:(NSString *)nameString matchesQuery:(NSString *)queryString;
|
||||
|
||||
+ (NSString *)callingCodeFromCountryCode:(NSString *)countryCode;
|
||||
+ (nullable NSString *)countryNameFromCountryCode:(NSString *)countryCode;
|
||||
+ (NSArray *)countryCodesForSearchTerm:(nullable NSString *)searchTerm;
|
||||
|
||||
// Returns a list of country codes for a calling code in descending
|
||||
// order of population.
|
||||
- (NSArray<NSString *> *)countryCodesFromCallingCode:(NSString *)callingCode;
|
||||
// Returns the most likely country code for a calling code based on population.
|
||||
- (NSString *)probableCountryCodeForCallingCode:(NSString *)callingCode;
|
||||
|
||||
@ -33,12 +26,9 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
to:(NSString *)target
|
||||
stickingRightward:(bool)preferHigh;
|
||||
|
||||
+ (NSString *)examplePhoneNumberForCountryCode:(NSString *)countryCode;
|
||||
|
||||
- (nullable NBPhoneNumber *)parse:(NSString *)numberToParse defaultRegion:(NSString *)defaultRegion error:(NSError **)error;
|
||||
- (NSString *)format:(NBPhoneNumber *)phoneNumber
|
||||
numberFormat:(NBEPhoneNumberFormat)numberFormat
|
||||
error:(NSError **)error;
|
||||
+ (nullable NBPhoneNumber *)getExampleNumberForType:(NSString *)regionCode
|
||||
type:(NBEPhoneNumberType)type
|
||||
nbPhoneNumberUtil:(NBPhoneNumberUtil *)nbPhoneNumberUtil;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@ -3,85 +3,26 @@
|
||||
//
|
||||
|
||||
#import "PhoneNumberUtil.h"
|
||||
#import "ContactsManagerProtocol.h"
|
||||
#import "FunctionalUtil.h"
|
||||
#import <SignalServiceKit/SignalServiceKit-Swift.h>
|
||||
#import <libPhoneNumber_iOS/NBPhoneNumber.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface PhoneNumberUtil ()
|
||||
|
||||
@property (nonatomic, readonly) NSMutableDictionary *countryCodesFromCallingCodeCache;
|
||||
@property (nonatomic, readonly) AnyLRUCache *parsedPhoneNumberCache;
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark -
|
||||
|
||||
@implementation PhoneNumberUtil
|
||||
|
||||
+ (PhoneNumberUtil *)sharedThreadLocal
|
||||
{
|
||||
NSString *key = PhoneNumberUtil.logTag;
|
||||
PhoneNumberUtil *_Nullable threadLocal = NSThread.currentThread.threadDictionary[key];
|
||||
if (!threadLocal) {
|
||||
threadLocal = [PhoneNumberUtil new];
|
||||
NSThread.currentThread.threadDictionary[key] = threadLocal;
|
||||
}
|
||||
return threadLocal;
|
||||
}
|
||||
|
||||
- (instancetype)init {
|
||||
self = [super init];
|
||||
|
||||
if (self) {
|
||||
_nbPhoneNumberUtil = [[NBPhoneNumberUtil alloc] init];
|
||||
_countryCodesFromCallingCodeCache = [NSMutableDictionary new];
|
||||
_parsedPhoneNumberCache = [[AnyLRUCache alloc] initWithMaxSize:256 nseMaxSize:0 shouldEvacuateInBackground:NO];
|
||||
_phoneNumberUtilWrapper = [PhoneNumberUtilWrapper new];
|
||||
}
|
||||
|
||||
OWSSingletonAssert();
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (nullable NBPhoneNumber *)parse:(NSString *)numberToParse
|
||||
defaultRegion:(NSString *)defaultRegion
|
||||
error:(NSError **)error
|
||||
{
|
||||
NSString *hashKey = [NSString stringWithFormat:@"numberToParse:%@defaultRegion:%@", numberToParse, defaultRegion];
|
||||
|
||||
NBPhoneNumber *_Nullable result = (NBPhoneNumber *)[self.parsedPhoneNumberCache objectForKey:hashKey];
|
||||
|
||||
if (!result) {
|
||||
result = [self.nbPhoneNumberUtil parse:numberToParse defaultRegion:defaultRegion error:error];
|
||||
if (error && *error) {
|
||||
OWSAssertDebug(!result);
|
||||
return nil;
|
||||
}
|
||||
|
||||
OWSAssertDebug(result);
|
||||
|
||||
if (result) {
|
||||
[self.parsedPhoneNumberCache setObject:result forKey:hashKey];
|
||||
} else {
|
||||
[self.parsedPhoneNumberCache setObject:[NSNull null] forKey:hashKey];
|
||||
}
|
||||
}
|
||||
|
||||
if ([result class] == [NSNull class]) {
|
||||
return nil;
|
||||
} else {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
- (NSString *)format:(NBPhoneNumber *)phoneNumber
|
||||
numberFormat:(NBEPhoneNumberFormat)numberFormat
|
||||
error:(NSError **)error
|
||||
{
|
||||
return [self.nbPhoneNumberUtil format:phoneNumber numberFormat:numberFormat error:error];
|
||||
}
|
||||
|
||||
// country code -> country name
|
||||
+ (nullable NSString *)countryNameFromCountryCode:(NSString *)countryCode
|
||||
{
|
||||
@ -102,82 +43,6 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
return countryName;
|
||||
}
|
||||
|
||||
// country code -> calling code
|
||||
+ (NSString *)callingCodeFromCountryCode:(NSString *)countryCode
|
||||
{
|
||||
if (countryCode.length < 1) {
|
||||
return @"+0";
|
||||
}
|
||||
|
||||
if ([countryCode isEqualToString:@"AQ"]) {
|
||||
// Antarctica
|
||||
return @"+672";
|
||||
} else if ([countryCode isEqualToString:@"BV"]) {
|
||||
// Bouvet Island
|
||||
return @"+55";
|
||||
} else if ([countryCode isEqualToString:@"IC"]) {
|
||||
// Canary Islands
|
||||
return @"+34";
|
||||
} else if ([countryCode isEqualToString:@"EA"]) {
|
||||
// Ceuta & Melilla
|
||||
return @"+34";
|
||||
} else if ([countryCode isEqualToString:@"CP"]) {
|
||||
// Clipperton Island
|
||||
//
|
||||
// This country code should be filtered - it does not appear to have a calling code.
|
||||
return nil;
|
||||
} else if ([countryCode isEqualToString:@"DG"]) {
|
||||
// Diego Garcia
|
||||
return @"+246";
|
||||
} else if ([countryCode isEqualToString:@"TF"]) {
|
||||
// French Southern Territories
|
||||
return @"+262";
|
||||
} else if ([countryCode isEqualToString:@"HM"]) {
|
||||
// Heard & McDonald Islands
|
||||
return @"+672";
|
||||
} else if ([countryCode isEqualToString:@"XK"]) {
|
||||
// Kosovo
|
||||
return @"+383";
|
||||
} else if ([countryCode isEqualToString:@"PN"]) {
|
||||
// Pitcairn Islands
|
||||
return @"+64";
|
||||
} else if ([countryCode isEqualToString:@"GS"]) {
|
||||
// So. Georgia & So. Sandwich Isl.
|
||||
return @"+500";
|
||||
} else if ([countryCode isEqualToString:@"UM"]) {
|
||||
// U.S. Outlying Islands
|
||||
return @"+1";
|
||||
}
|
||||
|
||||
NSString *callingCode =
|
||||
[NSString stringWithFormat:@"%@%@",
|
||||
COUNTRY_CODE_PREFIX,
|
||||
[[[self sharedThreadLocal] nbPhoneNumberUtil] getCountryCodeForRegion:countryCode]];
|
||||
return callingCode;
|
||||
}
|
||||
|
||||
- (NSArray<NSString *> *)countryCodesFromCallingCode:(NSString *)callingCode
|
||||
{
|
||||
@synchronized(self)
|
||||
{
|
||||
OWSAssertDebug(callingCode.length > 0);
|
||||
|
||||
NSArray *result = self.countryCodesFromCallingCodeCache[callingCode];
|
||||
if (!result) {
|
||||
NSMutableArray *countryCodes = [NSMutableArray new];
|
||||
for (NSString *countryCode in [PhoneNumberUtil countryCodesSortedByPopulationDescending]) {
|
||||
NSString *callingCodeForCountryCode = [PhoneNumberUtil callingCodeFromCountryCode:countryCode];
|
||||
if ([callingCode isEqualToString:callingCodeForCountryCode]) {
|
||||
[countryCodes addObject:countryCode];
|
||||
}
|
||||
}
|
||||
result = [countryCodes copy];
|
||||
self.countryCodesFromCallingCodeCache[callingCode] = result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
- (NSString *)probableCountryCodeForCallingCode:(NSString *)callingCode
|
||||
{
|
||||
OWSAssertDebug(callingCode.length > 0);
|
||||
@ -315,28 +180,16 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
}
|
||||
}
|
||||
|
||||
+ (NSString *)examplePhoneNumberForCountryCode:(NSString *)countryCode
|
||||
+ (nullable NBPhoneNumber *)getExampleNumberForType:(NSString *)regionCode
|
||||
type:(NBEPhoneNumberType)type
|
||||
nbPhoneNumberUtil:(NBPhoneNumberUtil *)nbPhoneNumberUtil
|
||||
{
|
||||
PhoneNumberUtil *sharedUtil = [self sharedThreadLocal];
|
||||
|
||||
// Signal users are very likely using mobile devices, so prefer that kind of example.
|
||||
NSError *error;
|
||||
NBPhoneNumber *nbPhoneNumber =
|
||||
[sharedUtil.nbPhoneNumberUtil getExampleNumberForType:countryCode type:NBEPhoneNumberTypeMOBILE error:&error];
|
||||
OWSAssertDebug(!error);
|
||||
if (!nbPhoneNumber) {
|
||||
// For countries that with similar mobile and land lines, use "line or mobile"
|
||||
// examples.
|
||||
nbPhoneNumber = [sharedUtil.nbPhoneNumberUtil getExampleNumberForType:countryCode
|
||||
type:NBEPhoneNumberTypeFIXED_LINE_OR_MOBILE
|
||||
error:&error];
|
||||
OWSAssertDebug(!error);
|
||||
NBPhoneNumber *_Nullable nbPhoneNumber = [nbPhoneNumberUtil getExampleNumberForType:regionCode type:type error:&error];
|
||||
if (error != nil) {
|
||||
OWSFailDebug(@"Error: %@", error);
|
||||
}
|
||||
NSString *result = (nbPhoneNumber
|
||||
? [sharedUtil.nbPhoneNumberUtil format:nbPhoneNumber numberFormat:NBEPhoneNumberFormatE164 error:&error]
|
||||
: nil);
|
||||
OWSAssertDebug(!error);
|
||||
return result;
|
||||
return nbPhoneNumber;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@ -3,10 +3,247 @@
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import libPhoneNumber_iOS
|
||||
|
||||
@objc
|
||||
public class PhoneNumberUtilWrapper: NSObject {
|
||||
|
||||
fileprivate let nbPhoneNumberUtil = NBPhoneNumberUtil()
|
||||
fileprivate var countryCodesFromCallingCodeCache = [String: [String]]()
|
||||
fileprivate let parsedPhoneNumberCache = LRUCache<String, NBPhoneNumber>(maxSize: 256, nseMaxSize: 0, shouldEvacuateInBackground: false)
|
||||
}
|
||||
|
||||
// MARK: -
|
||||
|
||||
fileprivate extension PhoneNumberUtilWrapper {
|
||||
|
||||
// country code -> calling code
|
||||
func callingCode(fromCountryCode countryCode: String) -> String? {
|
||||
guard let countryCode = countryCode.nilIfEmpty else {
|
||||
return "+0"
|
||||
}
|
||||
|
||||
if countryCode == "AQ" {
|
||||
// Antarctica
|
||||
return "+672"
|
||||
} else if countryCode == "BV" {
|
||||
// Bouvet Island
|
||||
return "+55"
|
||||
} else if countryCode == "IC" {
|
||||
// Canary Islands
|
||||
return "+34"
|
||||
} else if countryCode == "EA" {
|
||||
// Ceuta & Melilla
|
||||
return "+34"
|
||||
} else if countryCode == "CP" {
|
||||
// Clipperton Island
|
||||
//
|
||||
// This country code should be filtered - it does not appear to have a calling code.
|
||||
return nil
|
||||
} else if countryCode == "DG" {
|
||||
// Diego Garcia
|
||||
return "+246"
|
||||
} else if countryCode == "TF" {
|
||||
// French Southern Territories
|
||||
return "+262"
|
||||
} else if countryCode == "HM" {
|
||||
// Heard & McDonald Islands
|
||||
return "+672"
|
||||
} else if countryCode == "XK" {
|
||||
// Kosovo
|
||||
return "+383"
|
||||
} else if countryCode == "PN" {
|
||||
// Pitcairn Islands
|
||||
return "+64"
|
||||
} else if countryCode == "GS" {
|
||||
// So. Georgia & So. Sandwich Isl.
|
||||
return "+500"
|
||||
} else if countryCode == "UM" {
|
||||
// U.S. Outlying Islands
|
||||
return "+1"
|
||||
}
|
||||
|
||||
let countryCallingCode = getCountryCode(forRegion: countryCode)
|
||||
let callingCode = COUNTRY_CODE_PREFIX + "\(countryCallingCode.intValue)"
|
||||
return callingCode
|
||||
}
|
||||
|
||||
// Returns a list of country codes for a calling code in descending
|
||||
// order of population.
|
||||
func countryCodes(fromCallingCode callingCode: String) -> [String] {
|
||||
guard let callingCode = callingCode.nilIfEmpty else {
|
||||
return []
|
||||
}
|
||||
if let cachedValue = countryCodesFromCallingCodeCache[callingCode] {
|
||||
return cachedValue
|
||||
}
|
||||
let countryCodes: [String] = Self.countryCodesSortedByPopulationDescending.compactMap { (countryCode: String) -> String? in
|
||||
let callingCodeForCountryCode: String? = self.callingCode(fromCountryCode: countryCode)
|
||||
guard callingCode == callingCodeForCountryCode else {
|
||||
return nil
|
||||
}
|
||||
return countryCode
|
||||
}
|
||||
countryCodesFromCallingCodeCache[callingCode] = countryCodes
|
||||
return countryCodes
|
||||
}
|
||||
|
||||
func format(phoneNumber: NBPhoneNumber, numberFormat: NBEPhoneNumberFormat) throws -> String {
|
||||
try nbPhoneNumberUtil.format(phoneNumber, numberFormat: numberFormat)
|
||||
}
|
||||
|
||||
func parse(_ numberToParse: String, defaultRegion: String) throws -> NBPhoneNumber {
|
||||
let hashKey = "numberToParse:\(numberToParse), defaultRegion:\(defaultRegion)"
|
||||
if let cachedValue = parsedPhoneNumberCache[hashKey] {
|
||||
return cachedValue
|
||||
}
|
||||
let result = try nbPhoneNumberUtil.parse(numberToParse, defaultRegion: defaultRegion)
|
||||
parsedPhoneNumberCache[hashKey] = result
|
||||
return result
|
||||
}
|
||||
|
||||
func examplePhoneNumber(forCountryCode countryCode: String) -> String? {
|
||||
// Signal users are very likely using mobile devices, so prefer that kind of example.
|
||||
do {
|
||||
func findExamplePhoneNumber() -> NBPhoneNumber? {
|
||||
if let nbPhoneNumber = PhoneNumberUtil.getExampleNumber(forType: countryCode,
|
||||
type: .MOBILE,
|
||||
nbPhoneNumberUtil: nbPhoneNumberUtil) {
|
||||
return nbPhoneNumber
|
||||
}
|
||||
if let nbPhoneNumber = PhoneNumberUtil.getExampleNumber(forType: countryCode,
|
||||
type: .FIXED_LINE_OR_MOBILE,
|
||||
nbPhoneNumberUtil: nbPhoneNumberUtil) {
|
||||
return nbPhoneNumber
|
||||
}
|
||||
return nil
|
||||
}
|
||||
guard let nbPhoneNumber = findExamplePhoneNumber() else {
|
||||
if CurrentAppContext().isRunningTests {
|
||||
Logger.warn("Could not find example phone number for: \(countryCode)")
|
||||
} else {
|
||||
owsFailDebug("Could not find example phone number for: \(countryCode)")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
return try nbPhoneNumberUtil.format(nbPhoneNumber, numberFormat: .E164)
|
||||
} catch {
|
||||
if CurrentAppContext().isRunningTests {
|
||||
Logger.warn("Error: \(error)")
|
||||
} else {
|
||||
owsFailDebug("Error: \(error)")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func isPossibleNumber(_ number: NBPhoneNumber) -> Bool {
|
||||
nbPhoneNumberUtil.isPossibleNumber(number)
|
||||
}
|
||||
|
||||
func countryCodeByCarrier() -> String {
|
||||
nbPhoneNumberUtil.countryCodeByCarrier()
|
||||
}
|
||||
|
||||
func getRegionCodeForCountryCode(_ countryCallingCode: NSNumber) -> String? {
|
||||
nbPhoneNumberUtil.getRegionCode(forCountryCode: countryCallingCode)
|
||||
}
|
||||
|
||||
func isValidNumber(_ number: NBPhoneNumber) -> Bool {
|
||||
nbPhoneNumberUtil.isValidNumber(number)
|
||||
}
|
||||
|
||||
func getCountryCode(forRegion regionCode: String) -> NSNumber {
|
||||
nbPhoneNumberUtil.getCountryCode(forRegion: regionCode)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: -
|
||||
|
||||
@objc
|
||||
extension PhoneNumberUtil {
|
||||
public static let countryCodesSortedByPopulationDescending: [String] = [
|
||||
private static let unfairLock = UnfairLock()
|
||||
private var unfairLock: UnfairLock { Self.unfairLock }
|
||||
|
||||
@objc(callingCodeFromCountryCode:)
|
||||
public static func callingCode(fromCountryCode countryCode: String) -> String? {
|
||||
shared.callingCode(fromCountryCode: countryCode)
|
||||
}
|
||||
|
||||
@objc(callingCodeFromCountryCode:)
|
||||
public func callingCode(fromCountryCode countryCode: String) -> String? {
|
||||
unfairLock.withLock {
|
||||
phoneNumberUtilWrapper.callingCode(fromCountryCode: countryCode)
|
||||
}
|
||||
}
|
||||
|
||||
@objc(countryCodesFromCallingCode:)
|
||||
public static func countryCodes(fromCallingCode callingCode: String) -> [String] {
|
||||
shared.countryCodes(fromCallingCode: callingCode)
|
||||
}
|
||||
|
||||
// Returns a list of country codes for a calling code in descending
|
||||
// order of population.
|
||||
@objc(countryCodesFromCallingCode:)
|
||||
public func countryCodes(fromCallingCode callingCode: String) -> [String] {
|
||||
unfairLock.withLock {
|
||||
phoneNumberUtilWrapper.countryCodes(fromCallingCode: callingCode)
|
||||
}
|
||||
}
|
||||
|
||||
public func format(_ phoneNumber: NBPhoneNumber, numberFormat: NBEPhoneNumberFormat) throws -> String {
|
||||
try unfairLock.withLock {
|
||||
try phoneNumberUtilWrapper.format(phoneNumber: phoneNumber, numberFormat: numberFormat)
|
||||
}
|
||||
}
|
||||
|
||||
public func parse(_ numberToParse: String, defaultRegion: String) throws -> NBPhoneNumber {
|
||||
try unfairLock.withLock {
|
||||
try phoneNumberUtilWrapper.parse(numberToParse, defaultRegion: defaultRegion)
|
||||
}
|
||||
}
|
||||
|
||||
public func examplePhoneNumber(forCountryCode countryCode: String) -> String? {
|
||||
unfairLock.withLock {
|
||||
phoneNumberUtilWrapper.examplePhoneNumber(forCountryCode: countryCode)
|
||||
}
|
||||
}
|
||||
|
||||
public func isPossibleNumber(_ number: NBPhoneNumber) -> Bool {
|
||||
unfairLock.withLock {
|
||||
phoneNumberUtilWrapper.isPossibleNumber(number)
|
||||
}
|
||||
}
|
||||
|
||||
public func countryCodeByCarrier() -> String {
|
||||
unfairLock.withLock {
|
||||
phoneNumberUtilWrapper.countryCodeByCarrier()
|
||||
}
|
||||
}
|
||||
|
||||
public func getRegionCodeForCountryCode(_ countryCallingCode: NSNumber) -> String? {
|
||||
unfairLock.withLock {
|
||||
phoneNumberUtilWrapper.getRegionCodeForCountryCode(countryCallingCode)
|
||||
}
|
||||
}
|
||||
|
||||
public func isValidNumber(_ number: NBPhoneNumber) -> Bool {
|
||||
unfairLock.withLock {
|
||||
phoneNumberUtilWrapper.isValidNumber(number)
|
||||
}
|
||||
}
|
||||
|
||||
public func getCountryCode(forRegion regionCode: String) -> NSNumber {
|
||||
unfairLock.withLock {
|
||||
phoneNumberUtilWrapper.getCountryCode(forRegion: regionCode)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: -
|
||||
|
||||
fileprivate extension PhoneNumberUtilWrapper {
|
||||
static let countryCodesSortedByPopulationDescending: [String] = [
|
||||
"CN", // 1330044000
|
||||
"IN", // 1173108018
|
||||
"US", // 310232863
|
||||
|
||||
@ -29,6 +29,7 @@ extern NSNotificationName const WarmCachesNotification;
|
||||
@class OWSMessagePipelineSupervisor;
|
||||
@class OWSOutgoingReceiptManager;
|
||||
@class OWSReceiptManager;
|
||||
@class PhoneNumberUtil;
|
||||
@class SDSDatabaseStorage;
|
||||
@class SSKPreKeyStore;
|
||||
@class SSKPreferences;
|
||||
@ -112,7 +113,8 @@ extern NSNotificationName const WarmCachesNotification;
|
||||
payments:(id<Payments>)payments
|
||||
paymentsCurrencies:(id<PaymentsCurrencies>)paymentsCurrencies
|
||||
spamChallengeResolver:(SpamChallengeResolver *)spamResolver
|
||||
senderKeyStore:(SenderKeyStore *)senderKeyStore NS_DESIGNATED_INITIALIZER;
|
||||
senderKeyStore:(SenderKeyStore *)senderKeyStore
|
||||
phoneNumberUtil:(PhoneNumberUtil *)phoneNumberUtil NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
@property (nonatomic, readonly, class) SSKEnvironment *shared;
|
||||
|
||||
@ -174,6 +176,7 @@ extern NSNotificationName const WarmCachesNotification;
|
||||
@property (nonatomic, readonly) id<PaymentsCurrencies> paymentsCurrenciesRef;
|
||||
@property (nonatomic, readonly) SpamChallengeResolver *spamChallengeResolverRef;
|
||||
@property (nonatomic, readonly) SenderKeyStore *senderKeyStoreRef;
|
||||
@property (nonatomic, readonly) PhoneNumberUtil *phoneNumberUtilRef;
|
||||
|
||||
// This property is configured after Environment is created.
|
||||
@property (atomic, nullable) id<OWSCallMessageHandler> callMessageHandlerRef;
|
||||
|
||||
@ -55,6 +55,7 @@ static SSKEnvironment *sharedSSKEnvironment;
|
||||
@property (nonatomic) id<PaymentsCurrencies> paymentsCurrenciesRef;
|
||||
@property (nonatomic) SpamChallengeResolver *spamChallengeResolverRef;
|
||||
@property (nonatomic) SenderKeyStore *senderKeyStoreRef;
|
||||
@property (nonatomic) PhoneNumberUtil *phoneNumberUtilRef;
|
||||
|
||||
@end
|
||||
|
||||
@ -114,6 +115,7 @@ static SSKEnvironment *sharedSSKEnvironment;
|
||||
paymentsCurrencies:(id<PaymentsCurrencies>)paymentsCurrencies
|
||||
spamChallengeResolver:(SpamChallengeResolver *)spamResolver
|
||||
senderKeyStore:(SenderKeyStore *)senderKeyStore
|
||||
phoneNumberUtil:(PhoneNumberUtil *)phoneNumberUtil
|
||||
{
|
||||
self = [super init];
|
||||
if (!self) {
|
||||
@ -169,7 +171,8 @@ static SSKEnvironment *sharedSSKEnvironment;
|
||||
_paymentsCurrenciesRef = paymentsCurrencies;
|
||||
_spamChallengeResolverRef = spamResolver;
|
||||
_senderKeyStoreRef = senderKeyStore;
|
||||
|
||||
_phoneNumberUtilRef = phoneNumberUtil;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
@ -89,6 +89,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
id<PaymentsCurrencies> paymentsCurrencies = [MockPaymentsCurrencies new];
|
||||
SpamChallengeResolver *spamChallengeResolver = [SpamChallengeResolver new];
|
||||
SenderKeyStore *senderKeyStore = [SenderKeyStore new];
|
||||
PhoneNumberUtil *phoneNumberUtil = [PhoneNumberUtil new];
|
||||
|
||||
self = [super initWithContactsManager:contactsManager
|
||||
linkPreviewManager:linkPreviewManager
|
||||
@ -138,7 +139,8 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
payments:payments
|
||||
paymentsCurrencies:paymentsCurrencies
|
||||
spamChallengeResolver:spamChallengeResolver
|
||||
senderKeyStore:senderKeyStore];
|
||||
senderKeyStore:senderKeyStore
|
||||
phoneNumberUtil:phoneNumberUtil];
|
||||
|
||||
if (!self) {
|
||||
return nil;
|
||||
|
||||
@ -473,6 +473,14 @@ public extension NSObject {
|
||||
static var appVersion: AppVersion {
|
||||
AppVersion.shared()
|
||||
}
|
||||
|
||||
var phoneNumberUtil: PhoneNumberUtil {
|
||||
SSKEnvironment.shared.phoneNumberUtilRef
|
||||
}
|
||||
|
||||
static var phoneNumberUtil: PhoneNumberUtil {
|
||||
SSKEnvironment.shared.phoneNumberUtilRef
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Obj-C Dependencies
|
||||
@ -938,6 +946,14 @@ public extension Dependencies {
|
||||
static var appVersion: AppVersion {
|
||||
AppVersion.shared()
|
||||
}
|
||||
|
||||
var phoneNumberUtil: PhoneNumberUtil {
|
||||
SSKEnvironment.shared.phoneNumberUtilRef
|
||||
}
|
||||
|
||||
static var phoneNumberUtil: PhoneNumberUtil {
|
||||
SSKEnvironment.shared.phoneNumberUtilRef
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Swift-only Dependencies
|
||||
@ -1164,3 +1180,12 @@ public extension OWSDisappearingMessagesJob {
|
||||
SSKEnvironment.shared.disappearingMessagesJobRef
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: -
|
||||
|
||||
@objc
|
||||
public extension PhoneNumberUtil {
|
||||
static var shared: PhoneNumberUtil {
|
||||
SSKEnvironment.shared.phoneNumberUtilRef
|
||||
}
|
||||
}
|
||||
|
||||
@ -4,6 +4,7 @@
|
||||
|
||||
#import "PhoneNumberUtil.h"
|
||||
#import "SSKBaseTestObjC.h"
|
||||
#import <SignalServiceKit/SignalServiceKit-Swift.h>
|
||||
|
||||
@interface PhoneNumberUtilTest : SSKBaseTestObjC
|
||||
|
||||
|
||||
193
SignalServiceKit/tests/Contacts/PhoneNumberUtilTest.swift
Normal file
193
SignalServiceKit/tests/Contacts/PhoneNumberUtilTest.swift
Normal file
@ -0,0 +1,193 @@
|
||||
//
|
||||
// Copyright (c) 2021 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
import SignalServiceKit
|
||||
|
||||
class PhoneNumberUtilTestSwift: SSKBaseTestSwift {
|
||||
|
||||
func test_callingCodeFromCountryCode() {
|
||||
XCTAssertEqual("+1", phoneNumberUtil.callingCode(fromCountryCode: "US"))
|
||||
XCTAssertEqual("+598", phoneNumberUtil.callingCode(fromCountryCode: "UY"))
|
||||
XCTAssertEqual("+0", phoneNumberUtil.callingCode(fromCountryCode: "QG"))
|
||||
XCTAssertEqual("+0", phoneNumberUtil.callingCode(fromCountryCode: ""))
|
||||
XCTAssertEqual("+0", phoneNumberUtil.callingCode(fromCountryCode: "+"))
|
||||
XCTAssertEqual("+0", phoneNumberUtil.callingCode(fromCountryCode: "9"))
|
||||
XCTAssertEqual("+1", phoneNumberUtil.callingCode(fromCountryCode: "US "))
|
||||
}
|
||||
|
||||
func test_countryCodesFromCallingCode() {
|
||||
// Order matters here.
|
||||
XCTAssertEqual(["US", "CA", "DO", "PR", "JM", "TT", "BS", "BB", "LC", "GU", "VI", "GD", "VC", "AG", "DM", "BM", "AS", "MP", "KN", "KY", "SX", "VG", "TC", "AI", "MS", "UM"], phoneNumberUtil.countryCodes(fromCallingCode: "+1"))
|
||||
XCTAssertEqual(["GB", "JE", "IM", "GG"], phoneNumberUtil.countryCodes(fromCallingCode: "+44"))
|
||||
XCTAssertEqual(["UY"], phoneNumberUtil.countryCodes(fromCallingCode: "+598"))
|
||||
XCTAssertEqual([], phoneNumberUtil.countryCodes(fromCallingCode: "+7945"))
|
||||
XCTAssertEqual([], phoneNumberUtil.countryCodes(fromCallingCode: "+"))
|
||||
XCTAssertEqual([], phoneNumberUtil.countryCodes(fromCallingCode: ""))
|
||||
XCTAssertEqual([], phoneNumberUtil.countryCodes(fromCallingCode: " "))
|
||||
XCTAssertEqual([], phoneNumberUtil.countryCodes(fromCallingCode: "a"))
|
||||
XCTAssertEqual([], phoneNumberUtil.countryCodes(fromCallingCode: "++598"))
|
||||
XCTAssertEqual([], phoneNumberUtil.countryCodes(fromCallingCode: "+1 "))
|
||||
XCTAssertEqual([], phoneNumberUtil.countryCodes(fromCallingCode: " +1"))
|
||||
}
|
||||
|
||||
func test_parse() {
|
||||
XCTAssertEqual(NSNumber(value: 1), try! phoneNumberUtil.parse("+13334445555", defaultRegion: "US").countryCode)
|
||||
XCTAssertEqual(NSNumber(value: 1), try! phoneNumberUtil.parse("+13334445555", defaultRegion: "GB").countryCode)
|
||||
XCTAssertEqual(NSNumber(value: 1), try! phoneNumberUtil.parse("+13334445555", defaultRegion: "UY").countryCode)
|
||||
XCTAssertEqual(NSNumber(value: 44), try! phoneNumberUtil.parse("+441752395464", defaultRegion: "US").countryCode)
|
||||
XCTAssertEqual(NSNumber(value: 44), try! phoneNumberUtil.parse("+441752395464", defaultRegion: "GB").countryCode)
|
||||
XCTAssertEqual(NSNumber(value: 44), try! phoneNumberUtil.parse("+441752395464", defaultRegion: "UY").countryCode)
|
||||
// Invalid regions.
|
||||
XCTAssertEqual(NSNumber(value: 1), try! phoneNumberUtil.parse("+13334445555", defaultRegion: "UK").countryCode)
|
||||
XCTAssertEqual(NSNumber(value: 44), try! phoneNumberUtil.parse("+441752395464", defaultRegion: "UK").countryCode)
|
||||
XCTAssertEqual(NSNumber(value: 1), try! phoneNumberUtil.parse("+13334445555", defaultRegion: "ZQ").countryCode)
|
||||
XCTAssertEqual(NSNumber(value: 1), try! phoneNumberUtil.parse("+13334445555", defaultRegion: "").countryCode)
|
||||
XCTAssertEqual(NSNumber(value: 1), try! phoneNumberUtil.parse("+13334445555", defaultRegion: "99").countryCode)
|
||||
XCTAssertEqual(NSNumber(value: 1), try! phoneNumberUtil.parse("+13334445555", defaultRegion: "+").countryCode)
|
||||
XCTAssertEqual(NSNumber(value: 1), try! phoneNumberUtil.parse("+13334445555", defaultRegion: " ").countryCode)
|
||||
// Invalid phone numbers.
|
||||
XCTAssertEqual(NSNumber(value: 1), try! phoneNumberUtil.parse("+1333444555", defaultRegion: "UY").countryCode)
|
||||
XCTAssertEqual(NSNumber(value: 44), try! phoneNumberUtil.parse("+44175239546", defaultRegion: "UY").countryCode)
|
||||
XCTAssertEqual(NSNumber(value: 44), try! phoneNumberUtil.parse("+441752395468 ", defaultRegion: "UY").countryCode)
|
||||
XCTAssertEqual(NSNumber(value: 1), try! phoneNumberUtil.parse("++13334445555 ", defaultRegion: "UY").countryCode)
|
||||
|
||||
do {
|
||||
_ = try phoneNumberUtil.parse("+9764", defaultRegion: "US")
|
||||
XCTFail("Missing expected error.")
|
||||
} catch {
|
||||
// Error is expected.
|
||||
}
|
||||
do {
|
||||
_ = try phoneNumberUtil.parse("", defaultRegion: "US")
|
||||
XCTFail("Missing expected error.")
|
||||
} catch {
|
||||
// Error is expected.
|
||||
}
|
||||
do {
|
||||
_ = try phoneNumberUtil.parse(" ", defaultRegion: "US")
|
||||
XCTFail("Missing expected error.")
|
||||
} catch {
|
||||
// Error is expected.
|
||||
}
|
||||
do {
|
||||
_ = try phoneNumberUtil.parse("a", defaultRegion: "US")
|
||||
XCTFail("Missing expected error.")
|
||||
} catch {
|
||||
// Error is expected.
|
||||
}
|
||||
do {
|
||||
_ = try phoneNumberUtil.parse("+", defaultRegion: "US")
|
||||
XCTFail("Missing expected error.")
|
||||
} catch {
|
||||
// Error is expected.
|
||||
}
|
||||
do {
|
||||
_ = try phoneNumberUtil.parse("9876543210987654321098765432109876543210", defaultRegion: "US")
|
||||
XCTFail("Missing expected error.")
|
||||
} catch {
|
||||
// Error is expected.
|
||||
}
|
||||
do {
|
||||
_ = try phoneNumberUtil.parse("+9876543210987654321098765432109876543210", defaultRegion: "US")
|
||||
XCTFail("Missing expected error.")
|
||||
} catch {
|
||||
// Error is expected.
|
||||
}
|
||||
}
|
||||
|
||||
func test_format() {
|
||||
let phoneNumber1 = try! phoneNumberUtil.parse("+13334445555", defaultRegion: "US")
|
||||
let phoneNumber2 = try! phoneNumberUtil.parse("+441752395464", defaultRegion: "US")
|
||||
|
||||
XCTAssertEqual("+13334445555", try! phoneNumberUtil.format(phoneNumber1, numberFormat: .E164))
|
||||
XCTAssertEqual("(333) 444-5555", try! phoneNumberUtil.format(phoneNumber1, numberFormat: .NATIONAL))
|
||||
XCTAssertEqual("+1 333-444-5555", try! phoneNumberUtil.format(phoneNumber1, numberFormat: .INTERNATIONAL))
|
||||
XCTAssertEqual("tel:+1-333-444-5555", try! phoneNumberUtil.format(phoneNumber1, numberFormat: .RFC3966))
|
||||
|
||||
XCTAssertEqual("+441752395464", try! phoneNumberUtil.format(phoneNumber2, numberFormat: .E164))
|
||||
XCTAssertEqual("01752 395464", try! phoneNumberUtil.format(phoneNumber2, numberFormat: .NATIONAL))
|
||||
XCTAssertEqual("+44 1752 395464", try! phoneNumberUtil.format(phoneNumber2, numberFormat: .INTERNATIONAL))
|
||||
XCTAssertEqual("tel:+44-1752-395464", try! phoneNumberUtil.format(phoneNumber2, numberFormat: .RFC3966))
|
||||
}
|
||||
|
||||
func test_examplePhoneNumberForCountryCode() {
|
||||
XCTAssertEqual("+12015550123", phoneNumberUtil.examplePhoneNumber(forCountryCode: "US"))
|
||||
XCTAssertEqual("+447400123456", phoneNumberUtil.examplePhoneNumber(forCountryCode: "GB"))
|
||||
XCTAssertEqual("+59894231234", phoneNumberUtil.examplePhoneNumber(forCountryCode: "UY"))
|
||||
XCTAssertNil(phoneNumberUtil.examplePhoneNumber(forCountryCode: "+1"))
|
||||
XCTAssertNil(phoneNumberUtil.examplePhoneNumber(forCountryCode: "44"))
|
||||
XCTAssertNil(phoneNumberUtil.examplePhoneNumber(forCountryCode: " "))
|
||||
XCTAssertNil(phoneNumberUtil.examplePhoneNumber(forCountryCode: ""))
|
||||
XCTAssertNil(phoneNumberUtil.examplePhoneNumber(forCountryCode: "UK "))
|
||||
XCTAssertNil(phoneNumberUtil.examplePhoneNumber(forCountryCode: "UKK"))
|
||||
}
|
||||
|
||||
func test_isPossibleNumber() {
|
||||
let phoneNumber1 = try! phoneNumberUtil.parse("+13334445555", defaultRegion: "US")
|
||||
let phoneNumber2 = try! phoneNumberUtil.parse("+441752395464", defaultRegion: "US")
|
||||
// Invalid numbers.
|
||||
let phoneNumber3 = try! phoneNumberUtil.parse("+44175239546", defaultRegion: "US")
|
||||
let phoneNumber4 = try! phoneNumberUtil.parse("44", defaultRegion: "US")
|
||||
|
||||
XCTAssertEqual(true, phoneNumberUtil.isPossibleNumber(phoneNumber1))
|
||||
XCTAssertEqual(true, phoneNumberUtil.isPossibleNumber(phoneNumber2))
|
||||
XCTAssertEqual(true, phoneNumberUtil.isPossibleNumber(phoneNumber3))
|
||||
XCTAssertEqual(false, phoneNumberUtil.isPossibleNumber(phoneNumber4))
|
||||
}
|
||||
|
||||
func test_isValidNumber() {
|
||||
let phoneNumber1 = try! phoneNumberUtil.parse("+12125556789", defaultRegion: "US")
|
||||
let phoneNumber2 = try! phoneNumberUtil.parse("+441752395464", defaultRegion: "US")
|
||||
let phoneNumber3 = try! phoneNumberUtil.parse("+12125556789", defaultRegion: "GB")
|
||||
let phoneNumber4 = try! phoneNumberUtil.parse("+441752395464", defaultRegion: "GB")
|
||||
// Invalid numbers.
|
||||
let phoneNumber5 = try! phoneNumberUtil.parse("+44175239546", defaultRegion: "US")
|
||||
let phoneNumber6 = try! phoneNumberUtil.parse("44", defaultRegion: "US")
|
||||
let phoneNumber7 = try! phoneNumberUtil.parse("+13334445555", defaultRegion: "US")
|
||||
let phoneNumber8 = try! phoneNumberUtil.parse("+44175239546", defaultRegion: "GB")
|
||||
let phoneNumber9 = try! phoneNumberUtil.parse("44", defaultRegion: "GB")
|
||||
let phoneNumber10 = try! phoneNumberUtil.parse("+13334445555", defaultRegion: "GB")
|
||||
|
||||
XCTAssertEqual(true, phoneNumberUtil.isValidNumber(phoneNumber1))
|
||||
XCTAssertEqual(true, phoneNumberUtil.isValidNumber(phoneNumber2))
|
||||
XCTAssertEqual(true, phoneNumberUtil.isValidNumber(phoneNumber3))
|
||||
XCTAssertEqual(true, phoneNumberUtil.isValidNumber(phoneNumber4))
|
||||
XCTAssertEqual(false, phoneNumberUtil.isValidNumber(phoneNumber5))
|
||||
XCTAssertEqual(false, phoneNumberUtil.isValidNumber(phoneNumber6))
|
||||
XCTAssertEqual(false, phoneNumberUtil.isValidNumber(phoneNumber7))
|
||||
XCTAssertEqual(false, phoneNumberUtil.isValidNumber(phoneNumber8))
|
||||
XCTAssertEqual(false, phoneNumberUtil.isValidNumber(phoneNumber9))
|
||||
XCTAssertEqual(false, phoneNumberUtil.isValidNumber(phoneNumber10))
|
||||
}
|
||||
|
||||
func test_countryCodeByCarrier() {
|
||||
// This test might fail depending on how the test device/simulator is configured.
|
||||
XCTAssertEqual("ZZ", phoneNumberUtil.countryCodeByCarrier())
|
||||
}
|
||||
|
||||
func test_getRegionCodeForCountryCode() {
|
||||
XCTAssertEqual("US", phoneNumberUtil.getRegionCodeForCountryCode(NSNumber(value: 1)))
|
||||
XCTAssertEqual("GB", phoneNumberUtil.getRegionCodeForCountryCode(NSNumber(value: 44)))
|
||||
XCTAssertEqual("UY", phoneNumberUtil.getRegionCodeForCountryCode(NSNumber(value: 598)))
|
||||
XCTAssertEqual("ZZ", phoneNumberUtil.getRegionCodeForCountryCode(NSNumber(value: 0)))
|
||||
XCTAssertEqual("ZZ", phoneNumberUtil.getRegionCodeForCountryCode(NSNumber(value: 99999)))
|
||||
XCTAssertEqual("ZZ", phoneNumberUtil.getRegionCodeForCountryCode(NSNumber(value: -1)))
|
||||
}
|
||||
|
||||
func test_getCountryCodeForRegion() {
|
||||
XCTAssertEqual(NSNumber(value: 1), phoneNumberUtil.getCountryCode(forRegion: "US"))
|
||||
XCTAssertEqual(NSNumber(value: 44), phoneNumberUtil.getCountryCode(forRegion: "GB"))
|
||||
XCTAssertEqual(NSNumber(value: 598), phoneNumberUtil.getCountryCode(forRegion: "UY"))
|
||||
// Invalid regions.
|
||||
XCTAssertEqual(NSNumber(value: 0), phoneNumberUtil.getCountryCode(forRegion: "UK"))
|
||||
XCTAssertEqual(NSNumber(value: 1), phoneNumberUtil.getCountryCode(forRegion: "US "))
|
||||
XCTAssertEqual(NSNumber(value: 0), phoneNumberUtil.getCountryCode(forRegion: " "))
|
||||
XCTAssertEqual(NSNumber(value: 0), phoneNumberUtil.getCountryCode(forRegion: ""))
|
||||
XCTAssertEqual(NSNumber(value: 0), phoneNumberUtil.getCountryCode(forRegion: "+1"))
|
||||
XCTAssertEqual(NSNumber(value: 0), phoneNumberUtil.getCountryCode(forRegion: "ZZ"))
|
||||
XCTAssertEqual(NSNumber(value: 0), phoneNumberUtil.getCountryCode(forRegion: "+"))
|
||||
XCTAssertEqual(NSNumber(value: 0), phoneNumberUtil.getCountryCode(forRegion: "ZQ"))
|
||||
}
|
||||
}
|
||||
@ -275,15 +275,13 @@ extension FindByPhoneNumberViewController: CountryCodeViewControllerDelegate {
|
||||
if let localE164 = PhoneNumber(fromE164: localNumber), let localCountryCode = localE164.getCountryCode()?.intValue {
|
||||
callingCodeInt = localCountryCode
|
||||
} else {
|
||||
callingCodeInt = PhoneNumberUtil.sharedThreadLocal().nbPhoneNumberUtil.getCountryCode(
|
||||
forRegion: PhoneNumber.defaultCountryCode()
|
||||
)?.intValue
|
||||
callingCodeInt = phoneNumberUtil.getCountryCode(forRegion: PhoneNumber.defaultCountryCode()).intValue
|
||||
}
|
||||
|
||||
var callingCode: String?
|
||||
if let callingCodeInt = callingCodeInt {
|
||||
callingCode = COUNTRY_CODE_PREFIX + "\(callingCodeInt)"
|
||||
countryCode = PhoneNumberUtil.sharedThreadLocal().probableCountryCode(forCallingCode: callingCode!)
|
||||
countryCode = phoneNumberUtil.probableCountryCode(forCallingCode: callingCode!)
|
||||
}
|
||||
|
||||
updateCountry(callingCode: callingCode, countryCode: countryCode)
|
||||
|
||||
@ -8,6 +8,7 @@
|
||||
#import <SignalMessaging/Environment.h>
|
||||
#import <SignalServiceKit/PhoneNumber.h>
|
||||
#import <SignalServiceKit/PhoneNumberUtil.h>
|
||||
#import <SignalServiceKit/SignalServiceKit-Swift.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@ -183,7 +184,7 @@ NSString *const TappedStatusBarNotification = @"TappedStatusBarNotification";
|
||||
OWSAssertDebug(countryCode.length > 0);
|
||||
OWSAssertDebug(callingCode.length > 0);
|
||||
|
||||
NSString *examplePhoneNumber = [PhoneNumberUtil examplePhoneNumberForCountryCode:countryCode];
|
||||
NSString *examplePhoneNumber = [self.phoneNumberUtil examplePhoneNumberForCountryCode:countryCode];
|
||||
OWSAssertDebug(!examplePhoneNumber || [examplePhoneNumber hasPrefix:callingCode]);
|
||||
if (examplePhoneNumber && [examplePhoneNumber hasPrefix:callingCode]) {
|
||||
NSString *formattedPhoneNumber =
|
||||
|
||||
Loading…
Reference in New Issue
Block a user