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.
UPDATE: I needed to override the onDestroy method to close the Database Helper class object. Works fine now. Just add this in any activity where you create an object of your SQLiteOpenHelper class.
Database dbHelper; //in class
dbHelper = new Database(this, "pulling data",null,1); //in onCreate
#Override
protected void onDestroy()
{
super.onDestroy();
dbHelper.close();
}
I create and update a database from a fragment with data that comes in about every 2 seconds from sensors that are connected over Bluetooth to my Android app.
I go to different activities in my app and those activities should be able to read from the database to display the data in a list/textview, but the issue is that the context in which the database was created and is getting updated is from a fragment. Is there a way to make it so that all activities can read from the database?
I created a class that extends SQLiteOpenHelper, where you can access functions to do CRUD operations, but once I go into another activity and I query the database the cursor pulls nothing up although I inserted and am updating the database in the background from a fragment.
Heads up, I'm pretty new to Android dev and have looked at other questions/solutions but nothing works for me. Appreciate any tutorials or advice to get going, thanks!
Below is my SQLiteOpenHelper class:
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
public class Database extends SQLiteOpenHelper
{
public Context DBcontext = null;
//DatabaseContract version
public static final int DATABASE_VERSION = 1;
public static final String DATABASE_NAME = "Sensors";
public static final String SENSOR_DATA_TABLE_NAME ="SensorData";
public static final String SENSOR_DATA_COLUMN_ID = "SensorDataID";
public static final String NODE_COLUMN_NAME = "Nodes";
public static final String TEMP_COLUMN_NAME = "TemperatureData";
public static final String MOTION_COLUMN_NAME = "MotionData";
public static final String GAS_COLUMN_NAME = "GasData";
public static final String LIGHT_COLUMN_NAME = "LightData";
//Constructor for the Database activity
public DatabaseContract( Context context , String name, SQLiteDatabase.CursorFactory factory, int version) {
super( context, name, factory, version);
}
#Override
public void onCreate(SQLiteDatabase db) {
db.execSQL("CREATE TABLE "+SENSOR_DATA_TABLE_NAME+" ("+SENSOR_DATA_COLUMN_ID+" INTEGER PRIMARY KEY, "+NODE_COLUMN_NAME+ " STRING, "+TEMP_COLUMN_NAME+" STRING, "+MOTION_COLUMN_NAME+" STRING, "+GAS_COLUMN_NAME+" STRING, "+ LIGHT_COLUMN_NAME+" STRING)");
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)
{
db.execSQL("DROP TABLE IF EXISTS " + SENSOR_DATA_TABLE_NAME);
onCreate(db);
}
public boolean checkExist()
{
SQLiteDatabase db = getReadableDatabase();
String query = "SELECT * FROM "+ SENSOR_DATA_TABLE_NAME;
Cursor res = db.rawQuery(query, null);
if(res.getCount() > 0){
res.close();
return true;
}else {
res.close();
return false;
}
}
public void updateSensorData(String node_number, String temp_data, String motion_data, String light_data, String gas_data)
{
SQLiteDatabase db = getWritableDatabase();
String query = "SELECT * FROM " + SENSOR_DATA_TABLE_NAME + " WHERE " + NODE_COLUMN_NAME + " ='" + node_number + "'";
Cursor res = db.rawQuery(query, null);
if (res.getCount() == 0){
res.close();
ContentValues content = new ContentValues();
content.put(NODE_COLUMN_NAME, node_number);
content.put(TEMP_COLUMN_NAME, temp_data);
content.put(MOTION_COLUMN_NAME, motion_data);
content.put(GAS_COLUMN_NAME, gas_data);
content.put(LIGHT_COLUMN_NAME, light_data);
db.insert(SENSOR_DATA_TABLE_NAME, null, content);
}else{
/**try to get ID from cursor, not working so hardcoded 1 for now to test**/
//String ID = Long.toString(res.getLong(res.getColumnIndex(SENSOR_DATA_COLUMN_ID)));
ContentValues contentValues = new ContentValues();
contentValues.put(NODE_COLUMN_NAME, node_number);
contentValues.put(TEMP_COLUMN_NAME, temp_data);
contentValues.put(MOTION_COLUMN_NAME, motion_data);
contentValues.put(GAS_COLUMN_NAME, gas_data);
contentValues.put(LIGHT_COLUMN_NAME, light_data);
//hardcoded ID = 1 just for testing
db.update(SENSOR_DATA_TABLE_NAME, contentValues, SENSOR_DATA_COLUMN_ID + " = ? ", new String[] { "1" } );
}
}
}
Below is the fragment that interacts with the class from above to insert/update data in the database. I took the Google BluetoothChat app and modified it to work for my intended purpose. This fragment interacts with the Database class in the handler for MESSAGE_READ. I parse the data sent to me, then pass it as parameters to the Database function updateSensorData where it takes care of inserting then thereafter updating the data.
import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v7.app.AlertDialog;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.Toast;
public class Bluetooth extends Fragment
{
private static final String TAG = "Bluetooth";
// Intent request codes
private static final int REQUEST_CONNECT_DEVICE_INSECURE = 1;
private static final int REQUEST_ENABLE_BT = 2;
// Layout Views
private Button scan_button;
private Button move;
private DatabaseContract dbHelper;
/**
* Name of the connected device
*/
private String mConnectedDeviceName = null;
/**
* Local Bluetooth adapter
*/
private BluetoothAdapter BAdapter = null;
/**
* Member object for the chat services
*/
private BluetoothChatService mChatService = null;
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
// Get local Bluetooth adapter
BAdapter = BluetoothAdapter.getDefaultAdapter();
if (BAdapter == null)
{
FragmentActivity activity = getActivity();
new AlertDialog.Builder(activity)
.setTitle("Error: Not compatible")
.setMessage("Your phone does not support Bluetooth")
.setPositiveButton("Exit", new DialogInterface.OnClickListener()
{
public void onClick(DialogInterface dialog, int which)
{
System.exit(0);
}
})
.setIcon(android.R.drawable.ic_dialog_alert)
.show();
}
}
#Override
public void onStart()
{
super.onStart();
if (!BAdapter.isEnabled())
{
Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableIntent, REQUEST_ENABLE_BT);
// Otherwise, setup the chat session
}
else if (mChatService == null)
{
setupChat();
}
}
#Override
public void onDestroy()
{
super.onDestroy();
if (mChatService != null)
{
mChatService.stop();
}
}
#Override
public void onResume()
{
super.onResume();
// Performing this check in onResume() covers the case in which BT was
// not enabled during onStart(), so we were paused to enable it...
// onResume() will be called when ACTION_REQUEST_ENABLE activity returns.
if (mChatService != null)
{
// Only if the state is STATE_NONE, do we know that we haven't started already
if (mChatService.getState() == BluetoothChatService.STATE_NONE)
{
// Start the Bluetooth chat services
mChatService.start();
}
}
scan_button.setOnClickListener(new View.OnClickListener()
{
public void onClick(View v)
{
Intent serverIntent = new Intent(getActivity(), DeviceList.class);
startActivityForResult(serverIntent, REQUEST_CONNECT_DEVICE_INSECURE);
}
});
}
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container,
#Nullable Bundle savedInstanceState)
{
View v = inflater.inflate(R.layout.bluetooth, container, false);
Button move = (Button)v.findViewById(R.id.move);
move.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent intent = new Intent(getActivity(), Network.class);
startActivity(intent);
}
});
return v;
}
#Override
public void onViewCreated(View view, #Nullable Bundle savedInstanceState)
{
scan_button = (Button) view.findViewById(R.id.scan_button);
move = (Button) view.findViewById(R.id.move);
}
/**
* Set up the UI and background operations for chat.
*/
private void setupChat()
{
scan_button.setOnClickListener(new View.OnClickListener()
{
public void onClick(View v)
{
Intent serverIntent = new Intent(getActivity(), DeviceList.class);
startActivityForResult(serverIntent, REQUEST_CONNECT_DEVICE_INSECURE);
}
});
// Initialize the BluetoothChatService to perform bluetooth connections
mChatService = new BluetoothChatService(getActivity(), mHandler);
}
private final Handler mHandler = new Handler()
{
#Override
public void handleMessage(Message msg)
{
FragmentActivity activity = getActivity();
switch (msg.what)
{
case Constants.MESSAGE_STATE_CHANGE:
switch (msg.arg1)
{
case BluetoothChatService.STATE_CONNECTED:
Toast.makeText(getActivity(), "Connected to "+mConnectedDeviceName+" setting up network. . .", Toast.LENGTH_SHORT).show();
final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
move.setVisibility(View.VISIBLE);
scan_button.setVisibility(View.INVISIBLE);
}
}, 4000);
break;
case BluetoothChatService.STATE_CONNECTING:
Toast.makeText(getActivity(), "Connecting. . .", Toast.LENGTH_SHORT).show();
break;
case BluetoothChatService.STATE_LISTEN:
case BluetoothChatService.STATE_NONE:
scan_button.setVisibility(View.VISIBLE);
move.setVisibility(View.INVISIBLE);
}
break;
/******************************** where this fragment interacts with SQLiteOpenHelper class for database******************************/
case Constants.MESSAGE_READ:
byte[] readBuf = (byte[]) msg.obj;
// construct a string from the valid bytes in the buffer
String readMessage = new String(readBuf, 0, msg.arg1);
dbHelper = new DatabaseContract(getActivity(), "data transfer for sensors", null, 1);
int node = readMessage.indexOf("node");
int temp_number = readMessage.indexOf("t");
int motion_number = readMessage.indexOf("m");
int light_number = readMessage.indexOf("l");
int gas_number = readMessage.indexOf("g");
String node_number = readMessage.substring(node + 5, node + 6);
String temp_data = readMessage.substring(temp_number, motion_number);
String motion_data = readMessage.substring(motion_number, light_number);
String light_data = readMessage.substring(light_number, gas_number);
String gas_data = readMessage.substring(gas_number);
dbHelper.updateSensorData(node_number, temp_data, motion_data, light_data, gas_data);
break;
case Constants.MESSAGE_DEVICE_NAME:
// save the connected device's name
mConnectedDeviceName = msg.getData().getString(Constants.DEVICE_NAME);
break;
case Constants.MESSAGE_TOAST:
if (null != activity) {
Toast.makeText(activity, msg.getData().getString(Constants.TOAST),
Toast.LENGTH_SHORT).show();
}
break;
}
}
};
//automatically invoked when app starts up
public void onActivityResult(int requestCode, int resultCode, Intent data)
{
switch (requestCode)
{
case REQUEST_CONNECT_DEVICE_INSECURE:
// When DeviceList returns with a device to connect
if (resultCode == Activity.RESULT_OK)
{
connectDevice(data, false);
}
break;
case REQUEST_ENABLE_BT:
// When the request to enable Bluetooth returns
if (resultCode == Activity.RESULT_OK)
{
// Bluetooth is now enabled, so set up a chat session
setupChat();
}
else
{
FragmentActivity activity = getActivity();
new AlertDialog.Builder(activity)
.setTitle("Error")
.setMessage("Bluetooth is disabled")
.setPositiveButton("ENABLE", new DialogInterface.OnClickListener()
{
public void onClick(DialogInterface dialog, int which)
{
Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableIntent, 8);
onDestroy();
onResume();
}
})
.setIcon(android.R.drawable.ic_dialog_alert)
.show();
}
}
}
private void connectDevice(Intent data, boolean insecure)
{
// Get the device MAC address
String address = data.getExtras()
.getString(DeviceList.EXTRA_DEVICE_ADDRESS);
// Get the BluetoothDevice object
BluetoothDevice device = BAdapter.getRemoteDevice(address);
// Attempt to connect to the device
mChatService.connect(device, insecure);
}
}
Below is an example of one of the different classes that needs to access the information in the database. I test it with the checkExist() function and it returns false although in the fragment I do successfully insert then update the sensor data. This is where my problem lies, not sure why it isn't pulling anything from the database
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.ListView;
import android.widget.TextView;
/**Here is an example of one of the activities that needs to pull readings from the database to display**/
public class NodeData extends AppCompatActivity
{
private DatabaseContract dbHelper;
private TextView tempDisplay;
private TextView motionDisplay;
private TextView gasDisplay;
private TextView lightDisplay;
private ListView dataDisplay;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.nodedata);
String node_number = getIntent().getExtras().getString("node_number");
String label = "Node "+node_number+" Data";
TextView textViewToChange = (TextView) findViewById(R.id.node_data_label);
textViewToChange.setText(label);
dbHelper = new DatabaseContract(getApplicationContext(), "data transfer for sensors", null, 1);
boolean test = dbHelper.checkExist();
Toast.makeText(getApplicationContext(), "testing: "+test, Toast.LENGTH_SHORT).show();
}
}
Extends LoaderManager.LoaderCallbacks in your activity to load the data from the data base.
For more information you can read that:
https://developer.android.com/guide/components/loaders.html
See this:
http://guides.codepath.com/android/local-databases-with-sqliteopenhelper
I would recommend you to use the singleton pattern to avoid leak and to re-allocate the db each time.
It's highly recommended to use startTransaction and endTransaction as described in the link above.
If it still doesn't work, i also recommend to you to use Loaders as #Bruno suggested.
Regardless your question, just a small potential bug fix - In Database class in function updateSensorData you forgot to close the Cursor in the else flow.
I have issue with both FIleObserver and ContentObserver not working in Android Marshmallow. I am using this thing for detecting changes that happening inside a folder. I set run time permissions for marshmallow. But after that also it shows no events. It works perfectly in other versions. Please help me to solve this problem.
First I tried Content Resolver inside Service for detect folder changes in background.
public class TestService extends Service {
#Override
public void onCreate() {
super.onCreate();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
initial();
return START_STICKY;
}
public void initial(){
getContentResolver().registerContentObserver(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
true,
new ContentObserver(new Handler()) {
#Override
public boolean deliverSelfNotifications() {
Log.d("hai", "deliverSelfNotifications");
return super.deliverSelfNotifications();
}
#Override
public void onChange(boolean selfChange) {
super.onChange(selfChange);
}
#Override
public void onChange(boolean selfChange, Uri uri) {
if (uri.toString().matches(MediaStore.Images.Media.EXTERNAL_CONTENT_URI.toString() + "/[0-9]+")) {
Cursor cursor = null;
try {
cursor = getContentResolver().query(uri, new String[] {
MediaStore.Images.Media.DISPLAY_NAME,
MediaStore.Images.Media.DATA
}, null, null, null);
if (cursor != null && cursor.moveToFirst()) {
final String fileName = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DISPLAY_NAME));
final String path = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA));
// TODO: apply filter on the file name to ensure it's screen shot event
Log.d("file", "FILE CHANGE OCCURED " + fileName + " " + path);
}
} finally {
if (cursor != null) {
cursor.close();
}
}
}
super.onChange(selfChange, uri);
}
}
);
}
}
And run time permissions as:
private void getPermission(){
boolean hasPermission = (ContextCompat.checkSelfPermission(this,
Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED);
if (!hasPermission) {
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},
REQUEST_READ_STORAGE);
}
}
And received that permissions result in onRequestPermissionsResult.
This method didn't work for me. So I tried with FileObserver inside that service. That time also it works in all other platforms, but not Marshmallow.
This appears to be a bug in Marshmallow, see here.
You can only try working around it by polling for whatever information you need.
How well this will work for you depends on your use case. I found it usable for tracking download progress: start polling when the download starts, with a one-second interval, and stop when the download finishes.
If you expect very infrequent changes, you can try increasing the interval – at the cost of a potentially higher delay between changes happening and your app picking them up.
I am trying to add content observer for AOSP Browser's history provider i.e., with Uri Browser.BOOKMARKS_URI. If I attach an observer, the onChange(boolean) gets called on my ICS running my Samsung GT-S7562, my JB running Samsung GT-I8262 or HTC Desire X but I don't get any notifications for AOSP Browser provider on my friend's Android 4.3 running Samsung SM-G7102. However for Google Chrome's provider, i.e., residing at content://com.android.chrome.browser/bookmarks, I get notified for changes on all android releases. Also if I query the AOSP Browser database & scan for entries, it only returns those opened in Chrome (I mean it returns Chrome's history in Browser.BOOKMARKS_URI provider).
Below is the sample service I tested for reference which is not actually required (don't mind but I think everything is quite clear above already):
package vpz.hp;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.database.ContentObserver;
import android.net.Uri;
import android.os.Handler;
import android.os.IBinder;
import android.util.Log;
import android.widget.Toast;
public class Watcher extends Service {
private Provider Browser;
private Provider Chrome;
#Override public IBinder onBind(Intent intent) {
return null;
}
#Override public void onDestroy() {
if (this.Browser != null)
this.Browser.Stop();
if (this.Chrome != null)
this.Chrome.Stop();
super.onDestroy();
}
public final int onStartCommand(Intent Intention, int StartId, int Flags) {
this.Browser = new Provider(super.getApplicationContext(), android.provider.Browser.BOOKMARKS_URI);
this.Browser.Start();
if (Search(getApplicationContext(), "com.android.chrome")) {
this.Chrome = new Provider(super.getApplicationContext(), Uri.parse("content://com.android.chrome.browser/bookmarks"));
this.Chrome.Start();
}
return START_STICKY;
}
private static final boolean Search(Context Sender, String Package) {
try {
return Sender.getPackageManager().getPackageInfo(Package, PackageManager.GET_ACTIVITIES) != null;
} catch (NameNotFoundException Error) {
return false;
}
}
private static class Provider extends ContentObserver {
private Context Sender;
private Uri URI;
public Provider(Context Sender, Uri URI) {
super(new Handler());
this.Sender = Sender;
this.URI = URI;
}
#Override public void onChange(boolean Self) {
String Message = this.URI.toString() + " onChange(" + Self + ")";
Toast.makeText(this.Sender, Message, Toast.LENGTH_SHORT).show();
Log.e("VPZ", Message);
}
public final void Start() {
this.Sender.getContentResolver().registerContentObserver(this.URI, true, this);
}
public final void Stop() {
this.Sender.getContentResolver().unregisterContentObserver(this);
}
}
}
I have added below permission(s) already in the manifest:
<uses-permission android:name="com.android.browser.permission.READ_HISTORY_BOOKMARKS" />
Is content observer on AOSP Browser has been deprecated?
I want to block SMS by contentObserver. For that I want to get the phone number of the SMS first. What do I do to get the number? This is the code that I have, just counting the number of SMS.
package com.SMSObserver4;
import android.app.Activity;
import android.database.ContentObserver;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.provider.Contacts;
import android.provider.Contacts.People.Phones;
public class SMSObserver4 extends Activity {
/** Called when the activity is first created. */
private static final String Address = null;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
setReceiver();
}
private SmsSentCounter smsSentObserver = new SmsSentCounter(new Handler());
private int sms_sent_counter = 0;
private void setReceiver() {
this.getContentResolver().registerContentObserver(
Uri.parse("content://sms"), true, smsSentObserver);
}
class SmsSentCounter extends ContentObserver {
public SmsSentCounter(Handler handler) {
super(handler);
// TODO Auto-generated constructor stub
}
#Override
public void onChange(boolean selfChange) {
// TODO Auto-generated method stub
try{
System.out.println ("Calling onChange new");
super.onChange(selfChange);
Cursor sms_sent_cursor = SMSObserver4.this.managedQuery(Uri
.parse("content://sms"), null, "type=?",
new String[] { "2" }, null);
if (sms_sent_cursor != null) {
if (sms_sent_cursor.moveToFirst()) {
sms_sent_counter++;
System.out.println("test" + sms_sent_counter);
}
}
Uri phoneUri = Uri.withAppendedPath(Contacts.Phones.CONTENT_FILTER_URL, Address);
if (phoneUri != null) {
Cursor phoneCursor = getContentResolver().query(phoneUri, new String[] {Phones._ID, Contacts.Phones.PERSON_ID}, null, null, null);
if (phoneCursor.moveToFirst()) {
long person = phoneCursor.getLong(1); // this is the person ID you need
}
}
}catch(Exception e)
{}
}
}
}
I have done a lot of tests and I found this to be impossible. That's because when the messaging application inserts a new record in the SMS content provider, it is already trying to send the SMS. So, even if you detect the SMS in the content://sms/outbox URI, it will be too late to stop it. In fact, there's no way to stop it... it all depends on the SMS application, which you can't interrupt.
Nope, you cant. Observer will comeinto affect after dataset has been modified, by that time sms will already be on the way for delivery. Infact by any means you cant block outgoing sms.