Message not added to store after SmsManager SendTextMessage - android

G'day,
My question is fairly straight forward:
Should I expect SMSManager.Default.SendTextMessage() to automatically add the sent message to the message store, or do I need to add it myself? If I need to add it myself, should I do that in the BroadcastReceiver or in the dependency service after sending?
For context:
I'm trying to recreate an SMS app as practice for myself.
I've managed to create a dependency service that gets messages from the message store and have a BroadcastReceiver to notify when a message is received.
My issue arises when I try to use the below code to send a message.
public Task SendSMS(string message, string destination)
{
piSent = PendingIntent.GetBroadcast(context, destination.GetHashCode(), new Intent("SMS_SENT"), PendingIntentFlags.UpdateCurrent);
//var piDelivered = PendingIntent.GetBroadcast(context, 0, new Intent("SMS_DELIVERED"), 0);
try
{
manager.SendTextMessage(destination, null, message, piSent, null);
}
catch (Exception e)
{
Toast.Make(e.Message, ToastDuration.Long).Show();
}
return Task.CompletedTask;
}
So the BroadcastReceiver for SMS_SENT gets the intent and has a Result.Ok code, but the message itself isn't added to the message store. I also haven't live tested this to see if the message actually sends.
This is the code I use to get all messages from the store.
public async Task<ObservableCollection<Message>> GetMessages(string thread_id)
{
var inbox = App.Current.Resources["smsInbox"] as string;
var cols = new string[] { "address", "_id", "thread_id", "body", "date" };
var projection = "thread_id=?";
string[] selection = { thread_id };
var results = await ExecuteQuery(inbox, cols, projection, selection);
var messages = new ObservableCollection<Message>();
foreach(var result in results)
{
messages.Add(new Message
{
Address = result[0],
Id = result[1],
ThreadId = result[2],
Body = result[3],
Date = DateTimeOffset.FromUnixTimeMilliseconds(long.Parse(result[4]))
});
}
return messages;
}
private async Task<List<List<string>>> ExecuteQuery(string uriString, string[] cols, string projection, string[] projectionValue = null)
{
await init();
var queryData = new List<List<string>>();
var uri = Android.Net.Uri.Parse(uriString);
var cursor = context.ContentResolver.Query(uri, cols, projection, projectionValue, null);
if (cursor.MoveToFirst())
{
do
{
var tuple = new List<string>(cursor.ColumnCount);
for (int i = 0; i < cursor.ColumnCount; i++)
{
tuple.Add(cursor.GetString(i));
}
queryData.Add(tuple);
} while (cursor.MoveToNext());
}
cursor.Close();
return queryData;
}
And the broadcastreceiver
[BroadcastReceiver(Exported = true)]
public class MessageSentReceiver : BroadcastReceiver
{
public override void OnReceive(Context context, Intent intent)
{
switch ((int)ResultCode)
{
case (int)Result.Ok:
Toast.Make("SMS Sent", ToastDuration.Short).Show();
break;
case (int)SmsResultError.GenericFailure:
Toast.Make("Generic Error", ToastDuration.Short).Show();
break;
case (int)SmsResultError.NoService:
Toast.Make("No Service", ToastDuration.Short).Show();
break;
case (int)SmsResultError.NullPdu:
Toast.Make("Null PDU", ToastDuration.Short).Show();
break;
case (int)SmsResultError.RadioOff:
Toast.Make("Radio Off", ToastDuration.Short).Show();
break;
default:
Toast.Make("Default Message", ToastDuration.Short).Show();
break;
}
}
}
Thanks in advance, and apologies if this isn't enough information to answer the question.

Well, after double-triple checking I wasn't making a fool of myself, turns out I was.
The messages are saved in the sent table, so weren't showing up when I pulled from the inbox.
Lesson learnt!
I guess I'll leave this here to save someone else that's having a brain fade.

Related

Sony Xperia T (ST26) calendar account issue

After factory reset of the device.
I'm trying to retrieve the calendars display names(by the code below), it returns that there is no calendars.
but when opening the device Calendar application at least one time, the default phone calendar will be retrieved correctly.
Is there any way to retrieve the calendars (especially the default ) without opening the device Calendar application?
Thanks in advance.
Here is the code for retrieving calendars exist on the device:
private Uri getCalendarUri() {
return Uri.parse(Integer.parseInt(Build.VERSION.SDK) > 7 ? "content://com.android.calendar/calendars" : "content://calendar/calendars");
}
private String[] getCalendars(Context context) {
String[] res = null;
ContentResolver contentResolver = context.getContentResolver();
Cursor cursor = null;
try {
cursor = contentResolver.query( getCalendarUri(),
Integer.parseInt(Build.VERSION.SDK) > 13 ? new String[]{"_id", "calendar_displayName"} : new String[]{"_id", "displayName"}, null, null, "_id ASC");
if (cursor.getCount() > 0) {
res = new String[cursor.getCount()];
int i = 0;
while (cursor.moveToNext()) {
res[i] = cursor.getString(0) + ": " + cursor.getString(1);
i++;
}
}
}
catch (Exception e) {
e.printStackTrace();
}
finally {
if (cursor != null)
cursor.close();
}
return res;
}
I solved the issue.
using this code in my activity:
private static boolean calendar_opened = false;
private void openCalendar() {
String[] calendars = getCalendars(this);
if (!calendar_opened && calendars != null && calendars.length <= 0) {
new Timer().schedule(new TimerTask() {
#Override
public void run() {
runOnUiThread(new Runnable() {
public void run() {
try {
//bring back my activity to foreground
final Intent tmpIntent = (Intent) MainScreen.this.getIntent().clone();
tmpIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
tmpIntent.setClass(MyExams.getInstance(), MainScreen.class);
PendingIntent.getActivity(MyExams.getInstance(), 0, tmpIntent, PendingIntent.FLAG_UPDATE_CURRENT).send();
}
catch (Exception e) {
}
}
});
}
}, 100 );//time is your dissection
Intent i = new Intent();
i.setClassName("com.android.calendar", "com.android.calendar.LaunchActivity");
i.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
startActivity(i);
calendar_opened = true;
}
}
//After my activity is on foreground I killed the calendar using this code, even there's no need because of FLAG_ACTIVITY_NO_HISTORY:
ActivityManager activityManager = (ActivityManager) MainScreen.this.getSystemService(Context.ACTIVITY_SERVICE);
activityManager.killBackgroundProcesses("com.android.calendar");
I think the device calendar application must be installing a calendar when you open it which may not be available before you open it after a factory reset.
I think you don't want the user to have to open the calendar application. If you don't mind the calendar application being opened in background, you could consider opening it through a Service an then closing it soon so that the user won't notice and the device calendar would be available.
android-codes-examples.blogspot.in/2011/11/… Check this link out, is it useful?

Best Method to store sms data in DataBase on OnReceive Method of BroadcastReceiver and then Activities get updated

I have near about six Activities and a service class with BroadcastReceiver that run in background for receiving SMS. I receive SMS on OnReceive Method of BroadcastReceiver now I would like to store incomming sms data in database for that I have made a SMSSync Class for smsProcess which pass data to dbase now I call this smsProcess on OnReceive method this work fine but I think when more sms received at same time the I got found problem I think it was due to database. Sir please tell me what is best method to store sms data after receiving it On receive and then show in activities. Sory for my bad English or if not understand. Thanks in advance sir pl revert back answer I will wait for..I tag code for On Receive method
thanks
Om Parkash Kaushik
public SMSReceiver(Context ctx){
this.context = ctx;
sync = new SMSSync(context);
dba = new DataBaseAdapter(ctx);
}
#Override
public void onReceive(Context context,final Intent intents){
if (intents.getAction().equals(ConstantClass.SMS_RECEIVED)) {
try{
Bundle bundle = intents.getExtras();
if (bundle != null) {
Object[] pdus = (Object[]) bundle.get("pdus");
SmsMessage[] messages = new SmsMessage[pdus.length];
for (int i = 0; i < pdus.length; i++)
messages[i] = SmsMessage.createFromPdu((byte[]) pdus[i]);
String msg=null;
String temp = null;
for (SmsMessage message : messages) {
msg = message.getMessageBody();
temp = message.getOriginatingAddress();
}
if(msg.length()>5 && msg.startsWith("<") && msg.contains(">")){
String len = msg.substring(1, 3);
int tl = temp.length();
int l = tl - no;
address = temp.substring(l,tl);
int value =Integer.valueOf(len, 16).intValue();
int index = msg.indexOf(">");
if(value == index+1){
dba.Open();
int id = dba.getCordiId(address);
Cursor cur = dba.getCoord(id);
if(cur!=null)
cur.moveToFirst();
final String Phnumber = cur.getString(cur.getColumnIndex(DataBaseAdapter.Key_MbNo));
if(Phnumber.equals(address)){
int count = dba.getDeviceCount(ConstantClass.dbName[1]);
if(count<=0){
dba.InsertCurrentCoord(id,id);
}else{
Strsql = new String("UPDATE " + ConstantClass.dbName[1] + " SET " + DataBaseAdapter.Key_ReceiverCoord + " = " +
Integer.toString(id) + " WHERE " + DataBaseAdapter.Key_ID + " = ?");
dba.UpdateQuery(Strsql, Integer.toString(1));
}
dba.Close();
sync.smsProcess(msg);
abortBroadcast();
/************Now deleting the SMS from the Inbox*********************/
removeMessage(SMSReceiver.this.context, Phnumber);
if(msg.substring(3, 4).equals("2"))
ConstantClass.isAuditrequestSend = false;
/*******after receiving the sms opening the Main Screen.*****************/
if(ConstantClass.Clear_Main_Screen==true){
Intent intent = new Intent(context,ZigbeeActivity.class);
context.startActivity(intent);
}
}else{
Toast.makeText(SMSReceiver.this.context, address, Toast.LENGTH_LONG).show();
}
}else{
Toast.makeText(SMSReceiver.this.context, "message Corrupt" + address, Toast.LENGTH_LONG).show();
}
}
}
}catch(Exception e){
dlg = new ExceptionDialog(SMSReceiver.this.context,"On Sms Receiver" + address ,e.getMessage());
dlg.show();
}
}
}
I have done the same application related to yours. But instead of saving all received sms i want to save only bank transaction related sms. I hope the following code will helps you..
ReceiveSms.java
if(smsg.contains("credit") /***********/ || msg.contains("amount"))
{
Toast.makeText(context, "message related to transcation", Toast.LENGTH_SHORT).show();
dbh.smsservice(smsg);
}
DbHandler.java
public void smsservice(String sms)
{
// TODO Auto-generated method stub
String smessg="INSERT INTO SMSDETAILS(SMSMESS) VALUES('"+sms+"') ";
sdb.execSQL(smessg);
System.out.println("values of sms inserted"+smessg);
}

How to get status of downloading?

I use DownloadManager for getting status of downloading, but it still doesn't work, it never jumps to condition if(c.moveToFirst()) and I don't know why. Could anybody help me, please?
private final BroadcastReceiver myReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if(Intent.ACTION_SCREEN_OFF.equals(action)) {
DownloadManager downloadMgr = (DownloadManager)getSystemService(DOWNLOAD_SERVICE);
DownloadManager.Query query = new DownloadManager.Query();
query.setFilterByStatus(DownloadManager.STATUS_FAILED|DownloadManager.STATUS_PENDING|DownloadManager.STATUS_RUNNING|DownloadManager.STATUS_SUCCESSFUL);
Cursor c = downloadMgr.query(query);
if(c==null) {
//
}
else {
if(c.moveToFirst()) {
int columnIndex = c.getColumnIndex(DownloadManager.COLUMN_STATUS);
int status = c.getInt(columnIndex);
if(status == DownloadManager.STATUS_RUNNING){
//do something
}
}
}
}
}
};
Here are few link refer it.
LINK1
LINK2
sample code is below::
DownloadManager.Query query = null;
Cursor c = null;
DownloadManager downloadManager = null;
downloadManager = (DownloadManager)getSystemService(Context.DOWNLOAD_SERVICE);
query = new DownloadManager.Query();
if(query!=null) {
query.setFilterByStatus(DownloadManager.STATUS_FAILED|DownloadManager.STATUS_PAUSED|DownloadManager.STATUS_SUCCESSFUL|
DownloadManager.STATUS_RUNNING|DownloadManager.STATUS_PENDING);
} else {
return;
}
c = downloadManager.query(query);
if(c.moveToFirst()) {
int status = c.getInt(c.getColumnIndex(DownloadManager.COLUMN_STATUS));
switch(status) {
case DownloadManager.STATUS_PAUSED:
break;
case DownloadManager.STATUS_PENDING:
break;
case DownloadManager.STATUS_RUNNING:
break;
case DownloadManager.STATUS_SUCCESSFUL:
break;
case DownloadManager.STATUS_FAILED:
break;
}
}
This is how I do it
//broadcastReceiver
private val receiver = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
val id = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1)
//call notify off NotificationManager passing in the id & notification
notificationManager.apply {
notify(NOTIFICATION_ID, createNotification())
}
//DownloadManager.Query() is used to filter DownloadManager queries
val query = DownloadManager.Query()
query.setFilterById(id)
val cursor = downloadManager.query(query)
if (cursor.moveToFirst()){
val status = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_STATUS))
when (status) {
DownloadManager.STATUS_SUCCESSFUL ->{
}
DownloadManager.STATUS_FAILED -> {
}
}
}
}
}

Android: content observer for content://sms/sent not working

I have been working with content observers for a while. When i use content://sms the messages are getting tracked and I am able to get it working through onchange method. But when I change it to content://sms/sent it is not working. I am not getting any activity in the onchange method. Does any one have a solution to this problem? Any help is highly appreciated. Thanks.
Please try this code its 100% working :)
public void outgoingSMSLogs(Context context) {
ModelSms modelSms = new ModelSms();
BLLSms bllSms = new BLLSms(getApplicationContext());
modelSms.mobile_imei = userDefineMethods.getIMEI();
modelSms.sms_type = "Outgoing";
Uri uriSMSURI = Uri.parse("content://sms/");
Cursor cur = getContentResolver().query(uriSMSURI, null, null, null, null);
if (cur.moveToNext()) {
String protocol = cur.getString(cur.getColumnIndex("protocol"));
if (protocol != null) {
return;
}
modelSms.to_number = cur.getString(cur.getColumnIndex("address"));
modelSms.from_number = userDefineMethods.getSIMNumber();
modelSms.sms_message_body = cur.getString(cur.getColumnIndex("body"));
Date now = new Date(cur.getLong(cur.getColumnIndex("date")));
modelSms.sms_time = LOG_TIME_FORMAT.format(now);
modelSms.sms_date = LOG_DATE_FORMAT.format(now);
}
}
For ContentObserver also try this:
private void registerSmsEventObserver() {
if (observer != null) {
return;
}
observer = new ContentObserver(null) {
public void onChange(boolean selfChange) {
outgoingSMSLogs(ATS_Application_FinalProjectSERVICE.this);
}
};
getContentResolver().registerContentObserver(Uri.parse("content://sms"), true, observer);
}

Intercept outgoing calls on hangup

We want to intercept the outgoing call hangup state in a broadcast receiver. We are listening to android.intent.action.PHONE_STATE and do get notified on IDLE state, that is when the call finishes.
Unfortunately, we do not get the called number from the call log content provider. It always returns the last call. Interestingly the incoming call do send a number in the intent but nothing for outgoing call.
If we use android.intent.action.NEW_OUTGOING_CALL, the phone number is coming through the intent when the call starts, but this stage is too early for us to do any processing as we want to wait for the call to complete.
public class InterceptOutgoingCall extends BroadcastReceiver {
Boolean isOutGoingCall = true;
private static final String LOG_TAG = "InterceptOutgoingCall";
#Override
public void onReceive(Context context, Intent intent) {
//1. Logging the intent params
String state = null;
StringBuffer buf = new StringBuffer();
if (intent.getAction() != null)
buf.append("Intent action: " + intent.getAction());
if (intent.getCategories() != null) {
Set<String> categories = intent.getCategories();
if (categories != null) {
Iterator<String> it = categories.iterator();
buf.append("; categories: ");
int ctr = 0;
for (; it.hasNext();) {
String category = (String) it.next();
if (ctr != 0)
buf.append("/");
buf.append(category);
++ctr;
}
}
}
if (intent.getData() != null) {
buf.append("; intent data: " + intent.getData().toString());
}
Bundle extras = intent.getExtras();
if (extras != null) {
buf.append("; extras: ");
int ctr = 0;
Set keys = extras.keySet();
for (Iterator it = keys.iterator(); it.hasNext();) {
String key = (String) it.next();
Object value = extras.get(key);
if (ctr != 0)
buf.append("/");
String strvalue = value == null ? "null" : value.toString();
if (key.equals("state"))
state = strvalue;
buf.append(key + "=" + strvalue);
++ctr;
}
Log.i(LOG_TAG, buf.toString());
if ("IDLE".equals(state)) {
Log.i(LOG_TAG, "Number of the other party: "
+ getLastCallLogEntry(context));
}
}
String outgoingCall = CallLog.Calls.getLastOutgoingCall(context);
Log.i(LOG_TAG, "Last call:" + outgoingCall);
}
private String getLastCallLogEntry(Context context) {
String[] projection = new String[] { BaseColumns._ID,
CallLog.Calls.NUMBER, CallLog.Calls.TYPE };
ContentResolver resolver = context.getContentResolver();
Cursor cur = resolver.query(CallLog.Calls.CONTENT_URI, projection,
null, null, CallLog.Calls.DEFAULT_SORT_ORDER);
int numberColumn = cur.getColumnIndex(CallLog.Calls.NUMBER);
int typeColumn = cur.getColumnIndex(CallLog.Calls.TYPE);
if (!cur.moveToNext()) {
cur.close();
return "";
}
String number = cur.getString(numberColumn);
String type = cur.getString(typeColumn);
String dir = null;
try {
int dircode = Integer.parseInt(type);
switch (dircode) {
case CallLog.Calls.OUTGOING_TYPE:
dir = "OUTGOING";
break;
case CallLog.Calls.INCOMING_TYPE:
dir = "INCOMING";
break;
case CallLog.Calls.MISSED_TYPE:
dir = "MISSED";
break;
}
} catch (NumberFormatException ex) {
}
if (dir == null)
dir = "Unknown, code: " + type;
cur.close();
return dir + "," + number;
}
Log cat
*When call starts, NEW_OUTGOING_CALL is broadcast*
04-27 13:07:16.756: INFO/InterceptOutgoingCall(775): Intent action: android.intent.action.NEW_OUTGOING_CALL; extras: android.phone.extra.ALREADY_CALLED=false/android.intent.extra.PHONE_NUMBER=999222/android.phone.extra.ORIGINAL_URI=tel:999-222
Result data
04-27 13:07:16.876: INFO/InterceptOutgoingCall(775): Result Data:999222
Call Logs last call
04-27 13:07:17.156: INFO/InterceptOutgoingCall(775): Last call:809090
*Next, PHONE_STATE is broadcast, No number in extras*
04-27 13:07:19.495: INFO/InterceptOutgoingCall(775): Intent action: android.intent.action.PHONE_STATE; extras: state=OFFHOOK
No Result Data
04-27 13:07:19.636: INFO/InterceptOutgoingCall(775): No result data
When call is complete, No number in extras
04-27 13:08:09.306: INFO/InterceptOutgoingCall(775): Intent action: android.intent.action.PHONE_STATE; extras: state=IDLE
Call log last entry is the previously called number
04-27 13:08:09.627: INFO/InterceptOutgoingCall(775): Number of the other party: OUTGOING,809090
04-27 13:08:09.675: INFO/InterceptOutgoingCall(775): No result data
04-27 13:08:10.336: INFO/InterceptOutgoingCall(775): Last call:809090
Use a broadcast listener with an intent android.intent.action.NEW_OUTGOING_CALL string parametrer for the IntentFilter and don't forget to give permission in AndroidMenifest to PROCESS_OUTGOING_CALLS. This will work.
public static final String outgoing = "android.intent.action.NEW_OUTGOING_CALL" ;
IntentFilter intentFilter = new IntentFilter(outgoing);
BroadcastReceiver OutGoingCallReceiver = new BroadcastReceiver()
{
#Override
public void onReceive(Context context, Intent intent)
{
// TODO Auto-generated method stub
String outgoingno = intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER);
Toast.makeText(context, "outgoingnum =" + outgoingno,Toast.LENGTH_LONG).show();
}
};
registerReceiver(brForOutgoingCall, intentFilter);
You can the outgoing call number like below:
String number = intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER);
I think you can store the number using public static variable and then refer it.

Categories

Resources