forked from FossifyOrg/Phone
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(draft): fix invalid numbers before placing the call
This commit is a non-working draft, some cases fail and the setting is not working.
- Loading branch information
Showing
11 changed files
with
273 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
115 changes: 115 additions & 0 deletions
115
app/src/main/kotlin/org/fossify/phone/helpers/CallNumberHelper.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
package org.fossify.phone.helpers | ||
|
||
import android.net.Uri | ||
import android.util.Log | ||
import android.content.Context | ||
import android.telephony.TelephonyManager | ||
import com.google.i18n.phonenumbers.PhoneNumberUtil | ||
import com.google.i18n.phonenumbers.Phonenumber | ||
import com.google.i18n.phonenumbers.NumberParseException | ||
|
||
// country codes | ||
private const val BRAZIL_COUNTRY_CODE = 55 | ||
private const val BRAZIL_COUNTRY_CODE_STR = "BR" | ||
|
||
// brazil number constants | ||
private const val BR_LOCAL_AREA_LEN = 8 | ||
private const val BR_NEW_NUM_LEN = 9 | ||
private const val BR_LAND_PREFIX_MAX = 5 | ||
private const val BR_CEL_PREFIX_CHAR = '9' | ||
|
||
/** | ||
* Fix invalid numbers based on their country code | ||
*/ | ||
@Suppress("TooGenericExceptionCaught") | ||
fun fixInvalidNumbers(tel: Uri?, context: Context): Uri? { | ||
if (tel != null) { | ||
try { | ||
val countryCode = getCountryCode(tel, context) | ||
return when (countryCode) { | ||
BRAZIL_COUNTRY_CODE -> fixInvalidNumbersBrazil(tel) | ||
else -> tel | ||
} | ||
} catch (e: Exception) { | ||
Log.e("CallNumberHelper", "Error fixing invalid number: $e") | ||
} | ||
} | ||
return tel | ||
} | ||
|
||
/** | ||
* Get the country code of the dialed phone number (or infer from SIM) | ||
*/ | ||
private fun getCountryCode(tel: Uri, context: Context): Int? { | ||
// Decode the tel URI | ||
val decodedTel = tel.getSchemeSpecificPart() | ||
val phoneNumberUtil = PhoneNumberUtil.getInstance() | ||
var countryCode: Int? | ||
|
||
// Try to get the country code | ||
try { | ||
val phoneNumber: Phonenumber.PhoneNumber = phoneNumberUtil.parse(decodedTel, null) | ||
countryCode = phoneNumber.getCountryCode() | ||
} catch (e: NumberParseException) { | ||
// No country code in the number, so it must be a local call, | ||
// so we can use the SIM country code | ||
val tm = context.getSystemService(TelephonyManager::class.java) | ||
val countryIso = tm.getSimCountryIso().uppercase() | ||
Log.d("CallNumberHelper", "No country code, SIM country ISO: $countryIso") | ||
countryCode = phoneNumberUtil.getCountryCodeForRegion(countryIso) | ||
} | ||
Log.d("CallNumberHelper", "Country code: $countryCode") | ||
return countryCode | ||
} | ||
|
||
|
||
/** | ||
* Fix invalid numbers for Brazil | ||
* | ||
* https://www.gov.br/anatel/pt-br/regulado/numeracao/tabela-servico-movel-celular | ||
* https://www.gov.br/anatel/pt-br/regulado/numeracao/tabela-servico-telefonico-fixo-comutado | ||
* https://www.gov.br/anatel/pt-br/regulado/numeracao/tabela-servico-telefonico-fixo-comutado-codigos-nao-geograficos-cng | ||
* https://www.gov.br/anatel/pt-br/regulado/numeracao/codigos-nacionais/servicos-de-utilidade-publica-e-de-emergencia | ||
* https://www.gov.br/anatel/pt-br/regulado/numeracao/tabela-servico-movel-especializado | ||
*/ | ||
@Suppress("NestedBlockDepth") | ||
private fun fixInvalidNumbersBrazil(tel: Uri): Uri { | ||
// Decode a PhoneNumber from the URI | ||
val decodedTel = tel.getSchemeSpecificPart() | ||
val phoneNumberUtil = PhoneNumberUtil.getInstance() | ||
val phoneNumber: Phonenumber.PhoneNumber = phoneNumberUtil.parse(decodedTel, BRAZIL_COUNTRY_CODE_STR) | ||
|
||
// Get the national number, potentially with area and carrier code | ||
if (phoneNumber.hasNationalNumber()) { | ||
val nationalNum = phoneNumber.getNationalNumber() | ||
val nationalNumStr = nationalNum.toString() | ||
Log.d("CallNumberHelper", "Brazil national number: $nationalNumStr") | ||
|
||
// Look at the local area number (last eight digits) | ||
if (nationalNumStr.length >= BR_LOCAL_AREA_LEN) { | ||
val localAreaNumStr = nationalNumStr.substring(nationalNumStr.length - BR_LOCAL_AREA_LEN) | ||
|
||
// Is it a cellphone (starts with >5)? | ||
if (localAreaNumStr.get(0).digitToInt() > BR_LAND_PREFIX_MAX) { | ||
|
||
// Is it missing the 9 prefix? | ||
if (nationalNumStr.length < BR_NEW_NUM_LEN || | ||
nationalNumStr.get(nationalNumStr.length - BR_NEW_NUM_LEN) != BR_CEL_PREFIX_CHAR) { | ||
|
||
// Insert the 9 before the last 8 numbers | ||
val fixedNationalNum = ( | ||
nationalNumStr.substring(0, nationalNumStr.length - BR_LOCAL_AREA_LEN) + | ||
BR_CEL_PREFIX_CHAR + | ||
localAreaNumStr | ||
).toLong() | ||
phoneNumber.setNationalNumber(fixedNationalNum) | ||
val fixedNumStr = phoneNumberUtil.format(phoneNumber, PhoneNumberUtil.PhoneNumberFormat.E164) | ||
|
||
Log.d("CallNumberHelper", "Brazil fixed number: $fixedNumStr") | ||
return Uri.parse("tel:$fixedNumStr") | ||
} | ||
} | ||
} | ||
} | ||
return tel; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
109 changes: 109 additions & 0 deletions
109
app/src/test/kotlin/org/fossify/phone/helpers/CallNumberHelperTest.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
import android.content.Context | ||
import android.net.Uri | ||
import android.telephony.TelephonyManager | ||
import org.junit.Assert.assertEquals | ||
import org.junit.Before | ||
import org.junit.Test | ||
import org.junit.runner.RunWith | ||
import org.fossify.phone.helpers.fixInvalidNumbers | ||
import org.robolectric.RobolectricTestRunner | ||
import org.robolectric.RuntimeEnvironment | ||
import org.robolectric.annotation.Config | ||
import org.robolectric.Shadows | ||
import org.robolectric.shadows.ShadowTelephonyManager | ||
|
||
@RunWith(RobolectricTestRunner::class) | ||
@Config(sdk = [34]) | ||
class CallNumberHelperTest { | ||
|
||
private lateinit var context: Context | ||
private lateinit var telephonyManager: TelephonyManager | ||
private lateinit var shadowTelephonyManager: ShadowTelephonyManager | ||
|
||
@Before | ||
fun setUp() { | ||
context = RuntimeEnvironment.getApplication() | ||
telephonyManager = context.getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager | ||
shadowTelephonyManager = Shadows.shadowOf(telephonyManager) | ||
shadowTelephonyManager.setSimCountryIso("BR") | ||
} | ||
|
||
// Country and Area code | ||
|
||
@Test | ||
fun testInvalidWithCountryAndAreaCode() { | ||
val inputNumber = Uri.parse("tel:+551190000000") | ||
val expectedNumber = Uri.parse("tel:+5511990000000") | ||
val outputNumber = fixInvalidNumbers(inputNumber, context ) | ||
assertEquals(expectedNumber, outputNumber) | ||
} | ||
|
||
@Test | ||
fun testValidWithCountryAndAreaCode() { | ||
val inputNumber = Uri.parse("tel:+5511990000000") | ||
val expectedNumber = Uri.parse("tel:+5511990000000") | ||
val outputNumber = fixInvalidNumbers(inputNumber, context) | ||
assertEquals(expectedNumber, outputNumber) | ||
} | ||
|
||
@Test | ||
fun testLandWithCountryAndAreaCode() { | ||
val inputNumber = Uri.parse("tel:+551130000000") | ||
val expectedNumber = Uri.parse("tel:+551130000000") | ||
val outputNumber = fixInvalidNumbers(inputNumber, context) | ||
assertEquals(expectedNumber, outputNumber) | ||
} | ||
|
||
// Carrier and Area code | ||
|
||
@Test | ||
fun testInvalidWithCarrierAndAreaCode() { | ||
val inputNumber = Uri.parse("tel:0211190000000") | ||
val expectedNumber = Uri.parse("tel:+5502111990000000") | ||
val outputNumber = fixInvalidNumbers(inputNumber, context) | ||
assertEquals(expectedNumber, outputNumber) | ||
} | ||
|
||
@Test | ||
fun testValidWithCarrierAndAreaCode() { | ||
val inputNumber = Uri.parse("tel:02111990000000") | ||
val expectedNumber = Uri.parse("tel:+5502111990000000") | ||
val outputNumber = fixInvalidNumbers(inputNumber, context) | ||
assertEquals(expectedNumber, outputNumber) | ||
} | ||
|
||
@Test | ||
fun testLandWithCarrierAndAreaCode() { | ||
val inputNumber = Uri.parse("tel:0211130000000") | ||
val expectedNumber = Uri.parse("tel:+550211130000000") | ||
val outputNumber = fixInvalidNumbers(inputNumber, context) | ||
assertEquals(expectedNumber, outputNumber) | ||
} | ||
|
||
// Local Area number | ||
|
||
@Test | ||
fun testInvalidLocalAreaNumber() { | ||
val inputNumber = Uri.parse("tel:90000000") | ||
val expectedNumber = Uri.parse("tel:990000000") | ||
val outputNumber = fixInvalidNumbers(inputNumber, context) | ||
assertEquals(expectedNumber, outputNumber) | ||
} | ||
|
||
@Test | ||
fun testValidLocalAreaNumber() { | ||
val inputNumber = Uri.parse("tel:990000000") | ||
val expectedNumber = Uri.parse("tel:9990000000") | ||
val outputNumber = fixInvalidNumbers(inputNumber, context) | ||
assertEquals(expectedNumber, outputNumber) | ||
} | ||
|
||
@Test | ||
fun testlLandLocalAreaNumber() { | ||
val inputNumber = Uri.parse("tel:30000000") | ||
val expectedNumber = Uri.parse("tel:30000000") | ||
val outputNumber = fixInvalidNumbers(inputNumber, context) | ||
assertEquals(expectedNumber, outputNumber) | ||
} | ||
|
||
} |