Skip to content

Commit 6c1b347

Browse files
committed
Add HttpSmsApiService
1 parent d376e17 commit 6c1b347

9 files changed

Lines changed: 316 additions & 33 deletions

File tree

android/app/build.gradle

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
plugins {
22
id 'com.android.application'
33
id 'org.jetbrains.kotlin.android'
4+
id 'com.google.gms.google-services'
45
}
56

67
android {
78
compileSdk 32
89

10+
buildToolsVersion "32.0.0"
11+
912
defaultConfig {
1013
applicationId "com.httpsms"
1114
minSdk 30
@@ -32,8 +35,15 @@ android {
3235
}
3336

3437
dependencies {
38+
implementation platform('com.google.firebase:firebase-bom:30.1.0')
39+
implementation 'com.google.firebase:firebase-analytics-ktx'
40+
implementation 'com.google.firebase:firebase-messaging-ktx'
41+
implementation 'com.squareup.okhttp3:okhttp:4.10.0'
42+
implementation 'androidx.work:work-runtime-ktx:2.7.1'
3543
implementation 'androidx.core:core-ktx:1.8.0'
3644
implementation "androidx.cardview:cardview:1.0.0"
45+
implementation 'com.beust:klaxon:5.5'
46+
implementation 'androidx.work:work-runtime-ktx:2.7.1'
3747
implementation 'androidx.appcompat:appcompat:1.4.2'
3848
implementation 'com.google.android.material:material:1.6.1'
3949
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'

android/app/google-services.json

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
{
2+
"project_info": {
3+
"project_number": "877524083399",
4+
"project_id": "httpsms-86c51",
5+
"storage_bucket": "httpsms-86c51.appspot.com"
6+
},
7+
"client": [
8+
{
9+
"client_info": {
10+
"mobilesdk_app_id": "1:877524083399:android:5ceb08a909fd24a96514e2",
11+
"android_client_info": {
12+
"package_name": "com.httpsms"
13+
}
14+
},
15+
"oauth_client": [
16+
{
17+
"client_id": "877524083399-londfmd80qqlb2gebpbhctavlmqtla3b.apps.googleusercontent.com",
18+
"client_type": 1,
19+
"android_info": {
20+
"package_name": "com.httpsms",
21+
"certificate_hash": "58df9f7489b8bb5e3cd57f01a03d5e0068d8c185"
22+
}
23+
},
24+
{
25+
"client_id": "877524083399-7pn57hd8k2js6tc93i428ko1m51mj50r.apps.googleusercontent.com",
26+
"client_type": 3
27+
}
28+
],
29+
"api_key": [
30+
{
31+
"current_key": "AIzaSyBKiokmk5qhE2Zc5F97KWzOvRe8FDDuxDg"
32+
}
33+
],
34+
"services": {
35+
"appinvite_service": {
36+
"other_platform_oauth_client": [
37+
{
38+
"client_id": "877524083399-7pn57hd8k2js6tc93i428ko1m51mj50r.apps.googleusercontent.com",
39+
"client_type": 3
40+
}
41+
]
42+
}
43+
}
44+
}
45+
],
46+
"configuration_version": "1"
47+
}
Lines changed: 48 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,48 @@
1-
<?xml version="1.0" encoding="utf-8"?>
2-
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
3-
xmlns:tools="http://schemas.android.com/tools"
4-
package="com.httpsms">
5-
6-
7-
<uses-permission android:name="android.permission.READ_PHONE_NUMBERS" />
8-
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
9-
<uses-permission android:name="android.permission.READ_SMS" />
10-
<uses-permission android:name="android.permission.SEND_SMS" />
11-
12-
<application
13-
android:allowBackup="true"
14-
android:dataExtractionRules="@xml/data_extraction_rules"
15-
android:fullBackupContent="@xml/backup_rules"
16-
android:icon="@mipmap/ic_launcher"
17-
android:label="@string/app_name"
18-
android:roundIcon="@mipmap/ic_launcher_round"
19-
android:supportsRtl="true"
20-
android:theme="@style/Theme.HttpSMS"
21-
tools:targetApi="31">
22-
<activity
23-
android:name=".MainActivity"
24-
android:exported="true">
25-
<intent-filter>
26-
<action android:name="android.intent.action.MAIN" />
27-
28-
<category android:name="android.intent.category.LAUNCHER" />
29-
</intent-filter>
30-
</activity>
31-
</application>
32-
33-
</manifest>
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
3+
xmlns:tools="http://schemas.android.com/tools"
4+
package="com.httpsms">
5+
6+
7+
<uses-permission android:name="android.permission.READ_PHONE_NUMBERS" />
8+
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
9+
<uses-permission android:name="android.permission.READ_SMS" />
10+
<uses-permission android:name="android.permission.SEND_SMS" />
11+
<uses-permission android:name="android.permission.RECEIVE_SMS" />
12+
<uses-permission android:name="android.permission.INTERNET" />
13+
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
14+
15+
16+
<application
17+
android:allowBackup="true"
18+
android:dataExtractionRules="@xml/data_extraction_rules"
19+
android:fullBackupContent="@xml/backup_rules"
20+
android:icon="@mipmap/ic_launcher"
21+
android:label="@string/app_name"
22+
android:roundIcon="@mipmap/ic_launcher_round"
23+
android:supportsRtl="true"
24+
android:theme="@style/Theme.HttpSMS"
25+
tools:targetApi="31">
26+
<activity
27+
android:name=".MainActivity"
28+
android:exported="true">
29+
<intent-filter>
30+
<action android:name="android.intent.action.MAIN" />
31+
32+
<category android:name="android.intent.category.LAUNCHER" />
33+
</intent-filter>
34+
</activity>
35+
36+
<service
37+
android:name=".MyFirebaseMessagingService"
38+
android:exported="false">
39+
<intent-filter>
40+
<action android:name="com.google.firebase.MESSAGING_EVENT" />
41+
</intent-filter>
42+
</service>
43+
44+
<meta-data
45+
android:name="com.google.firebase.messaging.default_notification_channel_id"
46+
android:value="com.httpsms.notification.default" />
47+
</application>
48+
</manifest>
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
package com.httpsms
2+
3+
import android.content.Context
4+
import android.util.Log
5+
import androidx.work.OneTimeWorkRequest
6+
import androidx.work.WorkManager
7+
import androidx.work.Worker
8+
import androidx.work.WorkerParameters
9+
import com.google.firebase.messaging.FirebaseMessagingService
10+
import com.google.firebase.messaging.RemoteMessage
11+
12+
class MyFirebaseMessagingService : FirebaseMessagingService() {
13+
14+
// [START receive_message]
15+
override fun onMessageReceived(remoteMessage: RemoteMessage) {
16+
// TODO(developer): Handle FCM messages here.
17+
// Not getting messages here? See why this may be: https://goo.gl/39bRNJ
18+
Log.d(TAG, "From: ${remoteMessage.from}")
19+
20+
scheduleJob()
21+
22+
// Check if message contains a notification payload.
23+
remoteMessage.notification?.let {
24+
Log.d(TAG, "Message Notification Body: ${it.body}")
25+
}
26+
27+
// Also if you intend on generating your own notifications as a result of a received FCM
28+
// message, here is where that should be initiated. See sendNotification method below.
29+
}
30+
// [END receive_message]
31+
32+
// [START on_new_token]
33+
/**
34+
* Called if the FCM registration token is updated. This may occur if the security of
35+
* the previous token had been compromised. Note that this is called when the
36+
* FCM registration token is initially generated so this is where you would retrieve the token.
37+
*/
38+
override fun onNewToken(token: String) {
39+
Log.d(TAG, "Refreshed token: $token")
40+
41+
// If you want to send messages to this application instance or
42+
// manage this apps subscriptions on the server side, send the
43+
// FCM registration token to your app server.
44+
sendRegistrationToServer(token)
45+
}
46+
// [END on_new_token]
47+
48+
private fun scheduleJob() {
49+
// [START dispatch_job]
50+
val work = OneTimeWorkRequest
51+
.Builder(SendSmsWorker::class.java)
52+
.build()
53+
54+
WorkManager
55+
.getInstance(this)
56+
.enqueue(work)
57+
// [END dispatch_job]
58+
}
59+
private fun sendRegistrationToServer(token: String?) {
60+
// TODO: Implement this method to send token to your app server.
61+
Log.d(TAG, "sendRegistrationTokenToServer($token)")
62+
}
63+
64+
companion object {
65+
private val TAG = MyFirebaseMessagingService::class.simpleName
66+
}
67+
68+
internal class SendSmsWorker(appContext: Context, workerParams: WorkerParameters) : Worker(appContext, workerParams) {
69+
override fun doWork(): Result {
70+
Log.i(TAG, "fetching messages")
71+
val smsService = SmsManagerService()
72+
val messages = HttpSmsApiService().getOutstandingMessages()
73+
messages.forEach {
74+
message -> smsService.SendMessage(this.applicationContext, message, null, null)
75+
}
76+
Log.i(TAG, "received [${messages.size}] messages")
77+
return Result.success()
78+
}
79+
}
80+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package com.httpsms
2+
3+
import android.util.Log
4+
import okhttp3.OkHttpClient
5+
import okhttp3.Request;
6+
import java.net.URI
7+
8+
9+
class HttpSmsApiService {
10+
private val baseURL = URI("https://httpsms.free.beeceptor.com")
11+
12+
fun getOutstandingMessages(): List<Message> {
13+
val client = OkHttpClient()
14+
15+
val request: Request = Request.Builder()
16+
.url(baseURL.resolve("/v1/messages/outstanding").toURL())
17+
.build()
18+
19+
val response = client.newCall(request).execute()
20+
if (response.isSuccessful) {
21+
val payload = MessagesOutstanding.fromJson(response.body!!.string())?.data
22+
if (payload == null) {
23+
Log.e(TAG, "cannot decode payload [${response.body}]")
24+
return listOf();
25+
}
26+
return payload
27+
}
28+
29+
Log.e(TAG, "invalid response with code [${response.code}] and payload [${response.body}]")
30+
return listOf()
31+
}
32+
33+
companion object {
34+
private val TAG = HttpSmsApiService::class.simpleName
35+
}
36+
}

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

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import android.widget.Toast
1515
import androidx.activity.result.contract.ActivityResultContracts
1616
import androidx.appcompat.app.AppCompatActivity
1717
import androidx.core.app.ActivityCompat
18+
import androidx.core.content.ContextCompat
1819
import java.util.*
1920

2021

@@ -60,17 +61,28 @@ class MainActivity : AppCompatActivity() {
6061
) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(
6162
this,
6263
Manifest.permission.READ_PHONE_STATE
64+
) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(
65+
this,
66+
Manifest.permission.SEND_SMS
67+
) != PackageManager.PERMISSION_GRANTED
68+
&& ActivityCompat.checkSelfPermission(
69+
this,
70+
Manifest.permission.RECEIVE_SMS
6371
) != PackageManager.PERMISSION_GRANTED
6472
) {
6573
// You can directly ask for the permission.
6674
// The registered ActivityResultCallback gets the result of this request.
6775
requestPermissionLauncher.launch(Manifest.permission.READ_SMS)
6876
requestPermissionLauncher.launch(Manifest.permission.READ_PHONE_NUMBERS)
6977
requestPermissionLauncher.launch(Manifest.permission.READ_PHONE_STATE)
78+
requestPermissionLauncher.launch(Manifest.permission.SEND_SMS)
79+
requestPermissionLauncher.launch(Manifest.permission.RECEIVE_SMS)
80+
7081
}
7182

7283
val phoneNumber = telephonyManager.line1Number ?: "NO_PHONE_NUMBER"
7384
Log.d(logTag, phoneNumber)
7485
return phoneNumber
7586
}
87+
7688
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
// To parse the JSON, install Klaxon and do:
2+
//
3+
// val welcome4 = Welcome4.fromJson(jsonString)
4+
5+
package com.httpsms
6+
7+
import com.beust.klaxon.*
8+
9+
private val klaxon = Klaxon()
10+
11+
data class MessagesOutstanding (
12+
val data: List<Message>,
13+
val message: String,
14+
val status: String
15+
) {
16+
public fun toJson() = klaxon.toJsonString(this)
17+
companion object {
18+
public fun fromJson(json: String) = klaxon.parse<MessagesOutstanding>(json)
19+
}
20+
}
21+
22+
data class Message (
23+
val contact: String,
24+
val content: String,
25+
26+
@Json(name = "created_at")
27+
val createdAt: String,
28+
29+
@Json(name = "failure_reason")
30+
val failureReason: String,
31+
32+
val id: String,
33+
34+
@Json(name = "last_attempted_at")
35+
val lastAttemptedAt: String,
36+
37+
@Json(name = "order_timestamp")
38+
val orderTimestamp: String,
39+
40+
val owner: String,
41+
42+
@Json(name = "received_at")
43+
val receivedAt: String,
44+
45+
@Json(name = "request_received_at")
46+
val requestReceivedAt: String,
47+
48+
@Json(name = "send_time")
49+
val sendTime: Long,
50+
51+
@Json(name = "sent_at")
52+
val sentAt: String,
53+
54+
val status: String,
55+
val type: String,
56+
57+
@Json(name = "updated_at")
58+
val updatedAt: String
59+
)
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package com.httpsms
2+
3+
import android.app.PendingIntent
4+
import android.content.Context
5+
import android.telephony.SmsManager
6+
7+
class SmsManagerService {
8+
fun SendMessage(context: Context, message: Message, sentIntent:PendingIntent, deliveryIntent: PendingIntent) {
9+
val smsManager: SmsManager = context.getSystemService(SmsManager::class.java)
10+
smsManager.sendTextMessage(message.contact, message.owner, message.content, sentIntent, deliveryIntent)
11+
}
12+
}

0 commit comments

Comments
 (0)