I want to create a constant notification on status bar (like current battery percents - it's always there), but the icon will be changed every day on 00:00.
In addition, I want this notification will alert automatically after rebooting the device and not only after the user opens the application.
I created the notification in MainActivity, but I don't know how to make it alert after rebooting and also I don't know how to change it every day at mid-night.
I tried to create AlarmService and broadcast reciever but it run every 5 seconds and it's far too much so I deleted it.
My current code is:
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this)
.setContentTitle(getString(R.string.notificationTitle))
.setContentText(....)
.setLargeIcon(largeIconBitmap)
.setSmallIcon(getResources().getIdentifier("icon_status_" + myHelper.getCurrentImageNumber(),"drawable", getPackageName())); // change the icon at mid-night. 'getCurrentImageNumber' should get me the right icon number
Intent resultIntent = new Intent(this, MainActivity.class);
PendingIntent resultPendingIntent = PendingIntent.getActivity(this,0,resultIntent,PendingIntent.FLAG_UPDATE_CURRENT);
mBuilder.setContentIntent(resultPendingIntent);
Notification notification = mBuilder.build();
notification.flags |= Notification.FLAG_NO_CLEAR | Notification.FLAG_ONGOING_EVENT;
mNotifyMgr = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
mNotifyMgr.notify(mylHelper.myRequestCode, notification);
Right now I see a notification, but the icon doesn't change and it does not alarm after reboot. I saw some answers in stackoverflow but nothing helped me.
I wont give you all the code, you will need to learn by doing.
Here is what you should do:
1 Use a Service to launch your notification and maintain the logic to updating it. If the notification already exists you can update the existing one or programmatically dismiss it and replace with a new one.
2 Register a broadcast receiver in AndroidManifest.xml with multiple intent filters to launch your service.
<receiver android:name=".myReceiver">
<intent-filter>
<action android:name="android.intent.action.TIME_TICK" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
3 Create class which extends the broadcast receiver class and use and launch the above service.
Related
I have an app hooked with push notifications. When the user click on the notification, I want a broadcast receiver to be triggered instead of an activity.
I looked at these threads and looks like this is perfectly possible and common.
Android Notification Action is not fired (PendingIntent)
Send broadcast on notification click
However I can't get it to work. I see the notification, but when I click on it and it never triggers my Broadcast receiver.
Here what I have tried:
I created a custom receiver:
public class NotificationOnClickReceiver extends BroadcastReceiver {
#Override
public void onReceive(final Context context, Intent intent) {
Log.d(Constants.Engine.LOGGER_TAG_GCM,
NotificationOnClickReceiver.class.toString() + " triggered");
}
}
I registered this receiver dynamically on my global Application (not activity)
mNotificationOnClickReceiver = new NotificationOnClickReceiver();
IntentFilter intentFilterOnClick = new IntentFilter(Constants.Engine.BROADCAST_RECEIVER_FILTER_NOTIFICATION_ONCLICK);
getApplicationContext().registerReceiver(mNotificationOnClickReceiver, intentFilterOnClick);
Log.e(Constants.Engine.LOGGER_TAG_DBG, "mNotificationOnClickReceiver = " + mNotificationOnClickReceiver.toString());
The filter is just a string constant (I wonder if this is the problem)
public static final String BROADCAST_RECEIVER_FILTER_NOTIFICATION_ONCLICK = "push_notification.onclick";
Receiver intent setup:
// When the user taps on the notification bar, this is the receiver that I want to be called
Intent pushNotificationIntent;
Log.e(Constants.Engine.LOGGER_TAG_DBG, "Notification called!");
pushNotificationIntent = new Intent(this, NotificationOnClickReceiver.class);
// Not sure if this causing the problem
pushNotificationIntent.setAction(Constants.Engine.BROADCAST_RECEIVER_FILTER_NOTIFICATION_ONCLICK);
// ensures that each notification and intent are unique
int uniqueCode = new Random().nextInt(Integer.MAX_VALUE);
PendingIntent pendingIntent = PendingIntent.getBroadcast(
context,
uniqueCode,
pushNotificationIntent, // Receiver Intent
PendingIntent.FLAG_CANCEL_CURRENT);
Uri defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(context)
.setSmallIcon(mIconId)
.setContentTitle(context.getString(R.string.myString))
.setContentText("My GCM Alert!")
.setAutoCancel(true)
.setSound(defaultSoundUri)
.setContentIntent(pendingIntent);
From the logs, things seem to work except that my Broadcast receiver never gets called:
02-22 15:47:47.092 16863-16863/com.myapp.test E/MYAPP_DBG: mNotificationOnClickReceiver = mytest.broadcastreceivers.NotificationOnClickReceiver#d78f559
02-22 15:47:53.312 16863-17038/com.myapp.test E/MYAPP_DBG: Notification called!
If anyone has this working, can you point me out a sample code? I don't see where my bug is.
thank you!
This would appear to be the problem:
pushNotificationIntent = new Intent(this, NotificationOnClickReceiver.class);
You're actually creating an explicit Intent for the broadcast PendingIntent. Explicit Intents do not work with dynamically registered Receivers, as they target a Receiver class, rather than an instance.
You'll need to use an implicit Intent instead, which you can do by simply instantiating the Intent with the action String, rather than a Context and Class. For example:
pushNotificationIntent = new Intent(Constants.Engine.BROADCAST_RECEIVER_FILTER_NOTIFICATION_ONCLICK);
Please note that if your app's process is killed before the Notification is clicked, that dynamically registered Receiver instance will die, too, and the Notification's broadcast won't really do anything.
Depending on the desired behavior, it might be preferable to instead statically register your Receiver class in the manifest, and stay with the explicit Intent. Doing this will allow your app to receive the Notification broadcast even if its process has been killed.
To do that, you'd just need to add a <receiver> element for your NotificationOnClickReceiver in the manifest.
<receiver android:name="NotificationOnClickReceiver" />
Though you can still set an action on that broadcast Intent, you don't need an <intent-filter> for it here, as the explicit Intent is directly targeting the class anyway. If the Receiver is only for that one function, you don't necessarily need the action, and can just remove that altogether.
You can then remove the code you have in step 2, as you'd no longer need the dynamically registered instance.
To send a broadcast use this sendBroadcast(new Intent("NotificationClicked"));
Now to recieve the broadcast, mention this in your manifestunder application tag
<receiver android:name=".NotificationOnClickReceiver" >
<intent-filter>
<action android:name="NotificationClicked" >
</action>
</intent-filter>
</receiver>
I implemented FCM in my project. Push notification is working as expected, onMessageReceived is called when a notification is received. This is true when app is in the foreground.
However, when the app is in the background, the system tray always display a duplicate notification when one arrives (e.g. when Notification A is received, system tray display 2 Notification A)
How to fix this?
EDIT: added code
I extended FirebaseMessagingService class and have this in the onMessageReceived method
This is the only part in the project where I used NotificationManager.
Also, I tried to add a log on this method. onMessageReceived is called when app is in foreground. It doesn't get called when app is in background
#Override
public void onMessageReceived(RemoteMessage remoteMessage)
{
RemoteMessage.Notification notification = remoteMessage.getNotification();
Intent intent = new Intent(this, MainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0 /* Request code */, intent,
PendingIntent.FLAG_ONE_SHOT);
String title = notification.getTitle();
String message = notification.getBody();
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this)
.setSmallIcon(R.mipmap.ic_launcher)
.setContentTitle(title)
.setContentText(message)
.setAutoCancel(true)
.setDefaults(Notification.DEFAULT_SOUND | Notification.DEFAULT_VIBRATE)
.setContentIntent(pendingIntent);
NotificationManager notificationManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(0, notificationBuilder.build());
}
Same problem. I modified AndroidManifest.xml because i was requesting permissions to old GCM like this...
<uses-permission android:name="mypackage.permission.C2D_MESSAGE" />
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
<permission
android:name="mypackage.permission.C2D_MESSAGE"
android:protectionLevel="signature" />
So, removing it from manifest and uninstalling and reinstalling the app my problem was solved.
To handle push notifications manually use handleIntent(intent) of FirebaseMessagingService.
This method gets called when application is in foreground, background and killed state. To avoid the duplication, do not call super.handleIntent(intent). This will prevent the automatic push notification when app in BG or killed state.
This worked for me.
I was having the exact same 'duplicate' problem. This may be just a workaround because I couldn't get notifications behaving when app was in foreground without the 'duplicate' problem happening. Instead I implemented a WakefulBroadcastReceiver, when toggling the android:exported to "false" it started behaving.
AndroidManifest.xml
<receiver
android:name="PACKAGE.MyWakefulBroadcastReceiver"
android:exported="false">
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
</intent-filter>
</receiver>
MyWakefulListenerService.java
public class MyWakefulBroadcastReceiver extends WakefulBroadcastReceiver {
private final String TAG = "MyWakefulListener";
public void onReceive(Context context, Intent intent) {
sendNotification(context);
}
}
Goal
Mobile app with Parse's back-end
User creates message to all/admins/specific users
The "recipients" get notification that they have new message
When the notification is clicked, details about the message are displayed
Current approach
I create a custom push in the afterSave cloud code method. The call looks like this:
Parse.Push.send({
where : query,
data : {
action : "com.acme.CUSTOM_ACTION_GOES_HERE",
content : messageContent
}
}).then(...
(The query is defined to get specific Parse.Installation objects.)
In Android app, I have a BroadcastReceiver registered like this
<receiver
android:name=".MyBroadcastReceiver"
android:exported="false" >
<intent-filter>
<action android:name="com.acme.CUSTOM_ACTION_GOES_HERE" >
</action>
</intent-filter>
</receiver>
In the onReceive method of the broadcastreceiver, I create custom notification where I also define the pending intent starting an activity when the notification is clicked:
Intent contentIntent = new Intent(context, DisplayDetailsActivity.class);
TaskStackBuilder stackBuilder = TaskStackBuilder.create(context);
stackBuilder.addParentStack(DisplayDetailsActivity.class);
stackBuilder.addNextIntent(contentIntent);
PendingIntent pendingIntent = stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);
Notification noti = new Notification.Builder(context)
.setContentTitle("New message")
.setContentText(content)
.setSmallIcon(R.drawable.ic_stat_notify_message)
.setNumber(notificationsCount)
.setContentIntent(pendingIntent)
.setAutoCancel(true)
.build();
noti.defaults |= Notification.DEFAULT_SOUND;
NotificationManager mgr = (NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE);
mgr.notify(555, noti);
Problem
Without calling (e.g. in application's onCreate method)
PushService.setDefaultPushCallback(getApplicationContext(), SomeActivity.class);
... the pushes are not delivered to the device
When using that call, the activity SomeActivity is started when the notification is clicked instead of the activity DisplayDetailsActivity set in the intent in the broadcast receiver.
When I have just one type of custom notification, it is possible to call the setDefaultPushCallback with the DisplayDetailsActivity.class as second parameter.
However, I plan to have multiple different custom notifications, and clicking each of them should start different activity. In such case the workaround mentioned above is not viable option any more.
Any ideas how to solve this?
After working on this for a few hours I stumbled upon this post, I started from #pareshgoel workaround, the basic idea is to remove the need to register an Activity or subscribe to a Channel if it is not required and also lower the server requests for the Installation class.
I took the Parse-1.5.1.jar, from Parse.com and using JD-GUI I looked in PushService.setDefaultPushCallback(Context context, Class<? extends Activity> cls).
What it does is
if cls is null remove subscription;
create subscription for new cls;
call PushService.startServiceIfRequired
The function PushService.startServiceIfRequired starts parse push service if GCM is not supported on the device or sends a registration request to GCM, waits for the registration_id, and upon arrival updates the installation device token.
My workaround is to use : PushService.startServiceIfRequired - which doesn't seem to be documented, you can use if after the initialize or if you have users after login/signup, as it is using a background task it can be called on the main thread.
Another advantage is that using PushService.startServiceIfRequired you have 2 server requests to save/update the Installation class, first one sets push type to GCM and the second sets pushtype to GCM, sets device token to registration_id. PushService.setDefaultPushCallback introduces an initial server request.
I faced the same issue, and have a workaround.
First of all setDefaultPushCallback needs to be called to have Parse push notification working. This is most likely a bug n Parse. I am on Parse Android 1.5.1 .
The workaround is to not set the "alert" param in the parse push notification send code.
If this is not set, then Parse will not display the alert on its own, and your custom broadcast receiver could handle the push.
Push notification in Parse need some more bug fixing before it could be reliably used.
I am experiencing a strange behavior with my android application when dealing with a notification that is created from a BroadcastReceiver when a C2DM message arrives on the mobile device. The flow I am executing to experience this behavior is the following one:
Start my application, DashboardActivity is displayed;
Close application either by pressing home button or back button;
Receive the push message and create the notification;
Click the notification item and the activity BookingOfferActivity is launched;
Close the BookingOfferActivity either by pressing home or back button or calling finish()
Long press home button and select my application from recent applications
BookingOffcerActivity is displayed instead of DashboardActivity
The BookingOfferActivity is being launched from the notification using the following code:
Intent notificationIntent = new Intent(context, BookingOfferActivity.class);
notificationIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
Bundle b = new Bundle();
b.putSerializable("booking", booking);
notificationIntent.putExtras(b);
PendingIntent contentIntent = PendingIntent.getActivity(context, 0, notificationIntent, 0);
Notification notification = new Notification(icon, tickerText, when);
notification.setLatestEventInfo(context, contentTitle, contentText, contentIntent);
long[] vibrate = {0,100,200,300};
notification.vibrate = vibrate;
notification.flags = Notification.FLAG_AUTO_CANCEL;
NotificationManager mNotificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
mNotificationManager.notify(AppUtil.getNextPushIndexBooking(), notification);
BookingOfferActivity is defined in the AndroidManifest this way:
<activity android:name=".activity.BookingOfferActivity"
android:label="#string/app_name"
android:screenOrientation="portrait" />
and my DashboardActivity is defined like this:
<activity android:name=".activity.DashboardActivity"
android:label="#string/app_name"
android:configChanges="orientation|keyboardHidden"
android:windowSoftInputMode="stateHidden|adjustPan">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
The reason I am calling it a strange behavior is that I would like to start DashboardActivity whenever my application is started or restarted by the user, not by the notification item. So after closing, finishing or destroying BookingOfferActivity and reopening by application by accessing recent opened application (long press on home button) or accessing the launcher icon on the application list, I would like to see the Dashboard.
I create a question similar to this one but I didnt provide too much details, so I closed the other one and opened this one with more data.
Many thanks for any guidance on how to solve this problem
T
I'm not sure, but I suppose that in your scenario second activity just go to the top of activity stack and will be shown until application wont be killed. We have approximately same problem and solv it in easy way: Notification start main(first) activity with extra "go to second immediately". in onCreate of first activity check this extra and start second activity if needed. With this solution you should be careful with pressing back button - if you dont want to show first activity in case of "notification start" you should care about it in onResume of first activity
is there a way to awake already running app from the notification bar after c2dm message?
i have this app that is registered with c2dm servers that receives push notifications from my server to do some processing. so after i receive c2dm message from my server, it displays the status bar notification to the user, user expands the notifications and clicks on my app, brings it up.
all is good but if this app was already running before (stared from the icon) this would load another instance of my app into memory. also some of the things are crashing in it. i already changed the android:launchMode="singleTop" on all my activities, i tried using intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP) in my notification and no luck. i always end up with 2 apps running.
any help is appreciated
here my static function that i use to create a notification after i receive the c2dm message:
public static void notifyStart(Context context, String notificationText) {
//notification
String ns = Context.NOTIFICATION_SERVICE;
NotificationManager mNotificationManager = (NotificationManager) context.getSystemService(ns);
int icon = R.drawable.icon_notify;
CharSequence tickerText = notificationText;
long when = System.currentTimeMillis();
Notification notification = new Notification(icon, tickerText, when);
notification.ledARGB = 0xff00ff00;
notification.ledOnMS = 400;
notification.ledOffMS = 400;
notification.flags |= Notification.FLAG_SHOW_LIGHTS;
notification.defaults |= Notification.DEFAULT_SOUND;
CharSequence contentTitle = "App Name";
CharSequence contentText = notificationText;
Intent notificationIntent = new Intent(context, home.class);
notificationIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
PendingIntent contentIntent = PendingIntent.getActivity(context, 0, notificationIntent, 0);
notification.setLatestEventInfo(context, contentTitle, contentText, contentIntent);
mNotificationManager.notify(1350, notification);
}
and here is my home activity:
<activity android:name=".home"
android:label="#string/app_name"
android:theme="#android:style/Theme.NoTitleBar"
android:launchMode="singleTop" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
guys, i am very sorry but it was my fault :| couple of days ago i decided to change the name of the package of my app and forgot to remove the old app from the phone. i didn't realize that it would cause two separate installations on my phone, the task manager displays only app name so it did look like there were two instances of the same app, in fact there was one instance of each ;) sorry about trouble and appreciate your willingness to help :)
Android documentation says:
As shown in the table below, the modes fall into two main groups, with "standard" and "singleTop" activities on one side, and "singleTask" and "singleInstance" activities on the other. An activity with the "standard" or "singleTop" launch mode can be instantiated multiple times. The instances can belong to any task and can be located anywhere in the activity stack. Typically, they're launched into the task that called startActivity() (unless the Intent object contains a FLAG_ACTIVITY_NEW_TASK instruction, in which case a different task is chosen — see the taskAffinity attribute).
In contrast, "singleTask" and "singleInstance" activities can only begin a task. They are always at the root of the activity stack. Moreover, the device can hold only one instance of the activity at a time — only one such task.
so it seems (though I haven't checked) that singleInstance is what you're looking for.
see: http://bit.ly/gH8SBb