Skip to content

Commit e8a7501

Browse files
committed
fix(android): harden SMS delivery
Handle missing SIM metadata and Android's EmergencyNumber null pointer failure. Fall back to the default SMS manager and reject blank contacts before delivery. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 817c0f13-cbbd-4fec-8ec4-2553e5f2ca2e
1 parent 64cc1b7 commit e8a7501

5 files changed

Lines changed: 66 additions & 22 deletions

File tree

android/app/src/main/java/com/httpsms/FirebaseMessagingService.kt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,13 @@ class MyFirebaseMessagingService : FirebaseMessagingService() {
145145
}
146146

147147
val message = getMessage(applicationContext, messageID) ?: return Result.failure()
148+
149+
if (message.contact.isBlank()) {
150+
Timber.w("message contact is blank, stopping processing")
151+
handleFailed(applicationContext, messageID, "The contact phone number is empty.")
152+
return Result.failure()
153+
}
154+
148155
if (!Settings.getActiveStatus(applicationContext, message.sim)) {
149156
Timber.w("[${message.sim}] SIM is not active, stopping processing")
150157
handleFailed(applicationContext, messageID, "Outgoing messages have been disabled on the mobile app")

android/app/src/main/java/com/httpsms/SmsManagerService.kt

Lines changed: 41 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ class SmsManagerService {
3636
} else {
3737
context.getSystemService(SubscriptionManager::class.java)
3838
}
39-
return localSubscriptionManager.activeSubscriptionInfoList!!.size > 1
39+
return (localSubscriptionManager.activeSubscriptionInfoList?.size ?: 0) > 1
4040
}
4141
}
4242

@@ -45,11 +45,38 @@ class SmsManagerService {
4545
}
4646

4747
fun sendMultipartMessage(context: Context, contact: String, parts: ArrayList<String>, sim: String, sendIntents: ArrayList<PendingIntent>, deliveryIntents: ArrayList<PendingIntent>) {
48-
getSmsManager(context, sim).sendMultipartTextMessage(contact, null, parts, sendIntents, deliveryIntents)
48+
try {
49+
getSmsManager(context, sim).sendMultipartTextMessage(contact, null, parts, sendIntents, deliveryIntents)
50+
} catch (e: NullPointerException) {
51+
if (e.message?.contains("EmergencyNumber.getNumber()") == true) {
52+
Timber.w(e, "Caught EmergencyNumber NPE, falling back to default SmsManager")
53+
getDefaultSmsManager(context).sendMultipartTextMessage(contact, null, parts, sendIntents, deliveryIntents)
54+
} else {
55+
throw e
56+
}
57+
}
4958
}
5059

5160
fun sendTextMessage(context: Context, contact: String, content: String, sim: String, sentIntent:PendingIntent, deliveryIntent: PendingIntent) {
52-
getSmsManager(context, sim).sendTextMessage(contact, null, content, sentIntent, deliveryIntent)
61+
try {
62+
getSmsManager(context, sim).sendTextMessage(contact, null, content, sentIntent, deliveryIntent)
63+
} catch (e: NullPointerException) {
64+
if (e.message?.contains("EmergencyNumber.getNumber()") == true) {
65+
Timber.w(e, "Caught EmergencyNumber NPE, falling back to default SmsManager")
66+
getDefaultSmsManager(context).sendTextMessage(contact, null, content, sentIntent, deliveryIntent)
67+
} else {
68+
throw e
69+
}
70+
}
71+
}
72+
73+
@Suppress("DEPRECATION")
74+
private fun getDefaultSmsManager(context: Context): SmsManager {
75+
return if (Build.VERSION.SDK_INT >= 31) {
76+
context.getSystemService(SmsManager::class.java)
77+
} else {
78+
SmsManager.getDefault()
79+
}
5380
}
5481

5582
@Suppress("DEPRECATION")
@@ -61,15 +88,21 @@ class SmsManagerService {
6188
context.getSystemService(SubscriptionManager::class.java)
6289
}
6390

64-
Timber.d("active subscription info size: [${localSubscriptionManager.activeSubscriptionInfoList!!.size}]")
65-
val subscriptionId = if (sim == Constants.SIM1 && localSubscriptionManager.activeSubscriptionInfoList!!.isNotEmpty()) {
66-
localSubscriptionManager.activeSubscriptionInfoList!![0].subscriptionId
67-
} else if (sim == Constants.SIM2 && localSubscriptionManager.activeSubscriptionInfoList!!.size > 1) {
68-
localSubscriptionManager.activeSubscriptionInfoList!![1].subscriptionId
91+
val infoList = localSubscriptionManager.activeSubscriptionInfoList
92+
Timber.d("active subscription info size: [${infoList?.size ?: 0}]")
93+
94+
val subscriptionId = if (sim == Constants.SIM1 && !infoList.isNullOrEmpty()) {
95+
infoList[0].subscriptionId
96+
} else if (sim == Constants.SIM2 && (infoList?.size ?: 0) > 1) {
97+
infoList!![1].subscriptionId
6998
} else{
7099
SubscriptionManager.getDefaultSmsSubscriptionId()
71100
}
72101

102+
if (subscriptionId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
103+
return getDefaultSmsManager(context)
104+
}
105+
73106
return if (Build.VERSION.SDK_INT < 31) {
74107
SmsManager.getSmsManagerForSubscriptionId(subscriptionId)
75108
} else {
Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
#This file is generated by updateDaemonJvm
2-
toolchainUrl.FREE_BSD.AARCH64=https\://api.foojay.io/disco/v3.0/ids/ec7520a1e057cd116f9544c42142a16b/redirect
3-
toolchainUrl.FREE_BSD.X86_64=https\://api.foojay.io/disco/v3.0/ids/4c4f879899012ff0a8b2e2117df03b0e/redirect
4-
toolchainUrl.LINUX.AARCH64=https\://api.foojay.io/disco/v3.0/ids/ec7520a1e057cd116f9544c42142a16b/redirect
5-
toolchainUrl.LINUX.X86_64=https\://api.foojay.io/disco/v3.0/ids/4c4f879899012ff0a8b2e2117df03b0e/redirect
6-
toolchainUrl.MAC_OS.AARCH64=https\://api.foojay.io/disco/v3.0/ids/73bcfb608d1fde9fb62e462f834a3299/redirect
7-
toolchainUrl.MAC_OS.X86_64=https\://api.foojay.io/disco/v3.0/ids/846ee0d876d26a26f37aa1ce8de73224/redirect
8-
toolchainUrl.UNIX.AARCH64=https\://api.foojay.io/disco/v3.0/ids/ec7520a1e057cd116f9544c42142a16b/redirect
9-
toolchainUrl.UNIX.X86_64=https\://api.foojay.io/disco/v3.0/ids/4c4f879899012ff0a8b2e2117df03b0e/redirect
10-
toolchainUrl.WINDOWS.AARCH64=https\://api.foojay.io/disco/v3.0/ids/9482ddec596298c84656d31d16652665/redirect
11-
toolchainUrl.WINDOWS.X86_64=https\://api.foojay.io/disco/v3.0/ids/39701d92e1756bb2f141eb67cd4c660e/redirect
12-
toolchainVersion=21
2+
toolchainUrl.FREE_BSD.AARCH64=https\://api.foojay.io/disco/v3.0/ids/5c55020ad1e1758e65cf84d78a6991d9/redirect
3+
toolchainUrl.FREE_BSD.X86_64=https\://api.foojay.io/disco/v3.0/ids/057be4d72513d094c747045acda26562/redirect
4+
toolchainUrl.LINUX.AARCH64=https\://api.foojay.io/disco/v3.0/ids/5c55020ad1e1758e65cf84d78a6991d9/redirect
5+
toolchainUrl.LINUX.X86_64=https\://api.foojay.io/disco/v3.0/ids/057be4d72513d094c747045acda26562/redirect
6+
toolchainUrl.MAC_OS.AARCH64=https\://api.foojay.io/disco/v3.0/ids/690f22c7d5fabdba81db34b2bcbdfd40/redirect
7+
toolchainUrl.MAC_OS.X86_64=https\://api.foojay.io/disco/v3.0/ids/19d7c2d18fdc600f184666745a0567c4/redirect
8+
toolchainUrl.UNIX.AARCH64=https\://api.foojay.io/disco/v3.0/ids/5c55020ad1e1758e65cf84d78a6991d9/redirect
9+
toolchainUrl.UNIX.X86_64=https\://api.foojay.io/disco/v3.0/ids/057be4d72513d094c747045acda26562/redirect
10+
toolchainUrl.WINDOWS.AARCH64=https\://api.foojay.io/disco/v3.0/ids/38d4fc46de6f02af9912aa3f66104600/redirect
11+
toolchainUrl.WINDOWS.X86_64=https\://api.foojay.io/disco/v3.0/ids/34480c4bfcee5d3bd65f2a0592c5217b/redirect
12+
toolchainVendor=JETBRAINS
13+
toolchainVersion=25
Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
#Thu Jun 23 15:32:32 EEST 2022
1+
#Sun Aug 23 12:56:53 EEST 2026
22
distributionBase=GRADLE_USER_HOME
3-
distributionUrl=https\://services.gradle.org/distributions/gradle-9.4.1-bin.zip
43
distributionPath=wrapper/dists
5-
zipStorePath=wrapper/dists
4+
distributionUrl=https\://services.gradle.org/distributions/gradle-9.7.0-bin.zip
65
zipStoreBase=GRADLE_USER_HOME
6+
zipStorePath=wrapper/dists

android/settings.gradle.kts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@ pluginManagement {
55
mavenCentral()
66
}
77
}
8+
plugins {
9+
id("org.gradle.toolchains.foojay-resolver-convention") version "1.0.0"
10+
}
811
dependencyResolutionManagement {
912
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
1013
repositories {

0 commit comments

Comments
 (0)