Skip to content

Commit 02642ca

Browse files
thomasbuildsthestinger
authored andcommitted
Fix crash when declining a call with a quick response
Commit 9aec6f6 replaced the argument-less notification refresh with BugleNotifications.updateWithInlineReply(conversationId, message), which is also reached from the recipients-only RESPOND_VIA_MESSAGE path where conversationId is null. Telecom invokes this exported service whenever the user rejects an incoming call with a quick-response text, and the null conversationId crashes on the non-null channelId parameter of NotificationChannelUtil.getActiveNotification. Since the service sets intent redelivery, the crash also redelivers the intent and re-sends the reply, causing duplicate texts alongside the crash loop. Move the call into the branch where the conversation is known. The notification inline-reply path always supplies a conversation id, so its behavior is unchanged, and the recipients-only path has no active conversation notification to update in the first place.
1 parent 5dc2110 commit 02642ca

2 files changed

Lines changed: 102 additions & 2 deletions

File tree

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
package com.android.messaging.datamodel
2+
3+
import android.content.Intent
4+
import android.net.Uri
5+
import android.telephony.TelephonyManager
6+
import com.android.messaging.FactoryTestAccess
7+
import com.android.messaging.datamodel.action.InsertNewMessageAction
8+
import com.android.messaging.datamodel.data.MessageData
9+
import com.android.messaging.datamodel.data.ParticipantData
10+
import com.android.messaging.testutil.installTestFactory
11+
import com.android.messaging.ui.UIIntents
12+
import io.mockk.every
13+
import io.mockk.just
14+
import io.mockk.mockkStatic
15+
import io.mockk.runs
16+
import io.mockk.slot
17+
import io.mockk.unmockkAll
18+
import io.mockk.verify
19+
import org.junit.After
20+
import org.junit.Assert.assertEquals
21+
import org.junit.Before
22+
import org.junit.Test
23+
import org.junit.runner.RunWith
24+
import org.robolectric.RobolectricTestRunner
25+
import org.robolectric.RuntimeEnvironment
26+
27+
@RunWith(RobolectricTestRunner::class)
28+
class NoConfirmationSmsSendServiceRespondViaMessageTest {
29+
30+
@Before
31+
fun setUp() {
32+
installTestFactory(
33+
context = RuntimeEnvironment.getApplication().applicationContext,
34+
)
35+
mockkStatic(InsertNewMessageAction::class)
36+
every {
37+
InsertNewMessageAction.insertNewMessage(any(), any(), any(), any())
38+
} just runs
39+
every { InsertNewMessageAction.insertNewMessage(any()) } just runs
40+
}
41+
42+
@After
43+
fun tearDown() {
44+
unmockkAll()
45+
FactoryTestAccess.reset()
46+
}
47+
48+
@Test
49+
fun respondViaMessageWithoutConversationSendsReplyWithoutNotificationUpdate() {
50+
val intent = respondViaMessageIntent()
51+
52+
TestNoConfirmationSmsSendService().handle(intent)
53+
54+
verify(exactly = 1) {
55+
InsertNewMessageAction.insertNewMessage(
56+
ParticipantData.DEFAULT_SELF_SUB_ID,
57+
RECIPIENT,
58+
REPLY_TEXT,
59+
null,
60+
)
61+
}
62+
}
63+
64+
@Test
65+
fun respondViaMessageWithConversationStillUpdatesNotificationInlineReply() {
66+
mockkStatic(BugleNotifications::class)
67+
every { BugleNotifications.updateWithInlineReply(any(), any()) } just runs
68+
val intent = respondViaMessageIntent().putExtra(
69+
UIIntents.UI_INTENT_EXTRA_CONVERSATION_ID,
70+
CONVERSATION_ID,
71+
)
72+
73+
TestNoConfirmationSmsSendService().handle(intent)
74+
75+
val message = slot<MessageData>()
76+
verify(exactly = 1) { InsertNewMessageAction.insertNewMessage(capture(message)) }
77+
assertEquals(CONVERSATION_ID, message.captured.conversationId)
78+
verify(exactly = 1) {
79+
BugleNotifications.updateWithInlineReply(CONVERSATION_ID, REPLY_TEXT)
80+
}
81+
}
82+
83+
private fun respondViaMessageIntent(): Intent {
84+
return Intent(
85+
TelephonyManager.ACTION_RESPOND_VIA_MESSAGE,
86+
Uri.parse("smsto:$RECIPIENT"),
87+
).putExtra(Intent.EXTRA_TEXT, REPLY_TEXT)
88+
}
89+
90+
private class TestNoConfirmationSmsSendService : NoConfirmationSmsSendService() {
91+
fun handle(intent: Intent) {
92+
onHandleIntent(intent)
93+
}
94+
}
95+
96+
private companion object {
97+
private const val RECIPIENT = "+15551234567"
98+
private const val REPLY_TEXT = "Can't talk right now, what's up?"
99+
private const val CONVERSATION_ID = "194"
100+
}
101+
}

src/com/android/messaging/datamodel/NoConfirmationSmsSendService.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@
2525
import android.text.TextUtils;
2626

2727
import com.android.messaging.datamodel.action.InsertNewMessageAction;
28-
import com.android.messaging.datamodel.action.UpdateMessageNotificationAction;
2928
import com.android.messaging.datamodel.data.MessageData;
3029
import com.android.messaging.datamodel.data.ParticipantData;
3130
import com.android.messaging.ui.UIIntents;
@@ -126,8 +125,8 @@ protected void onHandleIntent(final Intent intent) {
126125
message);
127126
}
128127
InsertNewMessageAction.insertNewMessage(messageData);
128+
BugleNotifications.updateWithInlineReply(conversationId, message);
129129
}
130-
BugleNotifications.updateWithInlineReply(conversationId, message);
131130
}
132131
}
133132

0 commit comments

Comments
 (0)