How to get FCM onMessageReceived event in activity without PendingIntent - android

I want to implement pub/sub in my app, for that server send notification in specific event, I will do some modification on data which is display in my activity

onMessageReceived() doesn't need PendingIntent to be call. It will always call if you have correct setup. This link provide the data type you should sent to FCM server
With FCM, you can send two types of messages to clients:
Notification messages, sometimes thought of as "display messages."
Data messages, which are handled by the client app.
If you would like to always trigger use just data message so it will always trigger the onMessageReceived().If you try to use data-message and notification-message together the onMessageReceived() will not get trigger when your app is in background.
Just do anything you would like to do such as save to database, sharedPeference etc inside your onMessageReceived()
So how you sent to the activity?
Use Broadcast Receiver here is how you sent a broadcast receiver in your case you will like to put it inside your onMessageReceived() so anytime you received a new notification this code will help you sent the data to the specific activity.
Intent intent = new Intent("Use anything you like");
intent.putExtra("data","The data you receive");
sendBroadcast(intent);
In your activity register it in your onStart()
registerReceiver(broadCastReceiver,new IntentFilter("must match the intent filter parameter"));
Here is how you handle your data
class broadCastReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Log.d("Your data",intent.getData());
}
}
Note: your intent filter parameter must match the intent parameter you set in your onMessageReceived()
If your app never received data from the FCM this answer will be useless since your question still unclear this is the best I can do for you.

Related

Android - How to be the first to receive WAP PUSH (MMS)

I would like to intercept incomming MMS to enable mobile data. For that, I need to intercept them before any other app.
I have setup my intent filter to receive WAP_PUSH_RECEIVED_ACTION broadcasts with the highest possible priority.
But, in the Android documentation (https://developer.android.com/reference/android/provider/Telephony.Sms.Intents.html), there are the two following broadcasts:
WAP_PUSH_DELIVER_ACTION (Only sent to default sms app)
WAP_PUSH_RECEIVED_ACTION (Sent to all apps)
Please, can you tell me which of these broadcasts is sent first (WAP_PUSH_DELIVER_ACTION or WAP_PUSH_RECEIVED_ACTION) and where did you find this information ?
From where are them send in Android source code ?
Does listening for WAP_PUSH_RECEIVED_ACTION with the highest possible priority let me be the first to receive WAP PUSH broadcasts ?
Thanks
This topic seems to be not so popular!
I tried to answer the question myself and I found something interesting.
Analysis
SMS and MMS reception are mainly managed in the file InboundSmsHandler.java.
This file starts with a comment block that explains the SMS/MMS receiving state machine.
Here is an extract of this comment with explanations:
The state machine starts in InboundSmsHandler.IdleState state.
When the SMSDispatcher receives a new SMS from the radio, it calls dispatchNormalMessage(com.android.internal.telephony.SmsMessageBase), which transitions to InboundSmsHandler.DeliveringState state.
From the InboundSmsHandler.DeliveringState state, processMessagePart(InboundSmsTracker tracker) is called. Within this method, if the destination port number of the SMS is SmsHeader.PORT_WAP_PUSH (in other words if the SMS is an MMS), the WapPushOverSms.dispatchWapPdu(byte[] pdu, BroadcastReceiver receiver, InboundSmsHandler handler) method is called.
Inside the dispatchWapPdu method, they call InboundSmsHandler.dispatchIntent(Intent intent, String permission, int appOp, BroadcastReceiver resultReceiver, UserHandle user). They check if there is a default MMS app and if it's the case, configure the intent to only be delivered to this app.
Code:
// Direct the intent to only the default MMS app. If we can't find a default MMS app
// then sent it to all broadcast receivers.
ComponentName componentName = SmsApplication.getDefaultMmsApplication(mContext, true);
if (componentName != null) {
// Deliver MMS message only to this receiver
intent.setComponent(componentName);
if (DBG) Rlog.v(TAG, "Delivering MMS to: " + componentName.getPackageName() +
" " + componentName.getClassName());
}
handler.dispatchIntent(intent, permission, appOp, receiver, UserHandle.OWNER);
Inside the dispatchIntent we have what we are looking for, the call to Context.sendOrderedBroadcastAsUser(...). So, it is this method that sends the WAP_PUSH_DELIVER_ACTION broadcast as an ordered broadcast.
This broadcast is also handled (default app and SmsBroadcastReceiver) by the SmsBroadcastReceiver.onReceive(Context context, Intent intent) handler located in InboundSmsHandler.java. Inside this handler, the WAP_PUSH_DELIVER_ACTION case is processed. The intent is changed to WAP_PUSH_RECEIVED_ACTION and broadcasted again through the InboundSmsHandler.dispatchIntent(Intent intent, String permission, int appOp, BroadcastReceiver resultReceiver, UserHandle user) method. This time, not only the default app is concerned, but all interested apps.
Code:
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action.equals(Intents.SMS_FILTER_ACTION)) {
// ...
} else if (action.equals(Intents.SMS_DELIVER_ACTION)) {
// ...
} else if (action.equals(Intents.WAP_PUSH_DELIVER_ACTION)) {
// Now dispatch the notification only intent
intent.setAction(Intents.WAP_PUSH_RECEIVED_ACTION);
intent.setComponent(null);
// Only the primary user will receive notification of incoming mms.
// That app will do the actual downloading of the mms.
dispatchIntent(intent, android.Manifest.permission.RECEIVE_SMS,
AppOpsManager.OP_RECEIVE_SMS, this, UserHandle.OWNER);
} else {
// ...
}
}
Conclusion (Quick answer to the original question)
When an MMS is received, WAP_PUSH_DELIVER_ACTION is broadcasted first to the default app followed by the WAP_PUSH_RECEIVED_ACTION.
Both broadcasts are ordered broadcasts that means that priorities can be used.
Well, it's a bad news for me because it also means that I cannot be the first to be notified for an incoming MMS and turn on the modile data before the MMS app is notified.
Ahh Google, with Lollipop, you make the things harder for us : Android Issue 78084 - setMobileDataEnabled removed
So, I have to look for another way in order to do that.

Refreshing activity on receiving gcm push notification

Update: GCM is deprecated, use FCM
How to refresh activity on receiving gcm push notification if my app is open. I have an activity which contains listview filled with data from the server. I want to refresh my activity (here adding one more item to listview) , if I receive gcm push notification(which also contains some data).
One alternative is to add timer that periodically do server requests and update the list adapter data but I don't want these because it will take much resources.
Do I need to add broadcast receiver which will trigger on receiving gcm push which further request for newer server data and update my activity UI?
Dear commentors, please read the question carefully, I only need to refresh the list (if app is open and that particular activity is open) else no need for same.
Took me a few hours to figure it out. Posting here in case anyone anyone else has the same problem.
The idea is that you have to register your activity as a broadcast receiver. The easiest way to do this is like so:
//register your activity onResume()
#Override
public void onResume() {
super.onResume();
context.registerReceiver(mMessageReceiver, new IntentFilter("unique_name"));
}
//Must unregister onPause()
#Override
protected void onPause() {
super.onPause();
context.unregisterReceiver(mMessageReceiver);
}
//This is the handler that will manager to process the broadcast intent
private BroadcastReceiver mMessageReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
// Extract data included in the Intent
String message = intent.getStringExtra("message");
//do other stuff here
}
};
The above code goes in the activity that you want to 'listen' for events.
Now, how do we send data to this 'listener'? Go to your push notification handler(or from where you want to update your activity) and when you receive a notification call this function:
// This function will create an intent. This intent must take as parameter the "unique_name" that you registered your activity with
static void updateMyActivity(Context context, String message) {
Intent intent = new Intent("unique_name");
//put whatever data you want to send, if any
intent.putExtra("message", message);
//send broadcast
context.sendBroadcast(intent);
}
When you call the above function, your activity should receive it.
Note: Your activity must be running/open to receive the broadcast intent
Note2: I switched to a library called 'otto'. It does actually the same thing but easier, 'broadcasts events' thoughout the app. Here's a link http://square.github.io/otto/
I'm assuming your GCMBroadcastReceiver is in it's own .java file?
As far as refreshing an activity, I would also like to know the answer to that question.
But for knowing if a particular activity is active or not, meaning on screen just add a boolean (call it something like "active") and set it to true in your activity's onResume() event, and to false in the onPause() event:
protected void onResume()
{
super.onResume();
active = true;;
}
protected void onPause()
{
super.onPause();
active = false;
}
Your active variable would be a boolean which is global or static. This way you know if a particular activity is in "front".
Hope that helps a bit.
The accept answer is indeed correct for the "Refreshing activity on receiving gcm push notification" (I've upvoted it too). But if you only want to update a ListView that's being displayed you don't need a broadcast receiver.
Your GCM listener service can update the database using a ContentProvider rather than inserting a direct sql query.
Then you can rely on the notifyChange method on the ContentResolver to do the trick.
Notify registered observers that a row was updated. To register, call
registerContentObserver(). By default, CursorAdapter objects will get
this notification. If syncToNetwork is true, this will attempt to
schedule a local sync using the sync adapter that's registered for the
authority of the provided uri. No account will be passed to the sync
adapter, so all matching accounts will be synchronized.
If your app is already running then try to override the onNewIntent method
Seems there is an easier way. In the OnMessageReceived method of the GCM Listener, you can just do the update from there instead of sending the notification. You can use the same code you would have used if processing the notification. If you're doing StartActivity from the listener, you have to use the ActivityFlags.NewTask flag.
To sum it up in single sentence:
If you want to refresh activity, broadcast your custom event when notification arrives and register your activity as broadcast receiver of that event
Intent notificationIntent = new Intent(context, MainActivity.class);
notificationIntent.setAction(Long.toString(System.currentTimeMillis()));
PendingIntent.getActivity(context, 0, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT);

While my app is running, how can I update the current activity with the contents a GCM notification, without clicking on the notification?

Is this possible? Currently when I receive a notification OnMessage(Context context, Intent intent) fires, but I'm not able to reference any of my Activities in this context. Is there any way for me to do this? Or do I need the user to click the notification to update the activity and view?
In the OnMessage handler, just execute:
var i = new Intent(this, typeof(MyActivity));
i.SetFlags(ActivityFlags.NewTask);
context.StartActivity(i);
I had a similar problem. You can send a LocalBroadcast inside onMessage. See LocalBroadcast Manager.:
LocalBroadcast Manager is a helper to register for and send broadcasts of Intents to local objects within your process. The data you are broadcasting won't leave your app, so don't need to worry about leaking private data.`
You can send the LocalBroadcast from within the omMessage. Then inside you Activity you can listen to the broadcast which can be with an Intent message. Whenever you receive that local broadcast, you may do the desired action.
See how to use LocalBroadcastManager? on how to implement it. Hope it helps you.

How do I check the Currently Visible Activity and fire one of its Methods from Anywhere?

My app has a chat screen to send and receive messages. Whenever a message is received a push notification comes in and shows the latest received message. This all works fine.
But when I get my push notification I would like the chat screen to refresh itself. I guess this would require knowing if the chat screen is currently visible or not. How can I do this from the onReceive() method of my BroadcastReceiver?
Here's a little pseudo code (in my BroadcastReceiver subclass):
public void onReceive(Context context, Intent intent)
{
if(currentlyVisibleActivity.getClass() == chatScreenActivity.class())
{
((chatScreenActivity)currentlyVisibleActivity).getMessages();
}
}
I would like to know how to get the currentlyVisibleActvity and make it call getMessages() if it's a chatScreenActivity.
I assume you are planning the following setup?
C2DM -> YourBroadcastReceiver -> somehow call #getMessages()
How about having the following components:
A BroadcastReceiver <for receiving C2DM push notifications>
An IntentService <for executing #getMessages()>
A ContentProvider <for storing the results of #getMessages()>
An Activity <for displaying the contents of ContentProvider>
Basically, C2DM triggers your receiver which calls #startService, triggering
your IntentService.
Your IntentService calls #getMessages() and stores the messages in your
ContentProvider.
Whenever a change is performed on the data in the ContentProvider you will
trigger ContentResolver#notifyChange().
If your Activity is showing and uses, for instance, a CursorAdapter to read
from the ContentProvider it will automatically refresh.
Sending a chat message would also store a row in the ContentProvider in this scenario - automatically updating the UI just as a received message.

Android from receiver to activity

I'm just getting into Android development, and I have a question about communicating between a receiver class and an activity class. I'm very new to JAVA and Android so I hope I don't sound too stupid. I'm developing an application where I intercept an SMS message and then based on various elements of that SMS I might delete it once it's been saved to the inbox. I have a receiver class that intercepts the txt message, and I am also able to delete messages from my inbox with code in the activity class using a button at the moment. The problem I have is communicating between the receiver class and the activity class where the code to delete a message resides. I tried putting that code directly into the receiver class but as I'm sure most of you already know the BroadcastReceiver class doesn't seem to support what I need to delete messages. I've been searching for an answer to this for a while, but haven't been able to find anything. Honestly I'm not sure I know enough about JAVA and Android to even recognize a solution if I saw it.
If you need to complete a job without an interface look into creating a Service, if you need user interface just start an Activity
You can use the Context parameter of the onReceive method of the receiver to start a new service/activity
You can use Extras to pass params between context. So you can put as extra the message id or entire message and pass it to your service/activity and deal it there.
You could implement the handling messages logic using an IntentService. When your receiver gets the new incomming message, start the IntentService passing an intent with the message data.
Receiver
onReceive(Context context, Intent intent) {
//Setup Intent
Intent i = new Intent(context, MyIntentService.class);
i.setAction(MyIntentService.HANDLE_MESSAGE);
//Pass data to intent
i.putExtra(MyIntentService.MESSAGE_DATA, data);
//Start Intent Service
context.startService(i);
}
MyIntentService
onHandleIntent(Intent i){
String action = i.getAction();
if(action != null && action.equals(MyIntentService.HANDLE_MESSAGE){
//Get data and implement message logic
}
}
Hope it helps.

Categories

Resources