mirror of
https://github.com/vernu/textbee.git
synced 2026-04-30 19:54:44 -04:00
Merge pull request #96 from vernu/improve-call-reliability
Improve received sms and status tracking reliability using work manager
This commit is contained in:
@@ -11,8 +11,8 @@ android {
|
||||
applicationId "com.vernu.sms"
|
||||
minSdk 24
|
||||
targetSdk 32
|
||||
versionCode 14
|
||||
versionName "2.6.1"
|
||||
versionCode 15
|
||||
versionName "2.6.2"
|
||||
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
|
||||
@@ -54,6 +54,8 @@ dependencies {
|
||||
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
|
||||
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
|
||||
implementation 'com.journeyapps:zxing-android-embedded:4.1.0'
|
||||
|
||||
implementation 'androidx.work:work-runtime:2.7.1'
|
||||
|
||||
// def room_version = "2.4.2"
|
||||
// implementation "androidx.room:room-runtime:$room_version"
|
||||
|
||||
@@ -14,7 +14,9 @@
|
||||
<uses-permission android:name="android.provider.Telephony.SMS_RECEIVED" />
|
||||
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<application
|
||||
android:name=".SMSGatewayApplication"
|
||||
android:allowBackup="true"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
@@ -22,6 +24,12 @@
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/Theme.SMSGateway"
|
||||
android:usesCleartextTraffic="true" >
|
||||
|
||||
<provider
|
||||
android:name="androidx.startup.InitializationProvider"
|
||||
android:authorities="${applicationId}.androidx-startup"
|
||||
tools:node="remove" />
|
||||
|
||||
<service
|
||||
android:name=".services.FCMService"
|
||||
android:exported="false"
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
package com.vernu.sms;
|
||||
|
||||
import android.app.Application;
|
||||
|
||||
import androidx.work.Configuration;
|
||||
import androidx.work.WorkManager;
|
||||
|
||||
public class SMSGatewayApplication extends Application implements Configuration.Provider {
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Configuration getWorkManagerConfiguration() {
|
||||
return new Configuration.Builder()
|
||||
.setMinimumLoggingLevel(android.util.Log.INFO)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
@@ -6,17 +6,13 @@ import android.content.Intent;
|
||||
import android.provider.Telephony;
|
||||
import android.telephony.SmsMessage;
|
||||
import android.util.Log;
|
||||
import com.vernu.sms.ApiManager;
|
||||
import com.vernu.sms.AppConstants;
|
||||
import com.vernu.sms.dtos.SMSDTO;
|
||||
import com.vernu.sms.dtos.SMSForwardResponseDTO;
|
||||
import com.vernu.sms.helpers.SharedPreferenceHelper;
|
||||
import com.vernu.sms.workers.SMSReceivedWorker;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.Objects;
|
||||
|
||||
import retrofit2.Call;
|
||||
import retrofit2.Response;
|
||||
|
||||
public class SMSBroadcastReceiver extends BroadcastReceiver {
|
||||
private static final String TAG = "SMSBroadcastReceiver";
|
||||
@@ -64,32 +60,7 @@ public class SMSBroadcastReceiver extends BroadcastReceiver {
|
||||
// receivedSMSDTO.setMessage(receivedSMS.getMessage());
|
||||
// receivedSMSDTO.setReceivedAt(receivedSMS.getReceivedAt());
|
||||
|
||||
Call<SMSForwardResponseDTO> apiCall = ApiManager.getApiService().sendReceivedSMS(deviceId, apiKey, receivedSMSDTO);
|
||||
apiCall.enqueue(new retrofit2.Callback<SMSForwardResponseDTO>() {
|
||||
@Override
|
||||
public void onResponse(Call<SMSForwardResponseDTO> call, Response<SMSForwardResponseDTO> response) {
|
||||
// Date now = new Date();
|
||||
if (response.isSuccessful()) {
|
||||
Log.d(TAG, "SMS sent to server successfully");
|
||||
// receivedSMS.setLastAcknowledgedRequestAt(now);
|
||||
// receivedSMS.setServerAcknowledgedAt(now);
|
||||
// updateLocalReceivedSMS(receivedSMS, context);
|
||||
} else {
|
||||
Log.e(TAG, "Failed to send SMS to server");
|
||||
// receivedSMS.setServerAcknowledgedAt(null);
|
||||
// receivedSMS.setLastAcknowledgedRequestAt(now);
|
||||
// receivedSMS.setRetryCount(localReceivedSMS.getRetryCount() + 1);
|
||||
// updateLocalReceivedSMS(receivedSMS, context);
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void onFailure(Call<SMSForwardResponseDTO> call, Throwable t) {
|
||||
Log.e(TAG, "Failed to send SMS to server", t);
|
||||
// receivedSMS.setServerAcknowledgedAt(null);
|
||||
// receivedSMS.setLastAcknowledgedRequestAt(new Date());
|
||||
// updateLocalReceivedSMS(receivedSMS, context);
|
||||
}
|
||||
});
|
||||
SMSReceivedWorker.enqueueWork(context, deviceId, apiKey, receivedSMSDTO);
|
||||
}
|
||||
|
||||
// private void updateLocalReceivedSMS(SMS localReceivedSMS, Context context) {
|
||||
|
||||
@@ -7,16 +7,11 @@ import android.content.Intent;
|
||||
import android.telephony.SmsManager;
|
||||
import android.util.Log;
|
||||
|
||||
import com.vernu.sms.ApiManager;
|
||||
import com.vernu.sms.AppConstants;
|
||||
import com.vernu.sms.dtos.SMSDTO;
|
||||
import com.vernu.sms.dtos.SMSForwardResponseDTO;
|
||||
import com.vernu.sms.helpers.SharedPreferenceHelper;
|
||||
import com.vernu.sms.services.GatewayApiService;
|
||||
import com.vernu.sms.workers.SMSStatusUpdateWorker;
|
||||
|
||||
import retrofit2.Call;
|
||||
import retrofit2.Callback;
|
||||
import retrofit2.Response;
|
||||
|
||||
public class SMSStatusReceiver extends BroadcastReceiver {
|
||||
private static final String TAG = "SMSStatusReceiver";
|
||||
@@ -157,24 +152,7 @@ public class SMSStatusReceiver extends BroadcastReceiver {
|
||||
Log.e(TAG, "Device ID or API key not found");
|
||||
return;
|
||||
}
|
||||
|
||||
GatewayApiService apiService = ApiManager.getApiService();
|
||||
Call<SMSForwardResponseDTO> call = apiService.updateSMSStatus(deviceId, apiKey, smsDTO);
|
||||
|
||||
call.enqueue(new Callback<SMSForwardResponseDTO>() {
|
||||
@Override
|
||||
public void onResponse(Call<SMSForwardResponseDTO> call, Response<SMSForwardResponseDTO> response) {
|
||||
if (response.isSuccessful()) {
|
||||
Log.d(TAG, "SMS status updated successfully - ID: " + smsDTO.getSmsId() + ", Status: " + smsDTO.getStatus());
|
||||
} else {
|
||||
Log.e(TAG, "Failed to update SMS status. Response code: " + response.code());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Call<SMSForwardResponseDTO> call, Throwable t) {
|
||||
Log.e(TAG, "API call failed: " + t.getMessage());
|
||||
}
|
||||
});
|
||||
|
||||
SMSStatusUpdateWorker.enqueueWork(context, deviceId, apiKey, smsDTO);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
package com.vernu.sms.workers;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.work.Data;
|
||||
import androidx.work.Worker;
|
||||
import androidx.work.WorkerParameters;
|
||||
import androidx.work.BackoffPolicy;
|
||||
import androidx.work.Constraints;
|
||||
import androidx.work.NetworkType;
|
||||
import androidx.work.OneTimeWorkRequest;
|
||||
import androidx.work.WorkManager;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.vernu.sms.ApiManager;
|
||||
import com.vernu.sms.dtos.SMSDTO;
|
||||
import com.vernu.sms.dtos.SMSForwardResponseDTO;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import retrofit2.Call;
|
||||
import retrofit2.Response;
|
||||
|
||||
public class SMSReceivedWorker extends Worker {
|
||||
private static final String TAG = "SMSReceivedWorker";
|
||||
private static final int MAX_RETRIES = 5;
|
||||
|
||||
public static final String KEY_DEVICE_ID = "device_id";
|
||||
public static final String KEY_API_KEY = "api_key";
|
||||
public static final String KEY_SMS_DTO = "sms_dto";
|
||||
public static final String KEY_RETRY_COUNT = "retry_count";
|
||||
|
||||
public SMSReceivedWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) {
|
||||
super(context, workerParams);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Result doWork() {
|
||||
String deviceId = getInputData().getString(KEY_DEVICE_ID);
|
||||
String apiKey = getInputData().getString(KEY_API_KEY);
|
||||
String smsDtoJson = getInputData().getString(KEY_SMS_DTO);
|
||||
int retryCount = getInputData().getInt(KEY_RETRY_COUNT, 0);
|
||||
|
||||
if (deviceId == null || apiKey == null || smsDtoJson == null) {
|
||||
Log.e(TAG, "Missing required parameters");
|
||||
return Result.failure();
|
||||
}
|
||||
|
||||
// Check if we've exceeded the maximum retry count
|
||||
if (retryCount >= MAX_RETRIES) {
|
||||
Log.e(TAG, "Maximum retry count reached for received SMS");
|
||||
return Result.failure();
|
||||
}
|
||||
|
||||
SMSDTO smsDTO = new Gson().fromJson(smsDtoJson, SMSDTO.class);
|
||||
|
||||
try {
|
||||
Call<SMSForwardResponseDTO> call = ApiManager.getApiService().sendReceivedSMS(deviceId, apiKey, smsDTO);
|
||||
Response<SMSForwardResponseDTO> response = call.execute();
|
||||
|
||||
if (response.isSuccessful()) {
|
||||
Log.d(TAG, "Received SMS sent to server successfully");
|
||||
return Result.success();
|
||||
} else {
|
||||
Log.e(TAG, "Failed to send received SMS to server. Response code: " + response.code());
|
||||
return Result.retry();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, "API call failed: " + e.getMessage());
|
||||
return Result.retry();
|
||||
}
|
||||
}
|
||||
|
||||
public static void enqueueWork(Context context, String deviceId, String apiKey, SMSDTO smsDTO) {
|
||||
Data inputData = new Data.Builder()
|
||||
.putString(KEY_DEVICE_ID, deviceId)
|
||||
.putString(KEY_API_KEY, apiKey)
|
||||
.putString(KEY_SMS_DTO, new Gson().toJson(smsDTO))
|
||||
.putInt(KEY_RETRY_COUNT, 0)
|
||||
.build();
|
||||
|
||||
Constraints constraints = new Constraints.Builder()
|
||||
.setRequiredNetworkType(NetworkType.CONNECTED)
|
||||
.build();
|
||||
|
||||
OneTimeWorkRequest workRequest = new OneTimeWorkRequest.Builder(SMSReceivedWorker.class)
|
||||
.setConstraints(constraints)
|
||||
.setBackoffCriteria(BackoffPolicy.EXPONENTIAL, 10, TimeUnit.SECONDS)
|
||||
.setInputData(inputData)
|
||||
.addTag("sms_received")
|
||||
.build();
|
||||
|
||||
String uniqueWorkName = "sms_received_" + System.currentTimeMillis();
|
||||
WorkManager.getInstance(context)
|
||||
.beginUniqueWork(uniqueWorkName,
|
||||
androidx.work.ExistingWorkPolicy.APPEND_OR_REPLACE,
|
||||
workRequest)
|
||||
.enqueue();
|
||||
|
||||
Log.d(TAG, "Work enqueued for received SMS from: " + smsDTO.getSender());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
package com.vernu.sms.workers;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.work.Data;
|
||||
import androidx.work.Worker;
|
||||
import androidx.work.WorkerParameters;
|
||||
import androidx.work.BackoffPolicy;
|
||||
import androidx.work.Constraints;
|
||||
import androidx.work.NetworkType;
|
||||
import androidx.work.OneTimeWorkRequest;
|
||||
import androidx.work.WorkManager;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.vernu.sms.ApiManager;
|
||||
import com.vernu.sms.dtos.SMSDTO;
|
||||
import com.vernu.sms.dtos.SMSForwardResponseDTO;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import retrofit2.Call;
|
||||
import retrofit2.Response;
|
||||
|
||||
public class SMSStatusUpdateWorker extends Worker {
|
||||
private static final String TAG = "SMSStatusUpdateWorker";
|
||||
private static final int MAX_RETRIES = 5;
|
||||
|
||||
public static final String KEY_DEVICE_ID = "device_id";
|
||||
public static final String KEY_API_KEY = "api_key";
|
||||
public static final String KEY_SMS_DTO = "sms_dto";
|
||||
public static final String KEY_RETRY_COUNT = "retry_count";
|
||||
|
||||
public SMSStatusUpdateWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) {
|
||||
super(context, workerParams);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Result doWork() {
|
||||
String deviceId = getInputData().getString(KEY_DEVICE_ID);
|
||||
String apiKey = getInputData().getString(KEY_API_KEY);
|
||||
String smsDtoJson = getInputData().getString(KEY_SMS_DTO);
|
||||
int retryCount = getInputData().getInt(KEY_RETRY_COUNT, 0);
|
||||
|
||||
if (deviceId == null || apiKey == null || smsDtoJson == null) {
|
||||
Log.e(TAG, "Missing required parameters");
|
||||
return Result.failure();
|
||||
}
|
||||
|
||||
// Check if we've exceeded the maximum retry count
|
||||
if (retryCount >= MAX_RETRIES) {
|
||||
Log.e(TAG, "Maximum retry count reached for SMS status update");
|
||||
return Result.failure();
|
||||
}
|
||||
|
||||
SMSDTO smsDTO = new Gson().fromJson(smsDtoJson, SMSDTO.class);
|
||||
|
||||
try {
|
||||
Call<SMSForwardResponseDTO> call = ApiManager.getApiService().updateSMSStatus(deviceId, apiKey, smsDTO);
|
||||
Response<SMSForwardResponseDTO> response = call.execute();
|
||||
|
||||
if (response.isSuccessful()) {
|
||||
Log.d(TAG, "SMS status updated successfully - ID: " + smsDTO.getSmsId() + ", Status: " + smsDTO.getStatus());
|
||||
return Result.success();
|
||||
} else {
|
||||
Log.e(TAG, "Failed to update SMS status. Response code: " + response.code());
|
||||
return Result.retry();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, "API call failed: " + e.getMessage());
|
||||
return Result.retry();
|
||||
}
|
||||
}
|
||||
|
||||
public static void enqueueWork(Context context, String deviceId, String apiKey, SMSDTO smsDTO) {
|
||||
Data inputData = new Data.Builder()
|
||||
.putString(KEY_DEVICE_ID, deviceId)
|
||||
.putString(KEY_API_KEY, apiKey)
|
||||
.putString(KEY_SMS_DTO, new Gson().toJson(smsDTO))
|
||||
.putInt(KEY_RETRY_COUNT, 0)
|
||||
.build();
|
||||
|
||||
Constraints constraints = new Constraints.Builder()
|
||||
.setRequiredNetworkType(NetworkType.CONNECTED)
|
||||
.build();
|
||||
|
||||
OneTimeWorkRequest workRequest = new OneTimeWorkRequest.Builder(SMSStatusUpdateWorker.class)
|
||||
.setConstraints(constraints)
|
||||
.setBackoffCriteria(BackoffPolicy.EXPONENTIAL, 10, TimeUnit.SECONDS)
|
||||
.setInputData(inputData)
|
||||
.build();
|
||||
|
||||
String uniqueWorkName = "sms_status_" + smsDTO.getStatus() + "_" + System.currentTimeMillis();
|
||||
WorkManager.getInstance(context)
|
||||
.beginUniqueWork(uniqueWorkName,
|
||||
androidx.work.ExistingWorkPolicy.REPLACE,
|
||||
workRequest)
|
||||
.enqueue();
|
||||
|
||||
Log.d(TAG, "Work enqueued for SMS status update - ID: " + smsDTO.getSmsId());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user