I'm developing ,for educational purposes, a Android APP.
This APP have a GCMService and works well, but I'm trying to start a simple sound or alarm when the APP receive a certain message from GCM Service.
How I can do this?
I'm searching for information, but always see the people start a Service or Activity, and I think this is much easy.
Thanks ALL!
You can write the code into onMessage() of GCMIntentService like
#Override
protected void onMessage(Context context, Intent intent) {
Log.i(TAG, "Received message");
String message = getString(R.string.gcm_message);
displayMessage(context, message);
// notifies user
generateNotification(context, message);
//Write here for sound notification
//for example
Uri notification = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
Ringtone ringer = RingtoneManager.getRingtone(getApplicationContext(), notification);
ringer.play();
}
start a simple sound or alarm when the APP receive a certain message
from GCM Service
You can put condition in above method and play soound. like
if ("XYZ".equals(message)) {
//Then Play a sound
Uri notification = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
Ringtone ringer = RingtoneManager.getRingtone(getApplicationContext(), notification);
ringer.play();
}
Related
I have created android application to receive push notification from server but it is not working.
When app is in foreground, it works perfectly. But when we force close app from system tray it does not work.
Below is my json code which I send to FCM.
{"to":"\/topics\/global","data":{"title":"Title","body":"Body"}}
Below is my android function
public void onMessageReceived(RemoteMessage remoteMessage) {
super.onMessageReceived(remoteMessage);
Log.d("Msg", "Message received ["+remoteMessage+"]");
Map<String, String> data = remoteMessage.getData();
DatabaseHandler db = new DatabaseHandler(getApplicationContext());
db.addData(data.get("body"));
Intent resultIntent = new Intent(getApplicationContext(), MainActivity.class);
resultIntent.putExtra("message", data.get("body"));
showNotificationMessage(getApplicationContext(), data.get("title"), data.get("body"), "", resultIntent);
}
Below is code to show notification.
private void showNotificationMessage(Context context, String title, String message, String timeStamp, Intent intent) {
notificationUtils = new NotificationUtils(context);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
notificationUtils.showNotificationMessage(title, message, timeStamp, intent);
}
I can not find any problem, can any one please help me.
Thank you very much in advance.
Edit :
I have solved my problem by changing phone, in samsung device code is working fine but its problem with MI device itself.
I have also got solution for MI devices, use below steps to enable auto start that application.
Go to settings --> permissions --> autostart. From there, pick the apps you want to receive notifications, and toggle the switch to turn it on.
As per the doc there are two possibilities when notification arrived.
Application is in foreground.
You will get notify in onMessageReceived, and you can get data in this method. You need to generate local notification in system tray.
Handle Notification
You have done this code as mentioned in question.
Application is in background.
You get notification in system tray. You don't need to generate notification here. You will get data in Intent of launcher Activity.
Handle Notification
Here is code of launcher activity
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Intent intent = getIntent();
if (intent == null || intent.getExtras() == null) {
// your code to handle if there is no notification
} else {
// handle notification
String body = intent.getStringExtra("body");
String title = intent.getStringExtra("title");
//TODO your code to open activity as per notification
}
}
I have done this, and its works for me.
From here,
When in the background, apps receive the notification payload in the notification tray, and only handle the data payload when the user taps on the notification.
And from this,
This includes messages that contain both notification and data payload (and all messages sent from the Notifications console). In these cases, the notification is delivered to the device's system tray, and the data payload is delivered in the extras of the intent of your launcher Activity
You might get complete help from receive message tutorial
I am using FCM to push notification. I am passing intent to launch new activity when notification is clicked.when app is in foreground,app works fine and intent launch new activity, but when app is in background, it does not launch new activity but launch instance of default activity.
public class MyFirebaseMessagingService extends FirebaseMessagingService {
private static final String TAG = "MyFirebaseMsgService";
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
//Displaying data in log
//It is optional
Log.d(TAG, "From: " + remoteMessage.getFrom());
Log.d(TAG, "Notification Message Body: " + remoteMessage.getNotification().getBody());
//Calling method to generate notification
sendNotification(remoteMessage.getNotification().getBody());
}
private void sendNotification(String messageBody) {
Intent intent = new Intent(this, SecActivity.class);
intent.putExtra("started_from","notification");
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent,
PendingIntent.FLAG_ONE_SHOT);
Uri defaultSoundUri= RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this)
.setSmallIcon(R.mipmap.ic_launcher)
.setContentTitle("Firebase Push Notification")
.setContentText(messageBody)
.setAutoCancel(true)
.setSound(defaultSoundUri)
.setContentIntent(pendingIntent);
NotificationManager notificationManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(0, notificationBuilder.build());
}
}
Hope you are trying to launch the mainactivity when the message is received. When the app is resumed from background your current activity is getting cleared.
From the documentation for FLAG_ACTIVITY_CLEAR_TOP:
If set, and the activity being launched is already running in the current task, then instead of launching a new instance of that activity, all of the other activities on top of it will be closed and this Intent will be delivered to the (now on top) old activity as a new Intent.
Try removing this flag.
I too had this same problem but i managed to have it fix with this ,
In your default activity mentioned in the manifest do this in the onCreate
if (bundle != null) {
if ((String) bundle.get("tag") != null) {
String tag = (String) bundle.get("tag");
if (tag.equals("abc")) {
Intent intent = new Intent(SplashActivity.this, MessageDetailsActivity.class);
startActivity(intent);
} else if (tag.equals("def")) {
openSpecificActivity(tag, (String) bundle.get("id"));
}
} else {
Intent i = new Intent(SplashActivity.this, HomeActivity.class);
i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(i);
}
}
i got a solution for that.
just put below code in oncreate method of launcher activity.
if (bundle != null) {
String value = bundle.getString("key");
if (value != null) {
startActivity(new Intent(MainActivity.this, secActivity.class));
}
}
when app is in background or killed,FCM will not call onmessagerecieved method,but it will send data to system tray to display notification.so datapayload(sent from fcm console) will not be handled by onmessagerecieved method.when user click on notification,it will launch default activity of app and datapayload will be passed by intent .so making change in oncreate method of launcher activity(as above)we can get datapayload even when app is in background or killed.(ex key is sent by fcm console).when app is in foreground datapayload and will be handled by onmessagerecieved method of fcm service.
Based upon Antinio's answer
https://stackoverflow.com/a/37845174/4454119
Why is this happening?
There are two types of messages in FCM (Firebase Cloud Messaging):
display-messages: These messages trigger the onMessageReceived() callback only when your app is in foreground
data-messages: Theses messages trigger the onMessageReceived() callback even if your app is in foreground/background/killed
Firebase team have not developed a UI to send data-messages to your devices, yet.
So you need to use data-messages..
In FCM you have two types of messages
Notification Messages
Data Messages
Use notification messages when you want FCM to handle displaying a notification on your client app's behalf. Use data messages when you want to process the messages in your client app.
If you need to process your message before sending it to the system tray, it's better to use Data messages, as for these types of messages, the callback first reaches the onMessageRecieved method before going to the system tray.
Use this:
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
IN YOUR SERVICE
"to": token,
"notification": {
"title": "Title,
"body": "Body"
},
"data" : {
"update": "yes"
}
IN ANDROID KOTLIN
val intent = Intent(this,MainActivity::class.java)
intent.putExtra("update","yes")
......
I am using FCM in my app. I followed the Firebase documentation and all seems to be working as expected.
I am able to receive message notifications when the app is killed, in background and in foreground.
Now I want to give full control the user by adding some app preferences.
The user can disable all notification from the app settings
The user can change notification ringtone from the app settings
I have an idea on how to do it when the app is in killed or in the foreground. I am thinking of accessing the sharedprefs in my FirebaseMessagingService to see if the app should show the notification and check what ringtone to use. Unless there is a generic way to set those parameters, like "unsubscribing" from all notification or changing the app default notification ringtone which I am not aware of?
However I have no idea how i can do it for the notifications received when the app in is the background since the notifications are delivered to the device's system tray.
Anyone has any idea or can point me to some documentation... I am not finding any info on this?
By default, notifications affect every user. If you'd like to allow users to opt-out of all notifications (or certain subsets of notifications), you should use topic messaging: by default, you'd call subscribeToTopic() for all users and if they opt-out of notifications, you'd call unsubscribeToTopic().
By sending a notification to a topic, only the subscribed users will receive it.
The notification payload support documentation explains how to include a sound parameter to override the ringtone - on Android, that can be any sound bundled in the app's res/raw directory.
It should be noted that neither of these features are supported in the Console, but require that you create your own Firebase Cloud Messaging Server
As firebase notification service is having 2 object 1st is "data" and 2nd is "notification", when you are sending push from firebase console it sending data in "notification" object. When u handle the notification in FirebaseMessagingService.class you are creating a custom notification with NotificationBuilder. When App is in background you wont be able to create notification from "notification" object. so, your custom made notification wont be appear in notification tray, You need to push a notification from your backend and send notification contents in "data" object. You will be able to customise your notification every time.
please refer this for more : https://firebase.google.com/docs/cloud-messaging/android/send-multiple
The user can disable all notification from the app settings.
You can use shared preferences as you stated yourself. As far as a generic method is concerned you should look into #ianhanniballake 's answer.
The user can change notification ringtone from the app settings
For default ringtones refer to this link. The 3rd answer in this link also explains how to bring the sound selector from settings activity of your app. If you want custom sounds refer this.
Of course, you'll have to store user preferences so that you don't ask the user each time to select a sound.
And one more thing since you are using a service so you need not access shared preferences each and every time to find which sound to play, you can store the choice in any variable. Whenever there is a change of notif-sound by the user, you can either set a listener or {stop service -> update preferences -> restart service}. Make sure every time the service starts it reads the preferences.
In this AndroidHive tutorials you can find how we change Ringtone for particular app and how to deal with notifications when app is in foreground and app is in background.
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
......
// Check if message contains a notification payload.
if (remoteMessage.getNotification() != null) {
Log.e(TAG, "Notification Body: " + remoteMessage.getNotification().getBody());
handleNotification(remoteMessage.getNotification().getBody());
}
}
When notification type message is sent, firebase automatically shows the notification when the app is in background. If the app is in foreground, handleNotification() method handles the notification message.
private void handleNotification(String message) {
if (!NotificationUtils.isAppIsInBackground(getApplicationContext())) {
// app is in foreground, broadcast the push message
Intent pushNotification = new Intent(Config.PUSH_NOTIFICATION);
pushNotification.putExtra("message", message);
LocalBroadcastManager.getInstance(this).sendBroadcast(pushNotification);
// play notification sound
NotificationUtils notificationUtils = new NotificationUtils(getApplicationContext());
notificationUtils.playNotificationSound();
}else{
// If the app is in background, firebase itself handles the notification
}
}
Here you handle custom Notification Sound-
// Playing notification sound
public void playNotificationSound() {
try {
Uri alarmSound = Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE
+ "://" + mContext.getPackageName() + "/raw/notification");
Ringtone r = RingtoneManager.getRingtone(mContext, alarmSound);
r.play();
} catch (Exception e) {
e.printStackTrace();
}
}
Firebase will not call your onMessageReceived when your app is in background or killed, and you can't customise your notification. System generated notification will show.
to make firebase library to call your onMessageReived in every cases
a) Foreground
b) Background
c) Killed
you must not put json key "notification" in your request to firebase api but instead use "data", see below.
For example following message will not call onMessagereceived()
{
"to": "/topics/test",
"notification": {
"title" : "title",
"text": "data!",
"icon": "ic_notification"
}
}
but this will work
{
"to": "/topics/test",
"data": {
"text":"text",
"title":"",
"line1":"testline",
"line2":"test"
}
}
see this link:https://firebase.google.com/docs/cloud-messaging/concept-options
it has a detailed description of firebase message type
For example:
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
Log.d(TAG, "From: " + remoteMessage.getFrom());
// Check if message contains a data payload.
if (remoteMessage.getData().size() > 0) {
Log.d(TAG, "Message data payload: " + remoteMessage.getData());
}
if(remoteMessage.getData().get("state").toString().equals("Request")){
sendNotification(remoteMessage.getData().get("body").toString(), remoteMessage.getData().get("message").toString(), remoteMessage.getData().get("state").toString(),Activity_name.class);
}
}
private void sendNotification(String messageBody, String data, String state,Class<?> activityCompat) {
int requestID = (int) System.currentTimeMillis();
Intent intent = new Intent(this, activityCompat);
Bundle bundle = new Bundle();
bundle.putString("message", data);
bundle.putString("state", state);
intent.putExtras(bundle);
PendingIntent pendingIntent = PendingIntent.getActivity(this, requestID, intent, PendingIntent.FLAG_UPDATE_CURRENT);
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this)
.setSmallIcon(R.drawable.small_logo)
.setContentTitle("Title")
.setContentText(messageBody).setContentIntent(pendingIntent)
.setAutoCancel(true)
.setStyle(new NotificationCompat.BigTextStyle()
.bigText(messageBody))
.setTicker(messageBody);
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
notificationBuilder.getNotification().flags |= Notification.FLAG_AUTO_CANCEL;
Notification notification = notificationBuilder.build();
notificationManager.notify((int) Calendar.getInstance().getTimeInMillis(), notification);
}
I'm sending Firebase notifications through my own webservice with PHP like below.
$url = 'https://fcm.googleapis.com/fcm/send';
$fields = array(
'registration_ids' => $tokens,
'data' => $message
);
$headers = array(
'Authorization:key = SERVER_KEY ',
'Content-Type: application/json'
);
1.Notifications are coming when App is in Foreground and Background without any issues , But if I removed app from recent tray then notifications not coming , I must have to handle this any solution for this ? (like Whatsup notifications are showing all scenarios even I force stopped this app from settings)
2.Once I received notification , from "onMessageReceived" how to pass these message,body content to my Activity /Fragments?
3.In some cases I want to send notification to all , Instead of adding all tokens to array . any other way to handle like "send to ALL" something like that ?
public class MyFirebaseMessagingService extends FirebaseMessagingService {
private static final String TAG = "MsgService";
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
Log.d(TAG, "From: " + remoteMessage.getFrom());
Log.d(TAG, "Data Payload : " + remoteMessage.getData());
sendNotification(remoteMessage.getData().get("message"));
}
private void sendNotification(String messageBody) {
Intent intent = new Intent(this, MainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent,
PendingIntent.FLAG_ONE_SHOT);
Uri defaultSoundUri= RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this)
.setSmallIcon(R.mipmap.ic_launcher)
.setContentTitle("Firebase Push Notification")
.setContentText(messageBody)
.setAutoCancel(true)
.setSound(defaultSoundUri)
.setContentIntent(pendingIntent);
NotificationManager notificationManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(0, notificationBuilder.build());
}
}
Failed devices: (Notifications are not coming after removed from Recent Tray)
MI Redmi Note 2 (5.0.2 Lollipop)
Huawei honor 5c (5.1.1 Lollipop)
Succeed devices: (Notifications are coming after removed from Recent Tray)
HTC One X (4.2 Jelly Bean)
Samsung galaxy grand prime (4.4 Kitkat)
1.Notifications are coming when App is in Foreground and Background without any issues , But if I removed app from recent tray then
notifications not coming , I must have to handle this any solution for
this ? (like Whatsup notifications are showing all scenarios even I
force stopped this app from settings)
As per your code you must be getting a null pointer exception on remoteMessage.getNotification().getBody() as you are not sending notification, instead you are sending data payload from your curl request. As per my personal experience, the issue you just mentioned is seen especially in Android Kitkat or below devices. On Lollipop or above Firebase push seems to work fine.
2.Once I received notification , from "onMessageReceived" how to pass these message,body content to my Activity /Fragments?
You can issue a Broadcast from onMessageReceived() and register a Braodcast Receiver in your Activity and send the data in your broadcast intent. Example code:
Activity
private BroadcastReceiver receiver;
#Overrride
public void onCreate(Bundle savedInstanceState){
// your oncreate code
IntentFilter filter = new IntentFilter();
filter.addAction("SOME_ACTION");
receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
String message = intent.getStringExtra("message");
}
};
registerReceiver(receiver, filter);
}
#Override
protected void onDestroy() {
if (receiver != null) {
unregisterReceiver(receiver);
receiver = null
}
super.onDestroy();
}
FirebaseMessagingService
public class MyFirebaseMessagingService extends FirebaseMessagingService {
private static final String TAG = "MsgService";
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
Log.d(TAG, "From: " + remoteMessage.getFrom());
Log.d(TAG, "Notification Message Body: " + remoteMessage.getData());
Intent intent=new Intent();
intent.setAction("SOME_ACTION");
intent.putExtra("message", remoteMessage.getNotification().getBody());
sendBroadcast(intent);
}
}
3.In some cases I want to send notification to all , Instead of adding all tokens to array . any other way to handle like "send to ALL"
something like that ?
There is nothing like "Send to ALL" in Firebase API, the only way to do this is using Firebase Console which have its own issues to handle like white icon issue, and ripping the custom params of your notification.
I was having problem with FCM on exactly Mi Phone and Huawei phone as well! Turns out that it was not a problem with FCM or your app, but on their device level.
They have device level app settings that disable notifications or even wake lock, so onMessageReceived() is not fired when the message arrives. After I changed the settings (mainly allow notifications & disable battery optimisation for my app), everything works just fine!
Refer to Firebase cloud messaging not received when app in background.
This problem needs back-end implementation.
Let me discuss how I overcome this shortcoming.
We are aware of the Activity life-cycle. So upon destroy, I call a service from the back-end that unregisters my client token.
All incoming messages will now be queued for delivery since the token for target client is unregistered.
So upon bringing back the application, I call a back-end service that registers my client.
The back end now starts to sends messages from queue with the new client token for my device.
I want to receive a sms in my app, but I don't want my Android to show a notification about that event. Algorithm:
Receive sms (it's ok)
If this is a sms with special content-format (for my app) - process it with my app and don't display a notification.
If this is a simple message - I don't want to process it, so a notification must be displayed.
I tried to use an ordered broadcast, but it doesn't help. Somewhere I read that SMS_RECEIVE's broadcast is not ordered, but I saw some apps, which can receive SMS without notify.
Does anyone can help me or show me the right way to solve this problem?
Calling abortBroadcast() in broadcast doesn't help
set priority in your intent-filter
// in manifest
<intent-filter android:priority="100"> /*your receiver get high priority*/
// in broadcast receiver
if (keyword_match)
{
// Stop it being passed to the main Messaging inbox
abortBroadcast();
}
This should be possible by registering your app to receive SMS messages and then using abortBroadcast() when you detect your message has arrived. You say abortBroadcast() doesn't work - is the SMS definitely getting handled by your SMS receiver?
For anybody else wanting to do this, read on...
First, declare the SMS receiver in your AndroidManifest.xml and make sure the app has permission to receive SMS messages.
<receiver android:name="mypackage.SMSReceiver">
<intent-filter>
<action android:name="android.provider.Telephony.SMS_RECEIVED"/>
</intent-filter>
</receiver>
<uses-permission android:name="android.permission.RECEIVE_SMS" />
Here's some example code to handle the SMS messages:
public class SMSReceiver extends BroadcastReceiver
{
#Override
public void onReceive(Context context, Intent intent)
{
Bundle extras = intent.getExtras();
Object[] pdus = (Object[])extras.get("pdus");
for (Object pdu: pdus)
{
SmsMessage msg = SmsMessage.createFromPdu((byte[])pdu);
String origin = msg.getOriginatingAddress();
String body = msg.getMessageBody();
// Parse the SMS body
if (isMySpecialSMS)
{
// Stop it being passed to the main Messaging inbox
abortBroadcast();
}
}
}
}
You should not do this. Other apps might want or need to receive the SMS_RECEIVED broadcast. Aborting it will disrupt 3rd party apps from running properly. This is a bad way to program. you should only abort broadcasts that you create, not system broadcasts. I don't know why the Android OS lets you do this.
not sure if i know exactly what you are trying to do but from what i understand you just want to know how to not send a notification?
why cant you just do:
If(instance 2){
//do your processing
}else{
//send notification
}
if you mean you want to block the OS from broadcasting it then you might be out of luck because i dont believe you can do that
yo need android:priority attribute for that to work
<intent-filter android:priority="1">
<action android:name="android.provider.Telephony.SMS_RECEIVED" />
</intent-filter>
You are doing one mistake,
because you fired abortBroadcast(); if your special message so the message broadcasting is aborted, therefore SMS notification is not Showing, and sms is not saving in Inbox,
You have to make your own Notification in "onRecive" if your special message is received.
Example:
public class SMSReceiver extends BroadcastReceiver
{
#Override
public void onReceive(Context context, Intent intent)
{
Bundle extras = intent.getExtras();
Object[] pdus = (Object[])extras.get("pdus");
for (Object pdu: pdus)
{
SmsMessage msg = SmsMessage.createFromPdu((byte[])pdu);
String origin = msg.getOriginatingAddress();
String body = msg.getMessageBody();
// Parse the SMS body
if (isMySpecialSMS)
{ // Stop it being passed to the main Messaging inbox
abortBroadcast();
NotificationManager notificationManager = (NotificationManager)context.getSystemService(context.NOTIFICATION_SERVICE);
Notification notification = new Notification(R.drawable.ic_launcher, "New Message (My Messaging app)", System.currentTimeMillis());
// Uses the default lighting scheme
notification.defaults |= Notification.DEFAULT_LIGHTS;
// Will show lights and make the notification disappear when the presses it
notification.flags |= Notification.FLAG_AUTO_CANCEL | Notification.FLAG_SHOW_LIGHTS;
Intent notificationIntent = new Intent(context, SplashActivity.class);
PendingIntent pendingIntent =PendingIntent.getActivity(context, 0,
new Intent(context, SplashActivity.class), 0);
Log.i("Wakeup", "Display Wakeup");
PowerManager pm = (PowerManager)context.getApplicationContext().getSystemService(Context.POWER_SERVICE);
WakeLock wakeLock = pm.newWakeLock((PowerManager.SCREEN_BRIGHT_WAKE_LOCK | PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP), "Phone WakeUp");
wakeLock.acquire();
notification.setLatestEventInfo(context, "My Messaging App(New Message)",msg, pendingIntent);
//notification.sound.
notification.defaults |= Notification.DEFAULT_SOUND;
notificationManager.notify(9999, notification);
}
else{
//Continue Broadcasting to main android app
}
}
}
}
I hope this will solve your Problem