This question asked how to know if Android Talkback is active; that worked until Jelly Bean. Starting from Android 4.1, that steps no longer work, because the mentioned cursor is empty.
Having this said, I want to ask is if there is a way to do the same checking in Jelly Bean.
EDIT
I tried to search for TalkBack code and I found it here.
For checking if TalkBack is active, I am using the following code:
Intent screenReaderIntent = new Intent("android.accessibilityservice.AccessibilityService");
screenReaderIntent.addCategory("android.accessibilityservice.category.FEEDBACK_SPOKEN");
List<ResolveInfo> screenReaders = getPackageManager().queryIntentServices(screenReaderIntent, 0);
Cursor cursor = null;
ContentResolver cr = getContentResolver();
for (ResolveInfo screenReader : screenReaders) {
cursor = cr.query(Uri.parse("content://" + screenReader.serviceInfo.packageName
+ ".providers.StatusProvider"), null, null, null, null);
//here, cursor is not null, but calling cursor.moveToFirst() returns false, which means the cursor is empty
}
Having this said, if the cursor is empty, how do we know if TalkBack is running?
EDIT 2
Following #JoxTraex suggestions, I am now sending a broadcast to query whether or not TalkBack is enabled:
Intent i = new Intent();
i.setAction("com.google.android.marvin.talkback.ACTION_QUERY_TALKBACK_ENABLED_COMMAND");
sendBroadcast(i);
Now how should I receive the response?
I tried adding the following to manifest, but my receiver does not receive any response:
<receiver android:name="my.package.MyBroadcastReceiver"
android:permission="com.google.android.marvin.talkback.PERMISSION_SEND_INTENT_BROADCAST_COMMANDS_TO_TALKBACK">
<intent-filter>
<action android:name="com.google.android.marvin.talkback.ACTION_QUERY_TALKBACK_ENABLED_COMMAND" />
</intent-filter>
This can be achieved much easier by using AccessibilityManager.
AccessibilityManager am = (AccessibilityManager) getSystemService(ACCESSIBILITY_SERVICE);
boolean isAccessibilityEnabled = am.isEnabled();
boolean isExploreByTouchEnabled = am.isTouchExplorationEnabled();
You can check the enabled spoken accessibility servers
fun Context.isScreenReaderEnabled(): Boolean {
val accessibilityManager = getSystemService(Context.ACCESSIBILITY_SERVICE) as AccessibilityManager
if (!accessibilityManager.isEnabled)
return false
val serviceInfoList = accessibilityManager.getEnabledAccessibilityServiceList(AccessibilityServiceInfo.FEEDBACK_SPOKEN)
if (serviceInfoList.isNullOrEmpty())
return false
return true
}
While looking at TalkBackService.java, I found these code segments. These segments should provide some insight on how to query the status.
Code
/**
* {#link Intent} broadcast action for querying the state of TalkBack. </p>
* Note: Sending intent broadcast commands to TalkBack must be performed
* through {#link Context#sendBroadcast(Intent, String)}
*/
#Deprecated
// TODO(caseyburkhardt): Remove when we decide to no longer support intent broadcasts for
// querying the current state of TalkBack.
public static final String ACTION_QUERY_TALKBACK_ENABLED_COMMAND = "com.google.android.marvin.talkback.ACTION_QUERY_TALKBACK_ENABLED_COMMAND";
/**
* Result that TalkBack is enabled.
*
* #see #ACTION_QUERY_TALKBACK_ENABLED_COMMAND
*/
public static final int RESULT_TALKBACK_ENABLED = 0x00000001;
/**
* Result that TalkBack is disabled.
*
* #see #ACTION_QUERY_TALKBACK_ENABLED_COMMAND
*/
public static final int RESULT_TALKBACK_DISABLED = 0x00000002;
/**
* Permission to send {#link Intent} broadcast commands to TalkBack.
*/
public static final String PERMISSION_SEND_INTENT_BROADCAST_COMMANDS_TO_TALKBACK = "com.google.android.marvin.talkback.PERMISSION_SEND_INTENT_BROADCAST_COMMANDS_TO_TALKBACK";
/**
* Tag for logging.
*/
private static final String LOG_TAG = "TalkBackService";
public static final String ACTION_QUERY_TALKBACK_ENABLED_COMMAND = "com.google.android.marvin.talkback.ACTION_QUERY_TALKBACK_ENABLED_COMMAND";
..
} else if (ACTION_QUERY_TALKBACK_ENABLED_COMMAND.equals(intentAction)) {
// TODO(caseyburkhardt): Remove this block when we decide to no
// longer support
// intent broadcasts for determining the state of TalkBack in
// favor of the content
// provider method.
if (sInfrastructureInitialized) {
setResultCode(RESULT_TALKBACK_ENABLED);
} else {
setResultCode(RESULT_TALKBACK_DISABLED);
}
}
...
}
Explanation
You must send an Intent broadcast to the TalkBackService using the action of:
public static final String ACTION_QUERY_TALKBACK_ENABLED_COMMAND = "com.google.android.marvin.talkback.ACTION_QUERY_TALKBACK_ENABLED_COMMAND";
Then examine the contents of the Extras and process it accordingly.
ALSO insure that you have the right permission:
public static final String PERMISSION_SEND_INTENT_BROADCAST_COMMANDS_TO_TALKBACK = "com.google.android.marvin.talkback.PERMISSION_SEND_INTENT_BROADCAST_COMMANDS_TO_TALKBACK";
I'm not sure this is the best way of achieving what is proposed, but I managed to make this work by using the following code:
Intent screenReaderIntent = new Intent("android.accessibilityservice.AccessibilityService");
screenReaderIntent.addCategory("android.accessibilityservice.category.FEEDBACK_SPOKEN");
List<ResolveInfo> screenReaders = getPackageManager().queryIntentServices(screenReaderIntent, 0);
Cursor cursor = null;
int status = 0;
ContentResolver cr = getContentResolver();
List<String> runningServices = new ArrayList<String>();
ActivityManager manager = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
for (RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
runningServices.add(service.service.getPackageName());
}
for (ResolveInfo screenReader : screenReaders) {
cursor = cr.query(Uri.parse("content://" + screenReader.serviceInfo.packageName
+ ".providers.StatusProvider"), null, null, null, null);
if (cursor != null && cursor.moveToFirst()) { //this part works for Android <4.1
status = cursor.getInt(0);
cursor.close();
if (status == 1) {
//screen reader active!
} else {
//screen reader inactive
}
} else { //this part works for Android 4.1+
if (runningServices.contains(screenReader.serviceInfo.packageName)) {
//screen reader active!
} else {
//screen reader inactive
}
}
}
Probably this is not the best way but it is the only one I can think of that works in Jelly Bean and in previous Android versions
Related
According to the Android docs
TV Inputs provided and signed by the device manufacturer (signature
apps) or other apps installed in the system partition will have access
to the entire TV Provider database. This access can be used to
construct apps to browse and search across all available TV channels
and programs.
Assuming I signed as device manufacturer or installed app in system partition, how can I access the TvProvider and thus its channel information?
EDIT:
val tifSupport: Boolean = packageManager.hasSystemFeature(PackageManager.FEATURE_LIVE_TV)
Log.d("XXX", "TIF Support ? $tifSupport")
This line says true. Then I run these lines:
val tvInputManager = applicationContext.getSystemService(TV_INPUT_SERVICE) as TvInputManager?
Log.d("XXX", "TvInputManager $tvInputManager")
val il = tvInputManager?.tvInputList
Log.d("XXX", "TvInputList size --> ${il?.size}")
tvInputManager?.tvInputList?.forEach { info ->
Log.d("XXX", "TvInputListInfo ${info.id} ${info.serviceInfo} # ${info.extras.size()}")
}
First log prints
TvInputManager android.media.tv.TvInputManager#95728c2
so the tvInputManager looks valid. Second shows 0 as the TvInputList size and thus third log (in forEach()) is not printed at all.
You have to start with background for Android. By provider in the doc, they mean ContentProvider, which will share information between process within Android. Now to start with:
If TV Provider supported by our system.
If All the Manifest Permission set to the application
If Application installed under the system apps (and has right SE Policy)
Then you will be able to use ContentProvider to fetch all kind of information you need. To see the full support for TVContent Provider you can refer to this file (ensure it's aligned with your Android OS version) and other AOSP information. For ex.
/**
* Returns the current list of channels your app provides.
*
* #param resolver Application's ContentResolver.
* #return List of channels.
*/
public static List<Channel> getChannels(ContentResolver resolver) {
List<Channel> channels = new ArrayList<>();
// TvProvider returns programs in chronological order by default.
Cursor cursor = null;
try {
cursor = resolver.query(Channels.CONTENT_URI, Channel.PROJECTION, null, null, null);
if (cursor == null || cursor.getCount() == 0) {
return channels;
}
while (cursor.moveToNext()) {
channels.add(Channel.fromCursor(cursor));
}
} catch (Exception e) {
Log.w(TAG, "Unable to get channels", e);
} finally {
if (cursor != null) {
cursor.close();
}
}
return channels;
}
Another ex.
TvInputManager tv = (TvInputManager)getApplicationContext().getSystemService(Context.TV_INPUT_SERVICE);
List<TvInputInfo> list = tv.getTvInputList();
String[] projection = {
TvContract.Channels._ID,
TvContract.Channels.COLUMN_DISPLAY_NUMBER
};
ContentResolver cr = getContentResolver();
Iterator<TvInputInfo> it = list.iterator();
while(it.hasNext()) {
TvInputInfo aux = it.next();
Uri uri = TvContract.buildChannelsUriForInput(aux.getId());
Log.d("TAG", uri.toString());
Log.d("TAG", aux.toString());
Cursor cur = cr.query(uri, projection, null, null ,null);
Log.d("TAG", cur.toString());
if(cur.moveToFirst()) {
Log.d("TAG", "not empty cursors");
}
}
UPDATE:
The basic permission you should have(Also refer to the official documentation):
<uses-permission android:name="com.android.providers.tv.permission.READ_EPG_DATA" />
<uses-permission android:name="com.android.providers.tv.permission.WRITE_EPG_DATA" />
<uses-permission android:name="com.android.providers.tv.permission.ACCESS_ALL_EPG_DATA"/>
I know this question is way old and may be duplicate, but I have a particular query based on it for which I am still trying to find the solution.
As far as I know, ContentObserver on URI content://sms will be triggered when ever there is change in data.
I have tried,
https://katharnavas.wordpress.com/2012/01/18/listening-for-outgoing-sms-or-send-sms-in-android/
Android : Catching Outgoing SMS using ContentObserver or receiver not working
and many more...
As per my understanding this can only be achieved by Content provider and there is no broadcast to handle this. Also content://sms/sent doesn't work at
contentResolver.registerContentObserver(Uri.parse("content://sms/sent"), true, observer);
Am receiving the onChange for each messaging data whether its SMS sent, received, deleted. So as per the documentation of android and other stackoverflow links I found using https://developer.android.com/reference/android/provider/Telephony.TextBasedSmsColumns.html#MESSAGE_TYPE_SENT as comparison method.
So my check goes as,
#Override
public void onChange(boolean selfChange) {
super.onChange(selfChange);
Uri uriSMSURI = Uri.parse("content://sms");
Cursor cur = getContentResolver().query(uriSMSURI, null, null, null, null);
cur.moveToFirst();
String id = cur.getString(cur.getColumnIndex("_id"));
String protocol = cur.getString(cur.getColumnIndex("protocol"));
Log.d(TAG, "protocol = " + protocol);
int type = cur.getInt(cur.getColumnIndex("type"));
Log.d(TAG, "onChange: type = " + type);
// I have even tried with protocol == null check.
if (type == 2 && smsChecker(id)) {
Log.d(TAG, "Sent sms");
}
cur.close();
}
private boolean smsChecker(String smsId) {
boolean flagSMS = true;
if (smsId.equals(lastSmsId)) {
flagSMS = false;
}
else {
lastSmsId = smsId;
}
return flagSMS;
}
So my question here is, If I delete any messages or trigger a outgoing message I receive type 2 on my HTC phone - L OS (sometimes for incoming message too I see type==2).
How can I separate this onChange request, as I am particularly looking for SMS SENT change.
I would like to monitor/filter the websites that an user opens in Android.
I know how to retrieve the last visited URL (in Android default browser) using a ContentObserver on the browser history...
private static class BrowserObserver extends ContentObserver {
private static String lastVisitedURL = "";
private static String lastVisitedWebsite = "";
//Query values:
final String[] projection = new String[] { Browser.BookmarkColumns.URL }; // URLs
final String selection = Browser.BookmarkColumns.BOOKMARK + " = 0"; // history item
final String sortOrder = Browser.BookmarkColumns.DATE; // the date the item was last visited
public BrowserObserver(Handler handler) {
super(handler);
}
#Override
public void onChange(boolean selfChange) {
onChange(selfChange, null);
}
#Override
public void onChange(boolean selfChange, Uri uri) {
super.onChange(selfChange);
//Retrieve all the visited URLs:
final Cursor cursor = getContentResolver().query(Browser.BOOKMARKS_URI, projection, selection, null, sortOrder);
//Retrieve the last URL:
cursor.moveToLast();
final String url = cursor.getString(cursor.getColumnIndex(projection[0]));
//Close the cursor:
cursor.close();
if ( !url.equals(lastVisitedURL) ) { // to avoid information retrieval and/or refreshing...
lastVisitedURL = url;
//Debug:
Log.d(TAG, "URL Visited: " + url + "\n");
}
}
}
To register the ContentObserver I use:
browserObserver = new BrowserObserver(new Handler());
getContentResolver().registerContentObserver(Browser.BOOKMARKS_URI, true, browserObserver);
And to unregister it:
getContentResolver().unregisterContentObserver(browserObserver);
This works. However, in this way, I can analyze the URLs only after the browser has loaded them.
Now, is there a way to retrieve the URLs before the browser actually loads them in Android?
A solution which could help to create a Web Monitor, is to creation your own VPN service, so that you monitor all the device traffic. A good example of this is the project NetGuard.
https://github.com/M66B/NetGuard
Note that in some devices, the system will not pass through the VPN some applications (ex, in Samsung devices, the Samsung Web Browser is not forwarded through the system VPN, checked in S5 with Android 6.0).
Also your application should request the permission to be used as a VPN Service, but once the user gives this permission, it can monitor and filter most of the device network traffic.
I used Download Manager class inside my activity to perform downloads; it works fine and my next task is to show the same progress percentage inside my activity. I am not sure how to do it.
My code so far
public class DownloadSampleBook extends Activity{
private long enqueue;
private DownloadManager dm;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_sample_download);
BroadcastReceiver receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (DownloadManager.ACTION_DOWNLOAD_COMPLETE.equals(action)) {
long downloadId = intent.getLongExtra(
DownloadManager.EXTRA_DOWNLOAD_ID, 0);
Query query = new Query();
query.setFilterById(enqueue);
Cursor c = dm.query(query);
if (c.moveToFirst()) {
int columnIndex = c
.getColumnIndex(DownloadManager.COLUMN_STATUS);
if (DownloadManager.STATUS_SUCCESSFUL == c
.getInt(columnIndex)) {
view.setImageURI(Uri.parse(uriString));
}
}
}
}
};
registerReceiver(receiver, new IntentFilter(
DownloadManager.ACTION_DOWNLOAD_COMPLETE));
}
public void onClick(View view) {
dm = (DownloadManager) getSystemService(DOWNLOAD_SERVICE);
Request request = new Request(
Uri.parse("http://abc.com/a.png"));
enqueue = dm.enqueue(request);
}
public void showDownload(View view) {
Intent i = new Intent();
i.setAction(DownloadManager.ACTION_VIEW_DOWNLOADS);
startActivity(i);
}
}
Is there any method that give the progress download percentage?
If you are looking for a decent way to determine when to query the DownloadManager for progress updates, consider registering a ContentObserver for the uri content://downloads/my_downloads
Example:
DownloadManager manager = (DownloadManager) getSystemService( Context.DOWNLOAD_SERVICE );
manager.enqueue( myRequest );
Uri myDownloads = Uri.parse( "content://downloads/my_downloads" );
getContentResolver().registerContentObserver( myDownloads, true, new DownloadObserver() );
...
public static class DownloadObserver extends ContentObserver {
#Override
public void onChange( boolean selfChange, Uri uri ) {
Log.d( "DownloadObserver", "Download " + uri + " updated" );
}
This yields the following output as each chunk of the long running download is received
D/DownloadObserver(15584): Download content://downloads/my_downloads/437 updated
D/DownloadObserver(15584): Download content://downloads/my_downloads/437 updated
D/DownloadObserver(15584): Download content://downloads/my_downloads/437 updated
D/DownloadObserver(15584): Download content://downloads/my_downloads/437 updated
where '437' is the ID of your download.
Note that this follows the content URI defined in the class android.provider.Downloads which appears to be hidden in the framework and may not work consistently on all devices. (https://android.googlesource.com/platform/frameworks/base/+/refs/heads/master/core/java/android/provider/Downloads.java#89)
You can query the number of bytes downloaded so far, and the total number of bytes that need to be downloaded, using the query method, in much the same way as you have queried the status in your example code. Once you have those values, it's fairly easy to calculate the progress as a percentage.
There doesn't appear to be any way for you to be notified when new data is received, so it would be up to you to poll the download manager at some regular interval to determine the current status of any download that you want to monitor.
Query query = new Query();
query.setfilterById(downloadId);
Cursor c = dm.query(query);
if (c.moveToFirst()) {
int sizeIndex = c.getColumnIndex(DownloadManager.COLUMN_TOTAL_SIZE_BYTES);
int downloadedIndex = c.getColumnIndex(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR);
long size = c.getInt(sizeIndex);
long downloaded = c.getInt(downloadedIndex);
double progress = 0.0;
if (size != -1) progress = downloaded*100.0/size;
// At this point you have the progress as a percentage.
}
Note that the total size will initially be -1 and will only be filled in once the download starts. So in the sample code above I've checked for -1 and set the progress to 0 if the size is not yet set.
However, you may find in some cases that the total size is never returned (for example, in an HTTP chunked transfer, there will be no Content-Length header from which the size can be determined). If you need to support that kind of server, you should probably provide some kind of indication to the user that the download is progressing and not just a progress bar that is stuck at zero.
I had a requirement of tracking download of multiple files. After a lot of thinking and experimenting, I came up with the following code:
private void startDownloadThread(final List<DownloadFile> list) {
// Initializing the broadcast receiver ...
mBroadCastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
mFinishedFilesFromNotif.add(intent.getExtras()
.getLong(DownloadManager.EXTRA_DOWNLOAD_ID));
}
};
IntentFilter intentFilter = new IntentFilter(
"android.intent.action.DOWNLOAD_COMPLETE");
DownloadProgressUIFragment.this.getActivity().registerReceiver(mBroadCastReceiver,
intentFilter);
// initializing the download manager instance ....
mDownloadManager = (DownloadManager) getActivity()
.getSystemService(Context.DOWNLOAD_SERVICE);
// adding files to the download manager list ...
for(DownloadFile f: list) {
mDownloadIds.add(FileUtils.addFileForDownloadInBkg(getApplicationContext(),
f.getUrl(),
f.getPath()));
}
// starting the thread to track the progress of the download ..
mProgressThread = new Thread(new Runnable() {
#Override
public void run() {
// Preparing the query for the download manager ...
DownloadManager.Query q = new DownloadManager.Query();
long[] ids = new long[mDownloadIds.size()];
final List<Long> idsArrList= new ArrayList<>();
int i = 0;
for (Long id: mDownloadIds) {
ids[i++] = id;
idsArrList.add(id);
}
q.setFilterById(ids);
// getting the total size of the data ...
Cursor c;
while(true) {
// check if the downloads are already completed ...
// Here I have created a set of download ids from download manager to keep
// track of all the files that are dowloaded, which I populate by creating
//
if(mFinishedFilesFromNotif.containsAll(idsArrList)) {
isDownloadSuccess = true;
// TODO - Take appropriate action. Download is finished successfully
return;
}
// start iterating and noting progress ..
c = mDownloadManager.query(q);
if(c != null) {
int filesDownloaded = 0;
float fileFracs = 0f; // this stores the fraction of all the files in
// download
final int columnTotalSize = c.getColumnIndex
(DownloadManager.COLUMN_TOTAL_SIZE_BYTES);
final int columnStatus = c.getColumnIndex(DownloadManager.COLUMN_STATUS);
//final int columnId = c.getColumnIndex(DownloadManager.COLUMN_ID);
final int columnDwnldSoFar =
c.getColumnIndex(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR);
while (c.moveToNext()) {
// checking the progress ..
if(c.getInt(columnStatus) == DownloadManager.STATUS_SUCCESSFUL) {
filesDownloaded++;
}
// If the file is partially downloaded, take its fraction ..
else if(c.getInt(columnTotalSize) > 0) {
fileFracs += ((c.getInt(columnDwnldSoFar) * 1.0f) /
c.getInt(columnTotalSize));
} else if(c.getInt(columnStatus) == DownloadManager.STATUS_FAILED) {
// TODO - Take appropriate action. Error in downloading one of the
// files.
return;
}
}
c.close();
// calculate the progress to show ...
float progress = (filesDownloaded + fileFracs)/ids.length;
// setting the progress text and bar...
final int percentage = Math.round(progress * 100.0f);
final String txt = "Loading ... " + percentage + "%";
// Show the progress appropriately ...
}
}
}
});
mProgressThread.start();
}
And the function to enqueue to files are:
public static long addFileForDownloadInBkg(Context context, String url, String savePath) {
Uri uri = Uri.parse(url);
DownloadManager.Request request = new DownloadManager.Request(uri);
request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_HIDDEN);
request.setDestinationUri(Uri.fromFile(new File(savePath)));
final DownloadManager m = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE);
return m.enqueue(request);
}
Basically, I receive a notification individually for each of the files whose download has been finished and then add them to a set which is basically the set which helps me decide if all the downloads have been finished or not. I track the the progress based on the number of files and the fraction of each being complete. I hope this helps.
I was looking quite a bit on the forums for determining how many SMS messages I have that were not read. The code below seems to work good for received messages, but once I actually read the message the onChange of the ContentObserver is not being called.
So, on incoming SMS message the onChange is getting called and I get the correct number, but after reading the message it is not being called. The device is Samsung Note running Android 2.3.6 not rooted. Any help will be appreciated.
public class UnreadSMSContentObserver extends ContentObserver {
private static final String myTAG="PhoneInfoSMS";
private static final Uri SMS_INBOX = Uri.parse("content://sms/inbox");
private ContentResolver mContentResolver;
private Handler mHandler;
public int unreadSMS;
private static final String TAG = "PhoneInfoSMS";
public UnreadSMSContentObserver(ContentResolver cr, Handler h) {
super(null);
mContentResolver = cr;
mHandler = h;
}
public int getUnreadSMS() {
if (mContentResolver != null) {
try {
Cursor c = mContentResolver.query(SMS_INBOX, null, "read = 0", null, null);
if (c != null) {
unreadSMS = c.getCount();
c.deactivate();
Log.d(TAG, unreadSMS + " unread SMS messages");
}
}
catch (Exception ex) {
Log.e("ERROR: " + ex.toString(), "");
}
}
return unreadSMS;
}
#Override
public void onChange(boolean selfChange) {
Log.d(myTAG, "onChange");
if (mContentResolver != null) {
getUnreadSMS();
mHandler.obtainMessage(PhoneInfoServer.CONTENTO_INFOCHANGED, PhoneInfoServer.CONTENTO_US, unreadSMS).sendToTarget();
Log.d(myTAG, "done");
}
}
}
In the manifest file I have the following permissions:
"android.permission.READ_CONTACTS"
"android.permission.READ_SMS"
"android.permission.GET_ACCOUNTS"
"android.permission.BATTERY_STATS"
"android.permission.BLUETOOTH"
"android.permission.BLUETOOTH_ADMIN"
"android.permission.BROADCAST_SMS"
"android.permission.RECEIVE_SMS"
"android.permission.BROADCAST_SMS"
"android.permission.RECEIVE_MMS"
The way I set it up on the calling service is:
in the onCreate of the service I do:
mContentResolver = this.getContentResolver();
mUnreadSMSContentObserver = new UnreadSMSContentObserver(mContentResolver, mContentObserversHandler);
in the onStartCommand of the service I do:
mContentResolver.registerContentObserver(Uri.parse("content://sms/"), true, mUnreadSMSContentObserver);
mContentResolver.registerContentObserver(Uri.parse("content://sms/inbox/"), true, mUnreadSMSContentObserver);
I tried only the content://sms/ and only content://sms/inbox/ and both... did not solve the problem.
P.S. Similar method for the missed calls works perfect!
The application+service is sending over Bluetooth the battery data, missed calls and unread SMS messages to an Arduino based device that displays it on an LED screen. Why? Two reasons: first, this is my first Android program made for fun. The second is I am not carrying the phone with me at home all the time, and it is typically in my home office. If I did not hear it ringing I will still be able to see the LED display telling me I had calls or SMS when passing by.
this solution has worked for me :
context.getContentResolver().
registerContentObserver(Uri.parse("content://mms-sms/"), true, smsObserver);