I have a chat app and I'm trying to display a notification to the user once a new message is received.
Once I launch the activity I call onStart as follows:
#Override
protected void onStart() {
super.onStart();
popNotification();
}
popNotification is a class that is called in order to check if there was any update in my database. If yes, I call another class called AddNotification()
public void popNotification() {
db.collection("Users").document(auth.getUid()).collection("MyChats")
.addSnapshotListener(new EventListener<QuerySnapshot>() {
#Override
public void onEvent(#Nullable QuerySnapshot value,
#Nullable FirebaseFirestoreException e) {
if (e != null) {
Log.w("", "Listen failed.", e);
return;
}
for (QueryDocumentSnapshot doc : value) {
if (doc.getId() != null) {
DocumentReference docRef = db.collection("Users").document(auth.getUid()).collection("MyChats").document(doc.getId());
docRef.get().addOnCompleteListener(new OnCompleteListener<DocumentSnapshot>() {
#Override
public void onComplete(#NonNull Task<DocumentSnapshot> task) {
if (task.isSuccessful()) {
DocumentSnapshot document = task.getResult();
if (document.exists()) {
if(document.getLong("LastMessageTime") > document.getLong("lastChatVisited")){
AddNotification();
}
} else {
Log.d("", "No such document");
}
} else {
Log.d("", "get failed with ", task.getException());
}
}
});
}
}
}
});
}
and AddNotification():
private void AddNotification(){
FirebaseInstanceId.getInstance().getInstanceId()
.addOnCompleteListener(new OnCompleteListener<InstanceIdResult>() {
#Override
public void onComplete(#NonNull Task<InstanceIdResult> task) {
if (!task.isSuccessful()) {
Log.w("", "getInstanceId failed", task.getException());
return;
}
// Get new Instance ID token
String token = task.getResult().getToken();
try {
String title = "TEST ";
MyTaskParams params = new MyTaskParams(token, title, "TTT!");
MyTask myTask = new MyTask();
myTask.execute(params);
} catch (Exception ex) {
ex.printStackTrace();
}
}
});
}
One last thing is the mytask which is:
private class MyTask extends AsyncTask<MyTaskParams, Void, Void> {
#Override
protected Void doInBackground(MyTaskParams... params) {
String userDeviceIdKey = params[0].url;
String title = params[0].title;
String body = params[0].body;
String authKey = "XXX"; // You FCM AUTH key
String FMCurl = "https://fcm.googleapis.com/fcm/send";
URL url;
try {
url = new URL(FMCurl);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setUseCaches(false);
conn.setDoInput(true);
conn.setDoOutput(true);
conn.setRequestMethod("POST");
conn.setRequestProperty("Authorization","key="+authKey);
conn.setRequestProperty("Content-Type","application/json");
JSONObject json = new JSONObject();
json.put("to",userDeviceIdKey);
json.put("priority","high");
JSONObject info = new JSONObject();
info.put("title", title); // Notification title
info.put("body", body); // Notification body
json.put("data", info);
OutputStreamWriter wr = new OutputStreamWriter(conn.getOutputStream());
wr.write(json.toString());
wr.flush();
conn.getInputStream();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (JSONException e) {
e.printStackTrace();
}
return null;
}
}
Now, the problem is that I don't receive any notification.
I inserted Logs in order to check if the code runs there and it seems to pass all the required functions however still it doesn't show anything.
I added priority = high because I read it might affect but it didn't help.
My message class is:
public class MyFirebaseMessagingService extends FirebaseMessagingService {
private static final String TAG = "FCM Service";
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
Log.d(TAG, "From: " + remoteMessage.getFrom());
Log.d(TAG, "Notification Message Body: " + remoteMessage.getData().get("body"));
NotificationCompat.Builder builder = new NotificationCompat.Builder(this, "29358305")
.setSmallIcon(R.drawable.ic_launcher_custom_background)
.setContentTitle(remoteMessage.getData().get("title"))
.setContentText(remoteMessage.getData().get("body"))
.setStyle(new NotificationCompat.BigTextStyle()
.bigText(remoteMessage.getData().get("body")))
.setLargeIcon(BitmapFactory.decodeResource(getApplicationContext().getResources(),
R.mipmap.ic_launcher))
.setPriority(NotificationCompat.PRIORITY_DEFAULT);
//createNotificationChannel();
NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this);
notificationManager.notify(235345305, builder.build());
}
}
EDIT:
I also tried to use the following when creating the notification without any improvement:
public class MyFirebaseMessagingService extends FirebaseMessagingService {
private static final String TAG = "FCM Service";
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
Log.d(TAG, "From: " + remoteMessage.getFrom());
Log.d(TAG, "Notification Message Body: " + remoteMessage.getData().get("body"));
createNotificationChannel();
notifyThis(remoteMessage.getData().get("title"),remoteMessage.getData().get("body"));
}
private void createNotificationChannel() {
// Create the NotificationChannel, but only on API 26+ because
// the NotificationChannel class is new and not in the support library
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
CharSequence name = "ABC";
String description = "ABCDE";
int importance = NotificationManager.IMPORTANCE_DEFAULT;
NotificationChannel channel = new NotificationChannel("191919", name, importance);
channel.setDescription(description);
// Register the channel with the system; you can't change the importance
// or other notification behaviors after this
NotificationManager notificationManager = getSystemService(NotificationManager.class);
notificationManager.createNotificationChannel(channel);
}
}
public void notifyThis(String title, String message) {
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this, "191919")
.setSmallIcon(R.drawable.ic_launcher_background)
.setContentTitle(title)
.setContentText(message)
.setPriority(NotificationCompat.PRIORITY_DEFAULT);
NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this);
// notificationId is a unique int for each notification that you must define
notificationManager.notify(0, mBuilder.build());
}
Do I also need to add onPause or something else for it to work or do I have some other bug that I cant understand?
Thank you
Related
I am trying to make a chatting app in android studio. All the basic functions are done but I have been struggling with a problem for a time. The problem is sending notification to a device. I have searched the web a lot and was finally successful when a error came by the code is given below.
sendNotification function
private void sendNoti(String senderId, String receiverId){
JSONObject jsonObject = new JSONObject();
try {
jsonObject.put("to", "/User/"+receiverId);
JSONObject jsonObject1 = new JSONObject();
jsonObject1.put("title", "Message from " + senderId);
jsonObject1.put("body", "hello");
jsonObject.put("notification", jsonObject1);
JsonObjectRequest request = new JsonObjectRequest(Request.Method.POST, url, jsonObject, new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
Log.e("SUCCESS", response + "");
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Log.e("ERRORS", error + "");
}
}) {
#Override
public Map<String, String> getHeaders() throws AuthFailureError {
Map<String, String> map = new HashMap<>();
map.put("content-type", "application/json");
map.put("authorization", "key=key");
Log.d("Maping",map.toString());
return map;
}
};
RequestQueue requestQueue = Volley.newRequestQueue(this);
int socketTimeout = 1000 * 60;// 60 seconds
RetryPolicy policy = new DefaultRetryPolicy(socketTimeout, DefaultRetryPolicy.DEFAULT_MAX_RETRIES, DefaultRetryPolicy.DEFAULT_BACKOFF_MULT);
request.setRetryPolicy(policy);
requestQueue.add(request);
} catch (JSONException e) {
e.printStackTrace();
}
}
MyFirebaseMessagingService
public class MyFirebaseMessagingService extends FirebaseMessagingService {
#Override
public void onMessageReceived(#NonNull #NotNull RemoteMessage remoteMessage) {
super.onMessageReceived(remoteMessage);
sendNotification(remoteMessage);
}
#Override
public void onNewToken(String s) {
super.onNewToken(s);
Log.e("newToken", s);
getSharedPreferences("_", MODE_PRIVATE).edit().putString("fb", s).apply();
System.out.println("Token "+s);
}
private void sendNotification(RemoteMessage remoteMessage) {
String user = remoteMessage.getData().get("from");
String title = remoteMessage.getData().get("title");
String body = remoteMessage.getData().get("body");
System.out.println("user "+user);
System.out.println("title "+title);
System.out.println("body "+body);
Intent intent = new Intent(this, MainActivity.class);
String channel_id = "notification_channel";
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_ONE_SHOT);
NotificationCompat.Builder builder = new NotificationCompat
.Builder(getApplicationContext(), channel_id)
.setSmallIcon(R.drawable.vroo)
.setContentTitle(title)
.setContentText("body")
.setAutoCancel(true)
.setVibrate(new long[]{1000, 1000, 1000, 1000, 1000})
.setOnlyAlertOnce(true)
.setContentIntent(pendingIntent);
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel notificationChannel = new NotificationChannel(channel_id, "web_app", NotificationManager.IMPORTANCE_HIGH);
notificationManager.createNotificationChannel(notificationChannel);
}
notificationManager.notify(0, builder.build());
}
}
I get the log output that my message is sent but I never receive it on the receiver side can someone please help me?
I have the following FirebaseMessagingService which works fine when I get a push notification and the app is in foreground:
public class _FCMService extends FirebaseMessagingService {
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
if (remoteMessage.getData().size() > 0) {
// Log.i(TAG, "PUSH PAYLOAD: " + remoteMessage.getData());
JSONObject pushData = new JSONObject(remoteMessage.getData());
pushType = pushData.optString("pushType");
pushMessage = pushData.optString("body");
Log.i(TAG, "ON PUSH RECEIVED - pushType: " + pushType);
Log.i(TAG, "ON PUSH RECEIVED - pushMessage: " + pushMessage);
Uri defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this)
.setContentText(pushMessage)
.setStyle(new NotificationCompat.BigTextStyle())
.setAutoCancel(true)
.setSmallIcon(R.mipmap.ic_launcher)
.setSound(defaultSoundUri);
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
assert notificationManager != null;
notificationManager.notify(0 , notificationBuilder.build());
}
}
#Override
public void onNewToken(#NotNull String token) {
Log.i(TAG, "Refreshed token: " + token);
ANDROID_DEVICE_TOKEN = token;
}
}
So, If I receive a push, the Logcat prints out the notification's body and (if present) the pushType string.
What I would need to do is to make my other Activity update data when push is received, as well as get the pushMessage and pushType strings.
I know how to do that in iOS Swift - by using NotificationCenter - but have no idea about Android, I've tried LocalBroadcaster, but no success.
LocalBroadcastManager is now deprecated!
You can use LiveData implementation in a static reference and observe it in the Activity or Fragment
public class NotificationService extends FirebaseMessagingService {
#Override
public void onMessageReceived(#NonNull RemoteMessage remoteMessage) {
super.onMessageReceived(remoteMessage);
Notification.
getInstance().
addOrder(remoteMessage.getData().get("id"));
}
public static class Notification {
private static Notification instance;
private MutableLiveData<String> newOrder;
private Notification() {
newOrder = new MutableLiveData<>();
}
public static Notification getInstance() {
if(instance == null){
instance = new Notification();
}
return instance;
}
public LiveData<String> getNewOrder() {
return newOrder;
}
public void addOrder(String orderID){
newOrder.postValue(orderID);
}
}
}
And In the Activity or Fragment:
NotificationService.
Notification.
getInstance().
getNewOrder().
observe(getViewLifecycleOwner(), new Observer<String>() {
#Override
public void onChanged(String s) {
//TODO: update your ui here...
}
});
You can add a .setContentIntent(NotificationChannelUtil.createPendingIntent(this, pushMessage, pushType)) to your notificaitionBuilder.
Where that function is inside an util class like:
public class NotificationChannelUtil {
private NotificationChannelUtil() {}
public static PendingIntent createPendingIntent(Context context, String pushMessage, String pushType) {
Intent intent = new Intent(context, YourWantedActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
intent.putExtra("pushMessage", pushMessage);
intent.putExtra("pushType", pushType);
return PendingIntent.getActivity(context, 0 /* request code */, intent,
PendingIntent.FLAG_ONE_SHOT);
}
}
I've found a solution to my issue, which actually looks similar to the iOS NotificationCenter instance. I've added this class into my _FCMService.java file:
class NotificationCenter {
private static NotificationCenter _instance;
private HashMap<String, ArrayList<Runnable>> registredObjects;
private NotificationCenter(){
registredObjects = new HashMap<>();
}
//returning the reference
static synchronized NotificationCenter defaultCenter(){
if(_instance == null)
_instance = new NotificationCenter();
return _instance;
}
synchronized void addFunctionForNotification(String notificationName, Runnable r){
ArrayList<Runnable> list = registredObjects.get(notificationName);
if(list == null) {
list = new ArrayList<Runnable>();
registredObjects.put(notificationName, list);
}
list.add(r);
}
public synchronized void removeFunctionForNotification(String notificationName, Runnable r){
ArrayList<Runnable> list = registredObjects.get(notificationName);
if(list != null) {
list.remove(r);
}
}
synchronized void postNotification(String notificationName){
ArrayList<Runnable> list = registredObjects.get(notificationName);
if(list != null) {
for(Runnable r: list)
r.run();
}
}
}
Then I've called it inside the onMessageReceived() function:
NotificationCenter.defaultCenter().postNotification("pushNotif");
Lastly, I've added the observer into the onStart() function of my Activity as it follows:
#Override
protected void onStart() {
super.onStart();
// Start NotificationCenter to observe for new messages
NotificationCenter.defaultCenter().addFunctionForNotification("pushNotif", new Runnable() {
#Override
public void run() {
Log.i(TAG, "Obj Details -> pushMessage: " + pushMessage + "\npushType" + pushType);
}});
}
It works smoothly, hoper this helps somebody else.
android fcm notification not received and while the device which supposed to receivethe notification shows this message in Logcat (Received from FCM TITLE: null, Received from FCM BODY: null). I have already checked that notification is not being received in both <26 and >26 SDK Versions
====================MyFirebaseMessagingService===============================
public class MyFirebaseMessagingService extends FirebaseMessagingService {
private static final String channel_id = "the_id";
#Override
public void onNewToken(String s) {
super.onNewToken(s);
Log.e("NEW_TOKEN",s);
updateTokenToFirebase(s);
}
private void updateTokenToFirebase(String token) {
IDrinkShopAPI mService = Common.getAPI();
mService.updateToken("SERVER_01",token,"0")
.enqueue(new Callback<String>() {
#Override
public void onResponse(Call<String> call, Response<String> response) {
Log.d("DEBUG_TOKEN",response.body());
}
#Override
public void onFailure(Call<String> call, Throwable t) {
Log.d("DEBUG_TOKEN",t.getMessage());
}
});
}
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
super.onMessageReceived(remoteMessage);
if(remoteMessage.getData() != null){
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
sendNotification26(remoteMessage);
else
sendNotification(remoteMessage);
}
}
private void sendNotification26(RemoteMessage remoteMessage) {
Map<String,String> data = remoteMessage.getData();
String title = data.get("title");
String message = data.get("message");
NotificationHelper helper ;
Notification.Builder builder;
Uri defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
helper = new NotificationHelper(this);
builder = helper.getDrinkShopNotification(title,message,defaultSoundUri);
helper.getManager().notify(new Random().nextInt(),builder.build());
}
private void sendNotification(RemoteMessage remoteMessage) {
Map<String,String> data = remoteMessage.getData();
String title = data.get("title");
String message = data.get("message");
Uri defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
NotificationCompat.Builder builder = new NotificationCompat.Builder(this)
.setSmallIcon(R.mipmap.ic_launcher)
.setContentTitle(title)
.setContentText(message)
.setAutoCancel(true)
.setSound(defaultSoundUri);
NotificationManager mn =(NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
mn.notify(new Random().nextInt(),builder.build());
}
}
=========================NotificationHelper =================================
//this class is used to implement notification for all android versions
public class NotificationHelper extends ContextWrapper {
private static final String CHANNEL_ID = "the_id";
private static final String CHANNEL_NAME = "Drink_Shop";
private NotificationManager notificationManager;
public NotificationHelper(Context base) {
super(base);
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
createChannel();
}
#TargetApi(Build.VERSION_CODES.O)
private void createChannel() {
NotificationChannel nc = new NotificationChannel(CHANNEL_ID,CHANNEL_NAME,
NotificationManager.IMPORTANCE_DEFAULT);
nc.enableLights(false);
nc.enableVibration(true);
nc.setLockscreenVisibility(Notification.VISIBILITY_PRIVATE);
getManager().createNotificationChannel(nc);
}
public NotificationManager getManager() {
if(notificationManager == null)
notificationManager = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
return notificationManager;
}
#TargetApi(Build.VERSION_CODES.O)
public Notification.Builder getDrinkShopNotification(String title,
String message,
Uri soundUri)
{
return new Notification.Builder(getApplicationContext(),CHANNEL_ID)
.setContentTitle(title)
.setContentText(message)
.setSmallIcon(R.mipmap.ic_launcher)
.setSound(soundUri)
.setChannelId(CHANNEL_ID)
.setAutoCancel(true);
}
}
=============================Manifest=======================================
<service
android:name=".Services.MyFirebaseMessagingService"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
============================Build.gradle====================================
implementation 'com.google.firebase:firebase-messaging:20.0.0'
implementation 'com.google.firebase:firebase-core:17.2.1'
implementation 'com.google.android.gms:play-services-auth:17.0.0'
===========================IFCMService=======================================
public interface IFCMService {
#Headers({
"Content-Type:application/json",
"Authorization:mytoken"
})
#POST("fcm/send")
Call<MyResponse> sendNotification(#Body DataMessage body);
}
==========================sendNotificationToServer===============================
// this method used to send the notification to server device
private void sendNotificationToServer(OrderResult orderResult) {
mService.getToken("SERVER_01", "1")
.enqueue(new Callback<Token>() {
#Override
public void onResponse(Call<Token> call, Response<Token> response) {
Map<String,String> contentSend = new HashMap<>();
contentSend.put("title","NEW ORDER");
contentSend.put("message","You have got new order" + orderResult.getOrderId());
DataMessage dataMessage = new DataMessage();
if(response.body().getToken() != null)
dataMessage.setTo(response.body().getToken());
dataMessage.setData(contentSend);
IFCMService ifcmService = Common.getFCMService();
ifcmService.sendNotification(dataMessage)
.enqueue(new Callback<MyResponse>() {
#Override
public void onResponse(Call<MyResponse> call, Response<MyResponse> response) {
if(response.code() == 200){
if(response.body().success == 1){
Toast.makeText(CartActivity.this,
getResources().getString(R.string.order_submitted), Toast.LENGTH_SHORT)
.show();
//Clear Carts From Room Database
Common.cartRepository.emptyCart();
//finish();
}
else {
Toast.makeText(CartActivity.this, "Send Notification Failed", Toast.LENGTH_SHORT).show();
}
}
}
#Override
public void onFailure(Call<MyResponse> call, Throwable t) {
Toast.makeText(CartActivity.this, ""+t.getMessage(), Toast.LENGTH_SHORT).show();
}
});
}
#Override
public void onFailure(Call<Token> call, Throwable t) {
Toast.makeText(CartActivity.this, t.getMessage(), Toast.LENGTH_SHORT).show();
}
});
}
I have solved this issue by downgrading firebase-messaging library as follow (implementation 'com.google.firebase:firebase-messaging:17.3.4') as will as .setColor(ContextCompat.getColor(this, R.color.colorAccent)) in NotificationCompat. However this has solved the issue for me for SDK version lower than 26. Anyone knows why it is still cashing on APIs higher than 26 ?! help me please
When the App is running in background the notification is received in the system tray, and when is tapped, the intent is sended to your activity default, with the notification with payload of content of it.
When your application is running in front, the notification is received with the FirebaseMessagingService and the logic that you overrided.
I think you should add the logic of the first point, when the app is running in background
Check here more information
Handling messages
Android fcm notification is being received on android with APIs lower than 26 however APIs 26(Oreo 8.0) it doesn't and it cause app to be crashed
====================MyFirebaseMessagingService===============================
public class MyFirebaseMessagingService extends FirebaseMessagingService {
private static final String channel_id = "the_id";
#Override
public void onNewToken(String s) {
super.onNewToken(s);
Log.e("NEW_TOKEN",s);
updateTokenToFirebase(s);
}
private void updateTokenToFirebase(String token) {
IDrinkShopAPI mService = Common.getAPI();
mService.updateToken("SERVER_01",token,"0")
.enqueue(new Callback<String>() {
#Override
public void onResponse(Call<String> call, Response<String> response) {
Log.d("DEBUG_TOKEN",response.body());
}
#Override
public void onFailure(Call<String> call, Throwable t) {
Log.d("DEBUG_TOKEN",t.getMessage());
}
});
}
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
super.onMessageReceived(remoteMessage);
if(remoteMessage.getData() != null){
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
sendNotification26(remoteMessage);
else
sendNotification(remoteMessage);
}
}
private void sendNotification26(RemoteMessage remoteMessage) {
Map<String,String> data = remoteMessage.getData();
String title = data.get("title");
String message = data.get("message");
NotificationHelper helper ;
Notification.Builder builder;
Uri defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
helper = new NotificationHelper(this);
builder = helper.getDrinkShopNotification(title,message,defaultSoundUri);
helper.getManager().notify(new Random().nextInt(),builder.build());
}
private void sendNotification(RemoteMessage remoteMessage) {
Map<String,String> data = remoteMessage.getData();
String title = data.get("title");
String message = data.get("message");
Uri defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
NotificationCompat.Builder builder = new NotificationCompat.Builder(this)
.setSmallIcon(R.mipmap.ic_launcher)
.setContentTitle(title)
.setContentText(message)
.setAutoCancel(true)
.setColor(ContextCompat.getColor(this, R.color.colorAccent))
.setSound(defaultSoundUri);
NotificationManager mn =(NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
mn.notify(new Random().nextInt(),builder.build());
}
}
=========================NotificationHelper =================================
//this class is used to implement notification for APIs 26+
public class NotificationHelper extends ContextWrapper {
private static final String CHANNEL_ID = "the_id";
private static final String CHANNEL_NAME = "Drink_Shop";
private NotificationManager notificationManager;
public NotificationHelper(Context base) {
super(base);
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
createChannel();
}
#TargetApi(Build.VERSION_CODES.O)
private void createChannel() {
NotificationChannel nc = new NotificationChannel(CHANNEL_ID,CHANNEL_NAME,
NotificationManager.IMPORTANCE_DEFAULT);
nc.enableLights(false);
nc.enableVibration(true);
nc.setLockscreenVisibility(Notification.VISIBILITY_PRIVATE);
getManager().createNotificationChannel(nc);
}
public NotificationManager getManager() {
if(notificationManager == null)
notificationManager = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
return notificationManager;
}
#TargetApi(Build.VERSION_CODES.O)
public Notification.Builder getDrinkShopNotification(String title,
String message,
Uri soundUri)
{
return new Notification.Builder(getApplicationContext(),CHANNEL_ID)
.setContentTitle(title)
.setContentText(message)
.setSmallIcon(R.mipmap.ic_launcher)
.setSound(soundUri)
.setChannelId(CHANNEL_ID)
.setColor(ContextCompat.getColor(this, R.color.colorAccent))
.setAutoCancel(true);
}
}
=============================Manifest=======================================
<service
android:name=".Services.MyFirebaseMessagingService"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
============================Build.gradle====================================
implementation 'com.google.firebase:firebase-messaging:20.0.0'
implementation 'com.google.firebase:firebase-core:17.2.1'
implementation 'com.google.android.gms:play-services-auth:17.0.0'
===========================IFCMService=======================================
public interface IFCMService {
#Headers({
"Content-Type:application/json",
"Authorization:mytoken"
})
#POST("fcm/send")
Call<MyResponse> sendNotification(#Body DataMessage body);
}
==========================sendNotificationToServer===============================
// this method used to send the notification to server app
private void sendNotificationToServer(OrderResult orderResult) {
mService.getToken("SERVER_01", "1")
.enqueue(new Callback<Token>() {
#Override
public void onResponse(Call<Token> call, Response<Token> response) {
Map<String,String> contentSend = new HashMap<>();
contentSend.put("title","NEW ORDER");
contentSend.put("message","You have got new order" + orderResult.getOrderId());
DataMessage dataMessage = new DataMessage();
if(response.body().getToken() != null)
dataMessage.setTo(response.body().getToken());
dataMessage.setData(contentSend);
IFCMService ifcmService = Common.getFCMService();
ifcmService.sendNotification(dataMessage)
.enqueue(new Callback<MyResponse>() {
#Override
public void onResponse(Call<MyResponse> call, Response<MyResponse> response) {
if(response.code() == 200){
if(response.body().success == 1){
Toast.makeText(CartActivity.this,
getResources().getString(R.string.order_submitted), Toast.LENGTH_SHORT)
.show();
//Clear Carts From Room Database
Common.cartRepository.emptyCart();
//finish();
}
else {
Toast.makeText(CartActivity.this, "Send Notification Failed", Toast.LENGTH_SHORT).show();
}
}
}
#Override
public void onFailure(Call<MyResponse> call, Throwable t) {
Toast.makeText(CartActivity.this, ""+t.getMessage(), Toast.LENGTH_SHORT).show();
}
});
}
#Override
public void onFailure(Call<Token> call, Throwable t) {
Toast.makeText(CartActivity.this, t.getMessage(), Toast.LENGTH_SHORT).show();
}
});
}
I think you are making the code unnecessarily complicated.
Try this below code
private void createNotification(String title, String message) {
NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
// only create notification channel if SDK >= 26
if (android.os.Build.VERSION.SDK_INT >= 26) {
NotificationChannel channel = new NotificationChannel(CHANNEL_ID, CHANNEL_NAME, NotificationManager.IMPORTANCE_DEFAULT);
channel.enableLights(false);
channel.enableVibration(true);
channel.setDescription(CHANNEL_DESC);
manager.createNotificationChannel(channel);
}
Uri defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
NotificationCompat.Builder builder = new NotificationCompat.Builder(this, CHANNEL_ID)
.setSmallIcon(android.R.drawable.stat_notify_more)
.setContentTitle(title)
.setSmallIcon(R.mipmap.ic_launcher)
.setSound(defaultSoundUri)
.setColor(ContextCompat.getColor(this, R.color.colorAccent))
.setContentText(message);
manager.notify(new Random().nextInt(), builder.build());
}
We have an Android mobile app, where you can purchase parking tickets for a period. Now, we are planning to integrate it with Android wear.
What we are doing here is:
We want the user to get notified 15 before of the expiry of ticket.
To do this, we create a local notification and schedule it using Alarm Manger.
This scheduled notification is received by Android Broadcast receiver and display this notification on mobile device in Android notification section.
Further, this receiver calls the intent service to send the notification to wear. In this step, we create googleApiClient and onConnected callback, we send the data to wear to show the notification.
On wear, user can check the notification and on tap, user can extend the time of purchased ticket. This flow contains 3-4 views after notification tapping.
We have issue in step 4. Most of the time, on a very first connection (notification), wear does not show the notification and on second connection (notification), wear show both first and second notification and after that it works fine.
We tried to figure out the problem, but no success. Below is the code snippet of Receiver, Intent Service and wear side ListnerServices for understanding.
public class WearNotificationService extends IntentService {
private static final String TAG = "PhoneActivity";
private GoogleApiClient mGoogleApiClient;
public static String title;
public static String desc;
public static String data;
public WearNotificationService() {
super("WearNotificationService");
}
#Override
public void onCreate() {
super.onCreate();
Toast.makeText(this, title +"--"+ desc , Toast.LENGTH_SHORT).show();
mGoogleApiClient = new GoogleApiClient.Builder(this).addConnectionCallbacks(new GoogleApiClient.ConnectionCallbacks() {
#Override
public void onConnected(Bundle connectionHint) {
sendNotification(title,desc,data);
Log.d(TAG, "onConnected: " + connectionHint);
}
#Override
public void onConnectionSuspended(int cause) {
Log.d(TAG, "onConnectionSuspended: " + cause);
}
}).addOnConnectionFailedListener(new GoogleApiClient.OnConnectionFailedListener() {
#Override
public void onConnectionFailed(ConnectionResult result) {
Log.d(TAG, "onConnectionFailed: " + result);
}
}).addApi(Wearable.API).build();
mGoogleApiClient.connect();
}
#Override
protected void onHandleIntent(Intent intent) {
}
private void sendNotification(String title,String desc,String data) {
Log.e(TAG, "i am onConnectiond: ");
PutDataMapRequest dataMapRequest = PutDataMapRequest.create(Constants.PATH_NOTIFICATION);
dataMapRequest.getDataMap().putDouble(Constants.NOTIFICATION_TIMESTAMP, System.currentTimeMillis());
dataMapRequest.getDataMap().putString(Constants.KEY_TITLE, title);
dataMapRequest.getDataMap().putString(Constants.KEY_DESC, desc);
dataMapRequest.getDataMap().putString(Constants.KEY_DATA, data);
PutDataRequest putDataRequest = dataMapRequest.asPutDataRequest();
Wearable.DataApi.putDataItem(mGoogleApiClient, putDataRequest);
}
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (null != intent) {
String action = intent.getAction();
if (Constants.ACTION_DISMISS.equals(action)) {
dismissNotification();
}
}
return super.onStartCommand(intent, flags, startId);
}
#Override
public void onDataChanged(DataEventBuffer dataEvents) {
for (DataEvent dataEvent : dataEvents) {
if (dataEvent.getType() == DataEvent.TYPE_CHANGED) {
if (Constants.PATH_NOTIFICATION.equals(dataEvent.getDataItem().getUri().getPath())) {
DataMapItem dataMapItem = DataMapItem.fromDataItem(dataEvent.getDataItem());
String title = dataMapItem.getDataMap().getString(Constants.KEY_TITLE);
String content = dataMapItem.getDataMap().getString(Constants.KEY_DESC);
String data = dataMapItem.getDataMap().getString(Constants.KEY_DATA);
String id = null;
try {
JSONObject obj = new JSONObject(data);
id = (String) obj.get("id");
} catch (JSONException e) {
e.printStackTrace();
}
sendNotification(title, content, data,id);
}
}
}
}
private void sendNotification(String title, String content, String data,String id) {
Intent notificationIntent = new Intent(this, HoursExtension.class);
Log.e("data1111", data);
HoursExtension.data = data;
HoursExtension.id = id;
PendingIntent notificationPendingIntent = PendingIntent.getActivity(this, 0, notificationIntent,0);
NotificationCompat.Builder builder = new NotificationCompat.Builder(this)
.setSmallIcon(R.drawable.icon)
.setContentTitle(title)
.setContentText(content)
.setContentIntent(notificationPendingIntent)
.extend(new NotificationCompat.WearableExtender().setBackground(BitmapFactory.decodeResource(getResources(), R.drawable.rtabg)))
;
Notification notification = builder.build();
NotificationManagerCompat notificationManagerCompat = NotificationManagerCompat.from(this);
notificationManagerCompat.notify(Integer.parseInt(id), notification);
}
I solved it by sending a dummy request on app installation . Which is send once the app is installed and handled in wear by eating that first request this solved my problem . :)