Skip to content

Commit 8c35e9b

Browse files
committed
Add ability to receive an SMS
1 parent 8be0931 commit 8c35e9b

4 files changed

Lines changed: 127 additions & 17 deletions

File tree

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

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,43 @@ import android.content.Context
55
import android.content.Intent
66
import android.content.BroadcastReceiver
77
import android.util.Log
8+
import java.time.ZoneOffset
9+
import java.time.ZonedDateTime
810

911

1012
internal class DeliveredReceiver : BroadcastReceiver() {
1113
override fun onReceive(context: Context, intent: Intent) {
1214
when (resultCode) {
13-
Activity.RESULT_OK -> Log.i(TAG, "delivered message with intent [${intent.extras?.getString(Constants.KEY_MESSAGE_ID)}]")
14-
Activity.RESULT_CANCELED -> Log.e(TAG, "message not delivered [${intent.getStringExtra(Constants.KEY_MESSAGE_ID)}}]")
15+
Activity.RESULT_OK -> handleMessageDelivered(intent.getStringExtra(Constants.KEY_MESSAGE_ID))
16+
else -> handleMessageFailed(intent.getStringExtra(Constants.KEY_MESSAGE_ID))
1517
}
1618
}
1719

20+
private fun handleMessageDelivered(messageId: String?) {
21+
val timestamp = ZonedDateTime.now(ZoneOffset.UTC)
22+
Thread {
23+
Log.i(TAG, "delivered message with ID [${messageId}]")
24+
if (messageId == null) {
25+
Log.e(TAG, "cannot handle event because the message ID is null")
26+
return@Thread
27+
}
28+
HttpSmsApiService().sendDeliveredEvent(messageId, timestamp)
29+
}.start()
30+
}
31+
32+
private fun handleMessageFailed(messageId: String?) {
33+
val timestamp = ZonedDateTime.now(ZoneOffset.UTC)
34+
Thread {
35+
Log.i(TAG, "message with ID [${messageId}] not delivered")
36+
if (messageId == null) {
37+
Log.e(TAG, "cannot handle event because the message ID is null")
38+
return@Thread
39+
}
40+
HttpSmsApiService().sendFailedEvent(messageId,timestamp, "NOT_DELIVERED")
41+
}.start()
42+
}
43+
1844
companion object {
1945
private val TAG = DeliveredReceiver::class.simpleName
2046
}
21-
}
47+
}

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

Lines changed: 51 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,21 @@
11
package com.httpsms
22

33
import android.util.Log
4+
import okhttp3.MediaType.Companion.toMediaType
45
import okhttp3.OkHttpClient
5-
import okhttp3.Request;
6+
import okhttp3.Request
7+
import okhttp3.RequestBody.Companion.toRequestBody
68
import java.net.URI
9+
import java.text.SimpleDateFormat
10+
import java.time.LocalDateTime
11+
import java.time.ZonedDateTime
12+
import java.time.format.DateTimeFormatter
13+
import java.util.*
714

815

916
class HttpSmsApiService {
1017
private val baseURL = URI("https://httpsms.free.beeceptor.com")
18+
private val jsonMediaType = "application/json; charset=utf-8".toMediaType()
1119

1220
fun getOutstandingMessages(): List<Message> {
1321
val client = OkHttpClient()
@@ -18,7 +26,7 @@ class HttpSmsApiService {
1826

1927
val response = client.newCall(request).execute()
2028
if (response.isSuccessful) {
21-
val payload = MessagesOutstanding.fromJson(response.body!!.string())?.data
29+
val payload = ResponseMessagesOutstanding.fromJson(response.body!!.string())?.data
2230
if (payload == null) {
2331
Log.e(TAG, "cannot decode payload [${response.body}]")
2432
return listOf();
@@ -30,7 +38,47 @@ class HttpSmsApiService {
3038
return listOf()
3139
}
3240

41+
fun sendDeliveredEvent(messageId: String, timestamp: ZonedDateTime) {
42+
sendEvent(messageId, "DELIVERED", timestamp)
43+
}
44+
45+
fun sendSentEvent(messageId: String, timestamp: ZonedDateTime) {
46+
sendEvent(messageId, "SENT", timestamp)
47+
}
48+
49+
fun sendFailedEvent(messageId: String, timestamp: ZonedDateTime, reason: String) {
50+
sendEvent(messageId, "FAILED", timestamp, reason)
51+
}
52+
53+
54+
private fun sendEvent(messageId: String, event: String, timestamp: ZonedDateTime, reason: String? = null) {
55+
val client = OkHttpClient()
56+
57+
val formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'000000'ZZZZZ");
58+
val timestampString = formatter.format(timestamp).replace("+", "Z")
59+
60+
val body = """
61+
{
62+
"event_name": "$event",
63+
"reason": "$reason"
64+
"timestamp": "$timestampString"
65+
}
66+
""".trimIndent().toRequestBody(jsonMediaType)
67+
68+
val request: Request = Request.Builder()
69+
.url(baseURL.resolve("/v1/messages/${messageId}/events").toURL())
70+
.post(body)
71+
.build()
72+
73+
val response = client.newCall(request).execute()
74+
if (!response.isSuccessful) {
75+
Log.e(TAG, "error response [${response.body?.string()}] with code [${response.code}] while sending [${event}] event [${body}] for message with ID [${messageId}]")
76+
return
77+
}
78+
Log.i(TAG, "[$event] event sent successfully for message with ID [$messageId]" )
79+
}
80+
3381
companion object {
3482
private val TAG = HttpSmsApiService::class.simpleName
3583
}
36-
}
84+
}

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

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,23 @@ import com.beust.klaxon.*
88

99
private val klaxon = Klaxon()
1010

11-
data class MessagesOutstanding (
11+
data class ResponseMessagesOutstanding (
1212
val data: List<Message>,
1313
val message: String,
1414
val status: String
1515
) {
16-
public fun toJson() = klaxon.toJsonString(this)
1716
companion object {
18-
public fun fromJson(json: String) = klaxon.parse<MessagesOutstanding>(json)
17+
public fun fromJson(json: String) = klaxon.parse<ResponseMessagesOutstanding>(json)
18+
}
19+
}
20+
21+
data class ResponseMessage (
22+
val data: Message,
23+
val message: String,
24+
val status: String
25+
) {
26+
companion object {
27+
public fun fromJson(json: String) = klaxon.parse<ResponseMessage>(json)
1928
}
2029
}
2130

@@ -56,4 +65,4 @@ data class Message (
5665

5766
@Json(name = "updated_at")
5867
val updatedAt: String
59-
)
68+
)

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

Lines changed: 34 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,10 @@ import android.app.Activity
44
import android.content.BroadcastReceiver
55
import android.content.Context
66
import android.content.Intent
7-
import android.util.Log
87
import android.telephony.SmsManager
8+
import android.util.Log
9+
import java.time.ZoneOffset
10+
import java.time.ZonedDateTime
911

1012
internal class SentReceiver : BroadcastReceiver() {
1113
companion object {
@@ -14,11 +16,36 @@ internal class SentReceiver : BroadcastReceiver() {
1416

1517
override fun onReceive(context: Context, intent: Intent) {
1618
when (resultCode) {
17-
Activity.RESULT_OK -> Log.i(TAG, "sending successful with intent [${intent.getStringExtra(Constants.KEY_MESSAGE_ID)}]")
18-
SmsManager.RESULT_ERROR_GENERIC_FAILURE -> Log.i(TAG, "sending failed with RESULT_ERROR_GENERIC_FAILURE intent [${intent.getStringExtra(Constants.KEY_MESSAGE_ID)}]")
19-
SmsManager.RESULT_ERROR_NO_SERVICE -> Log.i(TAG, "sending failed with RESULT_ERROR_NO_SERVICE intent [${intent.getStringExtra(Constants.KEY_MESSAGE_ID)}]")
20-
SmsManager.RESULT_ERROR_NULL_PDU -> Log.i(TAG, "sending failed with RESULT_ERROR_NULL_PDU intent [${intent.getStringExtra(Constants.KEY_MESSAGE_ID)}]")
21-
SmsManager.RESULT_ERROR_RADIO_OFF -> Log.i(TAG, "sending failed with RESULT_ERROR_RADIO_OFF intent [${intent.getStringExtra(Constants.KEY_MESSAGE_ID)}]")
19+
Activity.RESULT_OK -> handleMessageSent(intent.getStringExtra(Constants.KEY_MESSAGE_ID))
20+
SmsManager.RESULT_ERROR_GENERIC_FAILURE -> handleMessageFailed(intent.getStringExtra(Constants.KEY_MESSAGE_ID), "GENERIC_FAILURE")
21+
SmsManager.RESULT_ERROR_NO_SERVICE -> handleMessageFailed(intent.getStringExtra(Constants.KEY_MESSAGE_ID), "NO_SERVICE")
22+
SmsManager.RESULT_ERROR_NULL_PDU -> handleMessageFailed(intent.getStringExtra(Constants.KEY_MESSAGE_ID), "NULL_PDU")
23+
SmsManager.RESULT_ERROR_RADIO_OFF -> handleMessageFailed(intent.getStringExtra(Constants.KEY_MESSAGE_ID), "RADIO_OFF")
24+
else -> handleMessageFailed(intent.getStringExtra(Constants.KEY_MESSAGE_ID), "UNKNOWN")
2225
}
2326
}
24-
}
27+
28+
private fun handleMessageSent(messageId: String?) {
29+
val timestamp = ZonedDateTime.now(ZoneOffset.UTC)
30+
Thread {
31+
Log.i(TAG, "sent message with ID [${messageId}]")
32+
if (messageId == null) {
33+
Log.e(TAG, "cannot handle event because the message ID is null")
34+
return@Thread
35+
}
36+
HttpSmsApiService().sendSentEvent(messageId,timestamp)
37+
}.start()
38+
}
39+
40+
private fun handleMessageFailed(messageId: String?, reason: String) {
41+
val timestamp = ZonedDateTime.now(ZoneOffset.UTC)
42+
Thread {
43+
Log.i(TAG, "message with ID [${messageId}] not sent with reason [$reason]")
44+
if (messageId == null) {
45+
Log.e(TAG, "cannot handle event because the message ID is null")
46+
return@Thread
47+
}
48+
HttpSmsApiService().sendFailedEvent(messageId, timestamp, reason)
49+
}.start()
50+
}
51+
}

0 commit comments

Comments
 (0)