I am building small android application in which I am reading incoming message and I want to mark it as read message. For that I have added required permissions and also added receive for listening incoming messages.Everything is working fine except mark it as read process. I tried it in following ways:
private void markMessageRead(Context context, String number, String body) {
Uri uri = Uri.parse("content://sms/inbox");
Cursor cursor = context.getContentResolver().query(uri, null, null, null, null);
try{
while (cursor.moveToNext()) {
Debug.print("inside mark read before if ------ ");
Debug.print(cursor.getString(cursor.getColumnIndex("address"))+" "+number);
Debug.print(cursor.getInt(cursor.getColumnIndex("read"))+" ");
Debug.print(cursor.getString(cursor.getColumnIndex("body"))+" "+body);
if ((cursor.getString(cursor.getColumnIndex("address")).equals(number)) && (cursor.getInt(cursor.getColumnIndex("read")) == 0)) {
if (cursor.getString(cursor.getColumnIndex("body")).startsWith(body)) {
Debug.print("inside read message inside if ... ");
String SmsMessageId = cursor.getString(cursor.getColumnIndex("_id"));
ContentValues values = new ContentValues();
values.put("read", true);
context.getContentResolver().update(Uri.parse("content://sms/inbox"), values, "_id=" + SmsMessageId, null);
return;
}
}
}
}catch(Exception e)
{
}
}
//inside receiver side ...
#Override
public void onReceive(Context context, Intent intent) {
mContext = context;
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
markMessageRead(mContext, message.getOriginatingAddress(), message.getMessageBody());
}
}, 2000);
}
Everything is working fine without any error. Only thing it is not marking my message as read message. Am I doing anything wrong. Need some help. Thank you.
Related
I want to read the sent message content from the mobile messages. I am not developing an sent sms reading application, but instead I want to read the recent last sent sms content form the mobile inbuilt sms app.
I want to read the sent sms from sent items and send some notification based on the keyword in the message.
I know we have to extend ContentObserver class and use ContentResolver.
Any idea is appreciated. Thank you!
This is my Observer class SMSObserver.java,
public class SMSObserver extends ContentObserver {
private String lastSmsId;
private Context c;
private String phoneNumber;
int type;
String lastID;
public SMSObserver(Handler handler) {
super(handler);
}
#Override
public void onChange(boolean selfChange,Uri uri) {
super.onChange(selfChange);
Uri uriSMSURI = Uri.parse("content://sms/out");
Cursor cur = c.getContentResolver().query(uriSMSURI, null, null, null, "date DESC LIMIT 1");
cur.moveToNext();
//String id = cur.getString(cur.getColumnIndex("_id"));
if( (type == 2 || type == 1) && (!lastID.contentEquals(cur.getString(cur.getColumnIndex("_id")))) ) {
String protocol = cur.getString(cur.getColumnIndex("protocol"));
lastID = cur.getString(cur.getColumnIndex("_id"));
// Message sent
if (protocol == null) {
Log.i("SMSStatus", "SMS Sent");
}
// Message receive
else {
Log.i("SMSStatus", "SMS received");
}
if (smsChecker(lastID)) {
String address = cur.getString(cur.getColumnIndex("address"));
// Optional: Check for a specific sender
if (address.equals(phoneNumber)) {
String message = cur.getString(cur.getColumnIndex("body"));
// Use message content for desired functionality
if(message.contains("Dinner")){
Toast.makeText(c,"Dinner offer for 2!!",Toast.LENGTH_LONG).show();
}
}
}
}
}
// Prevent duplicate results without overlooking legitimate duplicates
public boolean smsChecker(String smsId) {
boolean flagSMS = true;
if (smsId.equals(lastSmsId)) {
flagSMS = false;
}
else {
lastSmsId = smsId;
}
Log.d(lastSmsId ,"LastSmsId");
return flagSMS;
}
}
I'm registering the contentObserver in a class SentSMSTrackerService.java
public class SentSMSTrackerService extends Service {
#Override
public int onStartCommand(Intent intent, int flag, int startId) {
SMSObserver smsObserver = new SMSObserver(new Handler());
ContentResolver contentResolver = getApplicationContext().getContentResolver();
contentResolver.registerContentObserver(Uri.parse("content://sms/out"), true, smsObserver);
return START_STICKY;
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
}
I'm also giving the permission in AndroidManifest.xml
But,still i am not able to read the outgoing sms.
i am using broadcast receiver to read new incoming sms. my problem is when new sms from a contact recieves, my codes can not returns the last message of my contact, it returns the message before last one.
please help me to correct my codes. i am really confused.
public static class SmsReceiver extends BroadcastReceiver {
private static final String SMS_RECEIVED = "android.provider.Telephony.SMS_RECEIVED";
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(SMS_RECEIVED)) {
Bundle bundle = intent.getExtras();
if (bundle != null) {
readVerificationCodeFromInbox();
}
}
}
}
public static void readVerificationCodeFromInbox() {
long currentTime = System.currentTimeMillis();
Uri message = Uri.parse("content://sms/");
ContentResolver cr = context.getContentResolver();
Cursor c = cr.query(message, null, null, null, null);
try {
if (c.moveToFirst()) {
do {
if (c.getString(c.getColumnIndexOrThrow("address")) == null) {
c.moveToNext();
continue;
}
if (c.getString(c.getColumnIndexOrThrow("address")).equalsIgnoreCase("9101620")){
long date = c.getLong(c.getColumnIndexOrThrow("date"));
Log.d("date-->", "" + date);
String Body =c.getString(c.getColumnIndexOrThrow("body")).toString();
String numberOnly= Body.replaceAll("[^0-9]", "");
Log.d("Body-->", "" + numberOnly);
if (currentTime-date<0.25*3600*1000) {
confirm_number.setText(numberOnly);
// EnterVerificationCode(numberOnly);
}else{
Toast.makeText(context, R.string.retry_get_verificationCode_time, Toast.LENGTH_LONG).show();
dialog.dismiss();
}
break;
}
} while (c.moveToNext());
}
c.close();
context.unregisterReceiver(receiver);
} catch (Exception e) {
e.printStackTrace();
}
}
What is the priority of your receiver in AndroidManifest.xml? I faced the same issue because I chose a positive priority where my receiver had more priority than the default Android SMS receiver. So what actually happened was, I tried to read the message before the android SMS receiver and put it into the default SMS database which we are accessing over content resolver.
Try choosing priority to be a negative value and it should work.
PS: This should be a comment but could not post it as I dont have enough reputation.
I have a written a receiver for a NEW_OUTGOING_CALL intent (static receiver). In order not to hold the system, I do the lengthy part of the process in a AsyncTask.
Based on the number dialed, I may or may not start the AsyncTask (and proceed with regular processing). However, the tasks starts on its own, with the right param passed, and I cant figure out how !!
I've grep'ed the project, and there are no other calls to LongOperation other than the one in the CallOneShot function - but the traces surrounding the 'new' statement do not appear.
How can this happen ?
Please find the code attached, sorry for the length, I've tried to cut it down a bit
Thanks for the help
J.
package com.iper.phoneeco;
public class MyReceiver extends BroadcastReceiver {
private static final String TAG = "XXBroadcastReceiver";
FileWriter fDevLog;
MyPrefs myprefs=null;
public final static String EXTRA_MESSAGE = "com.iper.phoneeco.msg1";
#Override
public void onReceive(Context context, Intent intent) {
if(intent.getAction().equalsIgnoreCase("android.intent.action.NEW_OUTGOING_CALL"))
{
Log.d(TAG,"OUTGOING CALL RECEIVED");
String phoneNumber = getResultData();
if (phoneNumber == null) {
// No reformatted number, use the original
phoneNumber = intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER);
}
Log.d(TAG,"phone number:"+phoneNumber);
if (IsToProcess(phoneNumber)) {
Log.d (TAG,"Trapping the call");
// Lets Roll
CallOneShot(phoneNumber);
// and prevent other apps from calling as well
setResultData(null);
// abortBroadcast();
}
else {
Log.d (TAG,"Standard processing");
Toast.makeText(context, "standard processing" , Toast.LENGTH_LONG).show();
}
Log.d (TAG,"Finished processing intent");
}
//
// check is number against a list of exceptions, that we dont handle
//
private boolean IsToProcess(String num){
String[] excluded = {"15","17","18","112","911","991","08.*","^\\*.*","^#.*"};
for (String ex : excluded){
Log.d(TAG,"Exclusion test: "+ex + "versus: "+num);
if (num.matches(ex)) {
Log.d(TAG,"Exclusion FOUND: "+ex);
return false;
}
}
if (num.length() < myprefs.minLen) {
Log.d(TAG,"Exclusion FOUND: Numero trop court");
return false;
}
Log.d(TAG,"Exclusion not found: ");
return true;
}
//
// Displays a toast
//
void MyToast(String s, int col, int dur ) {
Toast toast=Toast.makeText(myprefs.ctx, s, dur);
toast.setGravity(Gravity.CENTER_HORIZONTAL, 0, 0);
toast.getView().setBackgroundColor(col );
LinearLayout toastLayout = (LinearLayout) toast.getView();
TextView toastTV = (TextView) toastLayout.getChildAt(0);
toastTV.setTextSize(20);
toast.show();
}
void MyToast(String s, int col) {
MyToast(s,col,Toast.LENGTH_LONG);
}
public void CallOneShot(String phoneNumber) {
Log.d (TAG,"CallOneShot");
MyToast (myprefs.ctx.getResources().getString(R.string.callbackipg)+" "+phoneNumber,Color.BLUE);
new LongOperation().execute(phoneNumber);
}
//
// the meat....
//
public class LongOperation extends AsyncTask<String, Void, String> {
String numToCall;
#Override
protected String doInBackground(String... params) {
int bytesRead;
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(1024);
byte[] buffer = new byte[1024];
String msgres;
String response;
Log.d(TAG, "Clientthread started");
numToCall=params[0];
Log.d(TAG, "numTocall"+numToCall);
// and add to the call log
ContentValues values = new ContentValues();
values.put(CallLog.Calls.NUMBER, numToCall);
values.put(CallLog.Calls.DATE, System.currentTimeMillis());
values.put(CallLog.Calls.DURATION, 0);
values.put(CallLog.Calls.TYPE, CallLog.Calls.OUTGOING_TYPE);
values.put(CallLog.Calls.NEW, 1);
values.put(CallLog.Calls.CACHED_NAME, "");
values.put(CallLog.Calls.CACHED_NUMBER_TYPE, 0);
values.put(CallLog.Calls.CACHED_NUMBER_LABEL, "");
Log.d(TAG, "Inserting call log placeholder for " + numToCall);
ContentResolver resolver = myprefs.ctx.getContentResolver();
resolver.insert(CallLog.Calls.CONTENT_URI, values);
response=myprefs.ctx.getResources().getString(R.string.errundef);
return response;
}
protected void onPostExecute (String s) {
if (!s.equals("ok")) {
Log.d(TAG,"OnPostExecute - failed: "+s);
MyToast (myprefs.ctx.getResources().getString(R.string.errcallback)+"\n"+s,Color.RED);
}
}
}
}
Have you assign value to myprefs. It seems that you have initialized it to null and never assign it to any value
ok - stupid me is the answer - I had changed the name of the package, and an old version of the package was still on the emulator, trapping the intent ! once I removed it, it all went back to normal...
Many thanks for your help anyway
I am developing an app that notify the user when any SMS marked as read even if the app isn't running
I simply created a contentobserver and I registered it in a service
the problem is that the contentobserver runs if the new SMS inserted or deleted but when the SMS marked as read ( Update operation) it doesn't work
here is my service code
public class Smssendservice extends Service {
private static Timer timer = new Timer();
private Context ctx;
public IBinder onBind(Intent arg0)
{
return null;
}
public void onCreate()
{
super.onCreate();
ctx = this;
startService();
}
private void startService()
{
//timer.scheduleAtFixedRate(new mainTask(), 0, 5000);
Toast.makeText(getApplicationContext(), "Before Register", Toast.LENGTH_SHORT).show();
final Uri SMS_STATUS_URI = Uri.parse("content://sms");
SMSLogger sl= new SMSLogger();
SMSObserver smsSentObserver = new SMSObserver(sl, ctx);
getContentResolver().registerContentObserver(SMS_STATUS_URI, true, smsSentObserver);
Toast.makeText(getApplicationContext(), "After Register", Toast.LENGTH_SHORT).show();
}
}
I am registering my content observer in the service
here is the content observer code
public class SMSObserver extends ContentObserver
{
SMSLogger smsLogger;
Context context;
public SMSObserver(SMSLogger smsLogger, Context context) {
super(new Handler());
this.context=context;
this.smsLogger = smsLogger;
}
#Override
public void onChange(boolean selfChange) {
super.onChange(selfChange);
smsLogger.querySMS(context);
}
}
eventually here is the SMS logger that I show the TOAST if the SMS data changed
public class SMSLogger {
protected void querySMS(Context context) {
Uri uriSMS = Uri.parse("content://sms/");
Cursor cur = context.getContentResolver().query(uriSMS, null, null, null, null);
/* cur.moveToNext(); // this will make it point to the first record, which is the last SMS sent
String body = cur.getString(cur.getColumnIndex("body")); //content of sms
String add = cur.getString(cur.getColumnIndex("address")); //phone num
String time = cur.getString(cur.getColumnIndex("date")); //date
String protocol = cur.getString(cur.getColumnIndex("protocol")); //protocol*/
Toast.makeText(context, "Data Changed CHECK SMS" , Toast.LENGTH_SHORT).show();
/*logging action HERE...*/
}
}
it showed this message "Data Changed CHECK SMS" if new SMS inserted or SMS deleted but in case of update the toast doesnt appear. any clue ?
In your update method, check if the number of entries updated is more than 0.
If it is, do getContext().getContentResolver().notifyChange(uri, null); before you return the number of entries updated.
How to receive broadcast when a user sends SMS from his Android phone? I am creating an application which is taking track of sent SMS and calls. I am done with the calls part, please help me with the SMS. Note that sms are sent by the phone not any application.
----------//solution-----------
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(VIEW_RESOURCE_ID);
SendSmsObserver smsObeserver = (new SendSmsObserver(new Handler()));
ContentResolver contentResolver = this.getContentResolver();
contentResolver.registerContentObserver(Uri.parse("content://sms"),true, smsObeserver);
}
public class SendSmsObserver extends ContentObserver {
public SendSmsObserver(Handler handler) {
super(handler);
}
#Override
public void onChange(boolean selfChange) {
super.onChange(selfChange);
// save the message to the SD card here
Log.d("sent sms", "one text send");
}
}
I found the answer
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(VIEW_RESOURCE_ID);
SendSmsObserver smsObeserver = (new SendSmsObserver(new Handler()));
ContentResolver contentResolver = this.getContentResolver();
contentResolver.registerContentObserver(Uri.parse("content://sms"),true, smsObeserver);
}
public class SendSmsObserver extends ContentObserver {
public SendSmsObserver(Handler handler) {
super(handler);
}
#Override
public void onChange(boolean selfChange) {
super.onChange(selfChange);
// save the message to the SD card here
Log.d("sent sms", "one text send");
}
}
You could build on CallLog. The CallLog provider contains information about placed and received calls.
The Following code can work
Cursor c = null; try {
c = getContentResolver().query(CallLog.Calls.CONTENT_URI, null, null, null, null);
if (c != null && c.moveToFirst()) {
do {
int duration = c.getInt(c.getColumnIndex(CallLog.Calls.DURATION));
// do something with duration
} while (c.moveToNext());
} } finally {
if (c != null) {
c.close();
} }
--------------------------ADDED NEW SOLUTION------------------------
Have a look at:
http://groups.google.com/group/android-developers/browse_thread/thread/9bc7d7ba0229a1d2
and :
http://code.google.com/p/android/issues/detail?id=914
Basically, you can do it by registering a content observer on the SMS
message store.Try
this:
ContentResolver contentResolver = this.getContentResolver();
contentResolver.registerContentObserver(Uri.parse("content://sms"),true, smsObeserver);