How to update RecyclerView from BroadcastReceiver? - java

In AndroidManifest.xml I have a BroadcastReceiver:
<receiver android:name=".SmsMonitor">
<intent-filter android:priority="-100">
<action android:name="android.provider.Telephony.SMS_RECEIVED" />
</intent-filter>
</receiver>
In my MainActivity, I have RecyclerView with a list of received SMS.
My question is - How I can update the RecyclerView from my BroadcastReceiver "SmsMonitor" in case new SMS received when the application is running?
UPD: I mean I need solution for both states - for running application AND for state when application is not running, in one receiver. Because I have to take SMS all time while phone is working. And in case the application is running I want to update RecyclerView.

I tried to do it through the Service, but I did not succeed.
But I found simple solution:
I still have BroadcastReceiver SmsMonitor, registered in AndroidManifest.xml
And in the point where I create instance of my RecyclerAdapter:
mainAdapter = new MainAdapter(this);
After this I register another BroadcastReceviver:
BroadcastReceiver br = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
setInitialData();
mainAdapter.notifyDataSetChanged();
}
};
IntentFilter filter = new IntentFilter("android.provider.Telephony.SMS_RECEIVED");
this.registerReceiver(br, filter);
And in setInitialData() I recreate all list of data for RecyclerView.
And now I have two independently working BroadcastReceiver. The first working the BroadcastReceiver from the AndroidManifest.xml, and then working the BroadcastReceiver registered in MainActivity.

You need to have the BrodcastReceiver in your MainActivity or Fragment as well which hosts the RecyclerView. So that when the new SMS is received, you can call the notifyDataSetChanged on the adapter of your RecyclerView to update it.
Declare a BroadcastReceiver in your Activity like the following. This can be an inner class of your MainActivity class.
class SMSBroadcastReceiver extends BroadcastReceiver {
private static final String SMS_RECEIVED = "android.provider.Telephony.SMS_RECEIVED";
private static final String TAG = "SMSBroadcastReceiver";
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction() == SMS_RECEIVED) {
Bundle bundle = intent.getExtras();
if (bundle != null) {
// Update your RecyclerView here
// by calling notifyDataSetChanged on the adapter
}
}
}
}
Now create an instance of this BroadcastReceiver in the onCreate function of your MainActivity and register the receiver.
You need to ask for SMS permission first in your Activity like the following.
if (ContextCompat.checkSelfPermission(mActivity, Manifest.permission.RECEIVE_SMS) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(mActivity, new String[]{Manifest.permission.RECEIVE_SMS}, 0);
} else {
// register sms receiver
IntentFilter filter = new IntentFilter(Telephony.Sms.Intents.SMS_RECEIVED_ACTION);
registerReceiver(smsReceiver, filter);
}
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions, #NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (ContextCompat.checkSelfPermission(mActivity, Manifest.permission.RECEIVE_SMS) != PackageManager.PERMISSION_GRANTED) {
} else {
// register sms receiver
IntentFilter filter = new IntentFilter(Telephony.Sms.Intents.SMS_RECEIVED_ACTION);
registerReceiver(smsReceiver, filter);
}
}
Do not forget to un-register the receiver in the onDestroy function of your MainActivity.
Hope that helps!
Update
Based on the comment below this answer, you have two cases.
Case 1. The app is running.
Case 2. The app is not running.
For case 1: The local BroadcastReceiver like I shown above, is good enough to update the RecyclerView instantly when a new SMS arrives. As you are handling the BroadcastReceiver from the MainActivity this should not be a problem, as you have the reference to your RecyclerView.
Now for Case 2: If you are able to detect any new SMS arrival, you can save the new SMS received in your local database. You need to have an SQLite database for your application which will store all the SMS and the RecyclerView in your application should populate the data from the database table where the SMS are stored. I hope you get the idea - just store the SMS in your local database associated with your application and when you run the application and launch the MainActivity, read the SMS from your local database and show them in your RecyclerView.

Related

Android Service to check whether the user screen on or off

Is there any way to create a service that runs forever on a background for Android user to check whether their screen on or off, etc?
I'm about to create an analytics, so I need to know when the user turn on or turn off their screen.
Thanks, I will appreciate all the input
You may use Android broadcast receiver to detect screen on and off.
Here is a good example of it
https://thinkandroid.wordpress.com/2010/01/24/handling-screen-off-and-screen-on-intents/
you may also follow this thread
https://stackoverflow.com/a/9478013/2784838
You need to create broadcast receiver and manage screen on or off status.
Declare receiver in manifest:
<receiver android:name=".DeviceWakeUpReceiver" />
public class DeviceWakeUpReceiver extends BroadcastReceiver {
private static final String TAG = "DeviceWakeUpService";
#Override
public void onReceive(Context context, Intent intent) {
Log.d(TAG, "onReceive() called");
if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
//End service when user phone screen off
} else if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) {
//Start service when user phone screen on
}
}
}
You cannot use a BroadcastReceiver for receiving screen off/on events.
Write a intent service which is started via boot complete listener and register for Intent.ACTION_SCREEN_OFF and Intent.ACTION_SCREEN_ON.
IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_ON);
IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_OFF);
registerReceiver(new ScreenOffOnReceiver(), filter);
class ScreenOffOnReiver extends BroadcastReceiver {
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
// Screen OFF
else if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) {
// Screen ON
}
}
}

How to get action from key of Headset in android [duplicate]

I'm trying to add a simple broadcast receiver to my audio application, so that I can mute everything when the user clicks their ACTION_MEDIA_BUTTON on their headset. I've read that you can either register it in the manifest, or dynamically in the code. I have gone down the path of registering it in the code, as I need to call methods within my main activity class to react to the media button press. For some reason however, my BroadcastReceiver just will not register, and I can't find anything that explains why (grey hairs increasing).
The following is what I have in MainActivity.java:
public class MainActivity extends Activity {
public IntentFilter intentFilter = new IntentFilter(Intent.ACTION_MEDIA_BUTTON);
public BroadcastReceiver MediaButtonIntentReceiver =
new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
String intentAction = intent.getAction();
if (Intent.ACTION_MEDIA_BUTTON.equals(intentAction)) {
KeyEvent event = (KeyEvent) intent
.getParcelableExtra(Intent.EXTRA_KEY_EVENT);
int action = event.getAction();
if (action == KeyEvent.ACTION_DOWN) {
Log.e("INFO", "Media Button Pressed");
MuteAll();
}
}
}
};
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Register media button event receiver
intentFilter.addAction("android.intent.action.ACTION_MEDIA_BUTTON");
intentFilter.setPriority(10000);
this.registerReceiver(MediaButtonIntentReceiver, intentFilter);
}
#Override
protected void onDestroy() {
super.onDestroy();
// Unregister media button event receiver
unregisterReceiver(MediaButtonIntentReceiver);
}
};
I am certain that the BroadcastReceiver doesn't register, as wrapping the register as below gives me a toast confirming it is null:
if (registerReceiver(MediaButtonIntentReceiver, intentFilter) == null)
{
Toast.makeText(this, "Could not register receiver", Toast.LENGTH_LONG).show();
} else {
Toast.makeText(this, "Receiver registered", Toast.LENGTH_LONG).show();
}
EDIT:
I've also tried the following based on suggestions so far:
Reading through - http://developer.android.com/training/managing-audio/volume-playback.html
I tried registering my receiver within the manifest like so...
<receiver android:name="com.mydomain.myapp.MainActivity$MediaButtonIntentReceiver">
<intent-filter>
<action android:name="android.intent.action.MEDIA_BUTTON" />
</intent-filter>
</receiver>
And then added the following example code:
public AudioManager am = mContext.getSystemService(Context.AUDIO_SERVICE);
...
// Start listening for button presses
am.registerMediaButtonEventReceiver(RemoteControlReceiver);
Eclipse complained that mContext didn't resolve to anything, so I added the following:
private Context mContext;
Then it complained about the "mContext.getSystemService(Context.AUDIO_SERVICE)" portion, saying "Type mismatch: cannot convert from Object to AudioManager"
So I added a cast to AudioManager:
public AudioManager am = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
And then added the suggested receiver registration code:
am.registerMediaButtonEventReceiver(MediaButtonIntentReceiver);
To which it complained about "registerMediaButtonEventReceiver" saying "The method registerMediaButtonEventReceiver(ComponentName) in the type AudioManager is not applicable for the arguments (BroadcastReceiver)"
Clearly I'm doing something wrong here. I've entered their example code as shown, yet it doesn't even compile.
--- END EDIT -----------------------------
Hoping someone out there can please help me. Please let me know if I need to supply anything further.
A Receiver for the ACTION_MEDIA_BUTTON action should be registered with AudioManager's registerMediaButtonEventReceiver() method, instead of the regular registerReceiver() method in the Activity. Unlike normal dynamic Receiver registration, however, this method takes the class as the parameter, instead of an instance of the class. The easiest way to this is to create a separate class file for it:
public class MediaButtonIntentReceiver extends BroadcastReceiver
{
#Override
public void onReceive(Context context, Intent intent)
{
...
}
}
And we would need this Receiver listed in the manifest, as well:
<receiver android:name=".MediaButtonIntentReceiver" >
<intent-filter>
<action android:name="android.intent.action.MEDIA_BUTTON" />
</intent-filter>
</receiver>
Now, the example in the link we've referred to is wrong, as the registerMediaButtonEventReceiver() method is expecting a ComponentName object, not just the name of the Receiver class itself. We need to change the example as follows:
AudioManager am = (AudioManager) getSystemService(AUDIO_SERVICE);
am.registerMediaButtonEventReceiver(
new ComponentName(this, MediaButtonIntentReceiver.class));
And, as we've established, you don't need the mContext field, as you are in anActivity Context, and can just use getSystemService() without qualification. You can also do away with the IntentFilter object, as the listing in the manifest takes care of that already.

Update textview of MainActivity from class that extends Service

I'm trying to create an android app that communicate with Bluetooth low energy module. I am able to connect to module, read data and so on. But the problem is i do not know how to update textview from class that extends Service (the one in which whole connection to BLE is going on). I know there is like BILLION or even more posts like these, but believe me i tried.
Here is MainActivity: http://pastebin.com/6yaP0dYM
and here is a class that extends Service: http://pastebin.com/cYuAUina
If someone could provide me some tips to solve my issue that would be more than great!
Create Broadcast Receiver and broadcast that in Service.
If your Activity is ope, register receiver and in onReceive() update the UI.
The receiver should be in the Activity...
Below is the working code
https://stackoverflow.com/a/14695943/1403112
You can get values through broadcast receiver......as follows, First create your own IntentFilter as,
Intent intentFilter=new IntentFilter();
intentFilter.addAction("YOUR_INTENT_FILTER");
Then create inner class BroadcastReceiver as,
private BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
/** Receives the broadcast that has been fired */
#Override
public void onReceive(Context context, Intent intent) {
if(intent.getAction()=="YOUR_INTENT_FILTER"){
//HERE YOU WILL GET VALUES FROM BROADCAST THROUGH INTENT EDIT YOUR TEXTVIEW///////////
String receivedValue=intent.getStringExtra("KEY");
}
}
};
Now Register your Broadcast receiver in onResume() as,
registerReceiver(broadcastReceiver, intentFilter);
And finally Unregister BroadcastReceiver in onDestroy() as,
unregisterReceiver(broadcastReceiver);
Now the most important part...You need to fire the broadcast from wherever you need to send values..... so do as,
Intent i=new Intent();
i.setAction("YOUR_INTENT_FILTER");
i.putExtra("KEY", "YOUR_VALUE");
sendBroadcast(i);
....cheers :)

Checking for variable change using infinite loop

I need to check when the value of a variable is changed in my activity by a service so that I can then update the UI with the new values. I am currently using an infinite loop to check for this within a new thread, will this be using a lot of resources/is there a more efficient way to do this?
You should use a broadcast from the Service to send the changes in the variable. First of all create a broadcast in your main Activity.
BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
Log.d("Broadcast","broadcast received");
String value = intent.getStringExtra("Variable"); // this will get the value
// send from Service
}
};
Next set a intent filter to which the broadcast listens. This you can do in onCreate() of your activity.
IntentFilter intentFilter = new IntentFilter("FROM_SERVICE");
registerReceiver(broadcastReceiver,intentFilter);
then in your service you must send a broadcast. If you want to send some data from Service to Activity then you must replace the above code with below
Intent intent = new Intent("FROM_SERVICE");
intent.putExtra("Variable", "change");
sendBroadcast(intent);

LocationPoller and multiple broadcast receiver

I am using cwac-Location Poller (from here) to constantly poll user location and display location based notifications. This all is working fine but now I am trying to attach another BroadcastReceiver so that if my application is in foreground, instead of displaying notification animate the google map to current user location. But for some reason I can't get it working.
onCreate() method of MapActivity I have following code to start poller:
#Override
public void onCreate(Bundle savedInstanceState) {
.....
alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
Intent i = new Intent(this, LocationPoller.class);
Bundle bundle = new Bundle();
LocationPollerParameter parameter = new LocationPollerParameter(bundle);
parameter.setIntentToBroadcastOnCompletion(new Intent(this, LocationReceiver.class));
parameter.setProviders(new String[] {LocationManager.GPS_PROVIDER, LocationManager.NETWORK_PROVIDER});
parameter.setTimeout(60000);
i.putExtras(bundle);
pendingIntent = PendingIntent.getBroadcast(this, 0, i, 0);
alarmManager.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
SystemClock.elapsedRealtime(), PERIOD, pendingIntent);
}
in onResume() method I am registering another receiver using registerReceiver() method:
#Override
protected void onResume() {
super.onResume();
IntentFilter intentFilter = new IntentFilter(com.commonsware.cwac.locpoll.LocationPollerParameter.INTENT_TO_BROADCAST_ON_COMPLETION_KEY);
intentFilter.setPriority(1);
registerReceiver(locationReceiver, intentFilter);
}
Where locationReceiver looks like:
private BroadcastReceiver locationReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
Log.d(TAG, "mapActivity called");
abortBroadcast();
}
};
And in order to send ordered broadcast to multiple receiver I have modified LocationPollerService to use sendOrderedBroadcast instead of sendBroadcast
public void onLocationChanged(Location location) {
handler.removeCallbacks(onTimeout);
Intent toBroadcast = createIntentToBroadcastOnCompletion();
toBroadcast.putExtra(LocationPollerResult.LOCATION_KEY, location);
sendOrderedBroadcast(toBroadcast, null);
quit();
}
Now the problem is my dynamically registered receiver never get called but the one mentioned in AndroidManifest.xml does:
<receiver android:name=".receiver.LocationReceiver" />
<receiver android:name="com.commonsware.cwac.locpoll.LocationPoller" />
<service android:name="com.commonsware.cwac.locpoll.LocationPollerService" />
Your problem is in a disconnect between the IntentFilter you create in Java and your createIntentToBroadcastOnCompletion() implementation, which you did not include in your question. Your IntentFilter is expecting a broadcast with a certain action string -- the Intent you are creating in createIntentToBroadcastOnCompletion() apparently does not include this action string.
BTW, with respect to "And in order to send broadcast to multiple receiver", sendBroadcast() is perfectly capable of sending broadcasts to multiple receivers.

Categories