Reputation: 335
I am stuck with one question for more than one month now. I want to start a broadcast receiver from an Android WorkManager class. I want to receive/filter all incoming text messages and then post to a server. However, my current solution cannot work for many hours before the android system kills the app and the receiver sync stops, or by the time I extract the text message from the PDU object (coming from telephone Intent) is onReceive method has already returned. Therefore to solve this I wish to keep broadcast onReceive method running inside a WorkManager to ensure the process does not terminate so fast. I have tried reading but I am not getting the kind of solution that works well with me, or maybe there is something not clear to me about the Broadcast Receiver or how android background processes work. This is my current implementation. Below is the onReceive() method as implemented on the MessageReceiver that extends BroadcastReceiver
@TargetApi(Build.VERSION_CODES.M)
@Override
public void onReceive(final Context context, Intent intent) {
this.context= context;
if (Telephony.Sms.Intents.SMS_RECEIVED_ACTION.equals(intent.getAction())) {
final Bundle data = intent.getExtras();
if (data !=null ) {
try {
final Object[] pdusObj = (Object[]) data.get("pdus");
if (pdusObj != null) {
for (int i = 0; i < pdusObj.length; i++) {
SmsMessage currentMessage =
SmsMessage.createFromPdu((byte[]) pdusObj[i]);
Log.d(TAG, "run: currentMessage: " + currentMessage);
Log.d(TAG, "passReceivedMsg: handleMessage: message " + currentMessage);
int msgNo = counter++;
msgID = "SMS_ID_0" + msgNo;
sender = currentMessage.getDisplayOriginatingAddress();
text_message = currentMessage.getDisplayMessageBody();
long timestampMilliseconds = System.currentTimeMillis();
timestamp = formatter.format(timestampMilliseconds);
Data.Builder dataBuilder = new Data.Builder();
dataBuilder.putString("sender",sender);
dataBuilder.putString("message",text_message);
dataBuilder.putString("timestamp",timestamp);
dataBuilder.putString("sms_id",msgID);
// Log.d(TAG, "onReceive: key:" +key+ " and keyValue "+data.get(key));
WorkManager mWorkManager = WorkManager.getInstance();
OneTimeWorkRequest mRequest = new OneTimeWorkRequest
.Builder(MessageSyncWorker.class)
.setInputData(dataBuilder.build())
.build();
mWorkManager.enqueue(mRequest);
}
}
}
catch (Exception e){
Log.d(TAG, "onReceive: Exception occured "+e.getMessage());
}
}
}
}
Below is my MessageSyncWorker class that extends the Worker- doWork ()method
@NonNull
@Override
public Result doWork() {
Data inputData1 = getInputData();
sender = inputData1.getString("sender");
text_message = inputData1.getString("message");
timestamp = inputData1.getString("timestamp");
msgID = inputData1.getString("sms_id");
Log.d(TAG, "doWork: Mesage "+text_message);
SharedPreferences sharedPreferences =
PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
BASE_API_URL = sharedPreferences.getString("settings_server_url", "");
Log.d(TAG, "doWork: BASE URL "+BASE_API_URL);
try {
//here I upload the data to the server
uploadMessageData();
} catch (JSONException e) {
e.printStackTrace();
Log.d(TAG, "doWork: uploadMessage method Exception "+e.getMessage());
}
return Result.success();
}
Upvotes: 1
Views: 1437
Reputation: 335
Finally, I have cracked it after a detailed discussion as can be seen in the comments area (for this question). I now have working code, and I trust by sharing I can help someone else stuck with similar. Below is how I did it.
here is the onReceive() method;
@Override
public void onReceive(Context context, Intent intent) {
if (Telephony.Sms.Intents.SMS_RECEIVED_ACTION
.equals(intent.getAction())){
this.context = context;
SmsMessage smsMessage = null;
StringBuilder fullMessage = new StringBuilder();
for (SmsMessage new_smsMessage : Telephony.Sms.Intents.getMessagesFromIntent(intent)){
smsMessage = new_smsMessage;
fullMessage.append(smsMessage.getDisplayMessageBody());
}
if (smsMessage ==null){
return;
}
String sender = smsMessage.getOriginatingAddress();
long timestampMilliseconds = System.currentTimeMillis();
String timestamp = formatter.format(timestampMilliseconds);
Log.d("NeTxt Receiver ", "onReceive: fullMessage: "+fullMessage);
Data.Builder dataBuilder = new Data.Builder();
dataBuilder.putString("fullMessage",fullMessage.toString());
dataBuilder.putString("sender", sender);
dataBuilder.putString("timestamp",timestamp);
//defining constraints
Constraints task_constraints = new Constraints.Builder()
.setRequiredNetworkType(NetworkType.CONNECTED)
.build();
//scheduling the work
WorkManager mWorkManager = WorkManager.getInstance();
OneTimeWorkRequest mRequest = new OneTimeWorkRequest
.Builder(NewTxtWorker.class)
.setInputData(dataBuilder.build())
.setConstraints(task_constraints)
.build();
mWorkManager.enqueue(mRequest);
mWorkManager.getWorkInfoById(mRequest.getId());
}
}
below is my doWork() method;
@NonNull
@Override
public Result doWork() {
Data inputData = getInputData();
String sender = inputData.getString("sender");
String text_message = inputData.getString("fullMessage");
String timestamp = inputData.getString("timestamp");
Log.d("Txt WorkManager", "doWork: fullmessage: "+text_message);
assert sender != null;
assert text_message != null;
if (!timestamp.isEmpty()||
!sender.isEmpty()||
!text_message.isEmpty()){
FirebaseFirestore fireDb = FirebaseFirestore.getInstance();
Map<String, Object> message = new HashMap<>();
message.put("text_message", text_message);
message.put("sender", sender);
message.put("timestamp", timestamp);
//sync the received message with the firebase firestore db
fireDb.collection("text_messages")
.add(message)
.addOnSuccessListener(new OnSuccessListener<DocumentReference>() {
@Override
public void onSuccess(DocumentReference documentReference) {
Log.d("Txt WorkManager", "onSuccess: doc Id"
+documentReference.getId());
}
})
.addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception e) {
Log.d("Txt WorkManager", "onFailure: "+e.getMessage());
}
}) ;
}
return Result.failure();
}
Upvotes: 1