I am showing a notification from a library attached to my project, when clicked on the notification, the notification takes to an Activity (ReceivingActivity). Activity opens after clicking the notification ,but the extras attached to it are not received.
Notification triggering code - I call sendNotification when i receive a gcm message and Notification code is in the library
public static final int NOTIFICATION_ID = 1;
private NotificationManager mNotificationManager;
NotificationCompat.Builder builder;
private void sendNotification(Bundle extras) {
mNotificationManager = (NotificationManager)
this.getSystemService(Context.NOTIFICATION_SERVICE);
Intent redirectIntent = new Intent(this, Class.forName("com.xyz.kljdf.ReceivingActivity"));
redirectIntent.putExtra("key", "value"); // These extras are not received in ReceivingActivity onCreate(), see the code below
PendingIntent contentIntent = PendingIntent.getActivity(this, 0,
redirectIntent, 0);
NotificationCompat.Builder mBuilder =
new NotificationCompat.Builder(this)
.setSmallIcon(((Context)this).getResources().getIdentifier("icon", "drawable", getPackageName()))
.setContentTitle(extras.getString(PushConstants.TITLE))
.setStyle(new NotificationCompat.BigTextStyle()
.bigText(extras.getString(PushConstants.ALERT)))
.setContentText(extras.getString(PushConstants.ALERT));
mBuilder.setContentIntent(contentIntent);
mNotificationManager.notify(NOTIFICATION_ID, mBuilder.build());
}
Checking the extras in the ReceivingActivity...
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_receiving);
Log.i("extras..... ######", getIntent().getExtras().toString()); //NPE here
}
I need help in figuring out how to pass the extras and receive them correctly.
Make sure the PendingIntent is actually passing the data when it's called. See this answer for an explanation: https://stackoverflow.com/a/3851414/1426565
For anyone else, if you're positive the intent already exists and is just brought to the front, the new Intent's data won't be passed to it by default. You can override onNewIntent(Intent) in order to get around that:
#Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
setIntent(intent); // Set the new Intent's data to be the currently passed arguments
}
Related
My app repeatedly loads data from a server. Among those data are messages.
Whenever new messages are loaded, the MainActivity is called on an Interface's callback method onMessagesReceived(int numOfMessages).
The app has only one Activity and every screen is implemented as a Fragment. Switching of Fragments is managed by a dedicated Navigator class.
My problem is the handling of the user tapping on the Notification. When the user taps on the Notification, the message list should be shown.
public class MainActivity extends AppCompatActivity implements MessageListener {
private static final int MESSAGE_NOTIFICATION_ID = 101010;
private static final String EXTRA_SHOW_MESSAGES = "SHOW_MESSAGES";
private Navigator mNavigator;
#Override
onMessagesReceived(int numOfMessages) {
Intent intent = new Intent(this, MainActivity.class);
testIntent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
testIntent.putExtra(EXTRA_SHOW_MESSAGES, true);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, 0);
NotificationCompat.Builder builder = new NotificationCompat.Builder(this, "testChannel")
.setSmallIcon(R.drawable.ic_message_notification)
.setContentTitle("New messages!")
.setContentText("You got " + numOfMessages + " new messages")
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
.setContentIntent(pendingIntent);
NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this);
notificationManager.notify(MESSAGE_NOTIFICATION_ID, builder.build());
}
#Override
protected void onResume() {
super.onResume();
Bundle extras = getIntent().getExtras();
if (extras != null && extras.containsKey(EXTRA_SHOW_MESSAGES)) {
if (extras.getBoolean(EXTRA_SHOW_MESSAGES)) {
mNavigator.openMessageList();
}
}
}
}
At the moment, the MainActivity shows up, when the app is in background, but in onResume, the Bundle returns as null.
When the app is in the foreground, nothing happens at all.
I want to achieve on a click on the Notification:
- When the user is inside the app, the MessageList Fragment should be opened
- When the user is not inside the app, it should be started before opening the MessageList Fragment
Can someone give me a hint, how to proceed from here? Maybe using Intents isn't the right solution here?
You can use intents just put some boolean extras in intent an just check the value in main activity if that extra value is true then call your method.
After some more digging on Intents and Notifications, I finally came up with a solution.
public class MainActivity extends AppCompatActivity implements MessageListener {
private static final int MESSAGE_NOTIFICATION_ID = 101010;
private static final String EXTRA_SHOW_MESSAGES = "SHOW_MESSAGES";
private Navigator mNavigator;
#Override
onMessagesReceived(int numOfMessages) {
Intent intent = new Intent(this, MainActivity.class);
testIntent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
testIntent.putExtra(EXTRA_SHOW_MESSAGES, true);
PendingIntent pendingIntent = PendingIntent.getActivity(
this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
NotificationCompat.Builder builder = new NotificationCompat.Builder(this, "testChannel")
.setSmallIcon(R.drawable.ic_message_notification)
.setContentTitle("New messages!")
.setContentText("You got " + numOfMessages + " new messages")
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
.setContentIntent(pendingIntent);
NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this);
notificationManager.notify(MESSAGE_NOTIFICATION_ID, builder.build());
}
#Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
this.setIntent(intetnt)
Bundle extras = intent.getExtras();
if (extras != null && extras.containsKey(EXTRA_SHOW_MESSAGES)) {
if (extras.getBoolean(EXTRA_SHOW_MESSAGES)) {
mNavigator.openMessageList();
}
}
}
}
I moved my code, reading the new Intent, to onNewIntent. This method gets called, when an Activity gets a new Intent and before onResume. This triggers regardless of the Activity being in the foreground or not. I also set this new Intent to be the Activities Intent with setIntent, otherwise the Intent that initialy started my Activity, is called by getIntent().
I am developing a flashLight app and I faced a problem in notification which is : When I press the notification text I want to turn of flash and close the whole app , How can I modified the notification method to do that ??
I tried to make anthor activity and put turn of and close app methods in it, but it does not work .
please help and thanks in advance .
this is my notification method
public void getNotification()
{
Intent intent = new Intent();
PendingIntent pIntent = PendingIntent.getActivity(this, 0, intent , PendingIntent.FLAG_CANCEL_CURRENT);
NotificationCompat.Builder builder = new NotificationCompat.Builder(this)
.setContentIntent(pIntent)
.setContentTitle(res.getString(R.string.notification_title))
.setContentText(res.getString(R.string.notification_text))
.setSmallIcon(R.drawable.icon)
.setAutoCancel(true)
.setTicker(getString(R.string.notification_ticker_msg));
// Build the notification:
Notification notification = builder.build();
// Get the notification manager:
NotificationManager notificationManager = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
// Publish the notification:
final int notificationId = 0;
notificationManager.notify(notificationId, notification);
}
If you use the same Activity, then the onCreate method will be called again. You can send one extra with your Intent that indicates it is an Intent generated from the click of notification. In your Activity onCreate, check for this extra and call finish() if it is present.
public void getNotification() {
Intent intent = new Intent(this, FlashActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
intent.putExtra("origin", "notification");
PendingIntent pIntent = PendingIntent.getActivity(this, 0, intent , PendingIntent.FLAG_CANCEL_CURRENT);
NotificationCompat.Builder builder = new NotificationCompat.Builder(this)
.setContentIntent(pIntent)
.setContentTitle(res.getString(R.string.notification_title))
.setContentText(res.getString(R.string.notification_text))
.setSmallIcon(R.drawable.icon)
.setAutoCancel(true)
.setTicker(getString(R.string.notification_ticker_msg));
// Build the notification:
Notification notification = builder.build();
// Get the notification manager:
NotificationManager notificationManager = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
// Publish the notification:
final int notificationId = 0;
notificationManager.notify(notificationId, notification);
}
And in your onCreate method in FlashActivity check the extra.
#Override
public void onCreate(Bundle savedInstanceState) {
...
if("notification".equals(getIntent().getStringExtra("origin"))) {
finish();
}
}
I believe you can use finish() on your Activity when the notification ils pressed.
EDIT: How to close any activity of my application by clicking on a notification?
You want to use PendingIntent.
Intent resultIntent = new Intent(this, MainActivity.class);
resultIntent.putExtra("FINISH",true);
PendingIntent resultPendingIntent =
PendingIntent.getActivity(
this,
0,
resultIntent,
PendingIntent.FLAG_UPDATE_CURRENT
);
builder.setContentIntent(resultPendingIntent);
// Build the notification:
Notification notification = builder.build();
//rest of your methods to show notification
In your MainActivity update depending on your code
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
onNewIntent(getIntent());
}
#Override
public void onNewIntent(Intent intent){
setContentView(R.layout.activity_main);
Bundle extras = intent.getExtras();
if(extras != null){
if(extras.containsKey("FINISH"))
{
finish();
}
}
}
Not able to identify id for item clicked on notification was for unique id which is working out well,now for the same even with different id when i click on notifications i get unique invoice id ,which i am passing to a webservice to get its invoice details,even though its fetching data for that id,the itemActivity page is showing previous details only,how will i update the page with new contents ?
Send Notification code is
public class SampleSchedulingService extends IntentService {
public SampleSchedulingService() {
super("SchedulingService");
}
List<GetReminder> newReminderList;
int invoiceId=0;
String remMes;
InvoiceData1 data1;
int InvM_Id;
public static final String TAG = "Scheduling Demo";
// An ID used to post the notification.
public static int NOTIFICATION_ID = 1;
private NotificationManager mNotificationManager;
NotificationCompat.Builder builder;
#Override
protected void onHandleIntent(Intent intent) {
// BEGIN_INCLUDE(service_onhandle)
// The URL from which to fetch content.
Log.d("MyService", "About to execute MyTask");
//
newReminderList=WebService.invokeGetReminderWS("GetReminder",41);
if(newReminderList!=null){
for(int i=0;i<newReminderList.size();i++) {
sendNotification(newReminderList.get(i).getRemMessage(),newReminderList.get(i).getInvM_Id());
}
}
// Release the wake lock provided by the BroadcastReceiver.
SampleAlarmReceiver.completeWakefulIntent(intent);
// END_INCLUDE(service_onhandle)
}
// Post a notification indicating whether a doodle was found.
private void sendNotification(String msg, int invM_id) {
try {
Intent notificationIntent = new Intent(this, ItemActivity.class);
notificationIntent.setAction(Intent.ACTION_MAIN);
notificationIntent.addCategory(Intent.CATEGORY_LAUNCHER);
data1=WebService.InvoiceDetailForExeedDiscount1(invM_id);
notificationIntent.putExtra("invoiceList", data1);
notificationIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
PendingIntent contentIntent = PendingIntent.getActivity(this, NOTIFICATION_ID, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT);
mNotificationManager = (NotificationManager)
this.getSystemService(Context.NOTIFICATION_SERVICE);
NotificationCompat.Builder mBuilder =
new NotificationCompat.Builder(this)
.setSmallIcon(R.drawable.ic_launcher)
.setContentTitle(getString(R.string.invoice_alert))
.setStyle(new NotificationCompat.BigTextStyle()
.bigText(msg))
.setContentText(msg);
mBuilder.setContentIntent(contentIntent);
mNotificationManager.notify(NOTIFICATION_ID, mBuilder.build());
NOTIFICATION_ID++;}
catch (IOException e) {
} catch (XmlPullParserException e) {
}
}
}
and itemActivity i am reading data like
public class ItemActivity extends Activity implements View.OnClickListener {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
final boolean customTitleSupported =
requestWindowFeature(Window.FEATURE_CUSTOM_TITLE);
setContentView(R.layout.itemlist);
if(customTitleSupported){
getWindow().setFeatureInt(Window.FEATURE_CUSTOM_TITLE,R.layout.item);
}
InvoiceData1 invoiceList = (InvoiceData1) getIntent().getSerializableExtra("invoiceList");
}
its like when we come out of the application and click on second notification,its just blandly showing the invoice details of previous one,der is no call going on to fetch data for clicked on.
As you are using FLAG_ACTIVITY_SINGLE_TOP flag in your PendingIntent you must also implement onNewIntenet() method in ItemActivity to properly handle this launch mode. As per documentation:
This is called for activities that set launchMode to "singleTop" in
their package, or if a client used the FLAG_ACTIVITY_SINGLE_TOP flag
when calling startActivity(Intent). In either case, when the activity
is re-launched while at the top of the activity stack instead of a new
instance of the activity being started, onNewIntent() will be called
on the existing instance with the Intent that was used to re-launch
it.
An activity will always be paused before receiving a new intent, so
you can count on onResume() being called after this method.
Note that getIntent() still returns the original Intent. You can use
setIntent(Intent) to update it to this new Intent.
so it should be sufficient to move some code from your onResume() and limit onNewIntent() implementation to single setIntent() call.
I have been searching a lot of questions and answers in stackoverflow. I am still not able to solve my problem.
I set broadcast for a particular time.
I receive the broadcast perfectly in another class 'AlarmReceiver.java' which creates notification on receiving broadcast.
But I pass a string through an intent that calls a class 'AlarmResponder.java' on pressing the notification.
The class is getting called.
I receive the String data i passed through the intent only for the first time.
Next time I dont get anything. getextras() gives me null .
If i change the ID of the notification in NotificationManager.notify(1, mBuilder.build()); as
NotificationManager.notify(2, mBuilder.build()); it works .
But always it works only once
Please help me
public class AlarmReceiver extends BroadcastReceiver{
#Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
CharSequence reminderText = intent.getCharSequenceExtra("reminderText");
if (reminderText != null && reminderText != "") {
Uri notification = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
Ringtone r = RingtoneManager.getRingtone(context, notification);
r.play();
//Toast.makeText(context, intent.getCharSequenceExtra("reminderText"), Toast.LENGTH_LONG).show();
NotificationCompat.Builder mBuilder =
new NotificationCompat.Builder(context)
.setSmallIcon(R.drawable.ic_launcher)
.setContentTitle(reminderText)
.setContentText("its time buddy");
// Creates an explicit intent for an Activity in your app
Intent resultIntent = new Intent(context, AlarmResponder.class);
resultIntent.putExtra("reminderText", reminderText);
resultIntent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP);
// The stack builder object will contain an artificial back stack for the
// started Activity.
// This ensures that navigating backward from the Activity leads out of
// your application to the Home screen.
TaskStackBuilder stackBuilder = TaskStackBuilder.create(context);
// Adds the back stack for the Intent (but not the Intent itself)
stackBuilder.addParentStack(AlarmResponder.class);
// Adds the Intent that starts the Activity to the top of the stack
stackBuilder.addNextIntent(resultIntent);
PendingIntent resultPendingIntent =
stackBuilder.getPendingIntent(
0,
PendingIntent.FLAG_UPDATE_CURRENT
);
mBuilder.setContentIntent(resultPendingIntent);
NotificationManager mNotificationManager =
(NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
// mId allows you to update the notification later on.
mNotificationManager.notify(1, mBuilder.build());
}
}
}
and the AlarmResponder class is
public class AlarmResponder extends Activity{
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
onNewIntent(getIntent());
}
#Override
public void onNewIntent(Intent intent){
Bundle extras = intent.getExtras();
if(extras != null){
if(extras.containsKey("reminderText"))
{
setContentView(R.layout.alarm_responder);
TextView reminderText = (TextView) findViewById(R.id.reminderText);
// extract the extra-data in the Notification
String msg = extras.getString("reminderText");
reminderText.setText(msg);
}
}
}
}
I'm trying to implement a GCM client & server architecture. Everything works fine so far.
Except: When my activity is closed and I get a new notification by GCM, the notification is displayed in the notification bar. So far, so good. But when I click on the notification, my activity is opened but the onReceive event of my BroadcastReceiver is not triggered. :(
If the Activity is open, the onReceive is triggered perfectly.
Do you know, what's wrong here?
Cheers
Chris
So this is my service:
package xy;
import ...;
public class GcmIntentService extends IntentService
{
private NotificationManager mNotificationManager;
NotificationCompat.Builder builder;
public GcmIntentService()
{
super("GcmIntentService");
}
#Override
protected void onHandleIntent(Intent intent)
{
Bundle extras = intent.getExtras();
GoogleCloudMessaging gcm = GoogleCloudMessaging.getInstance(this);
String messageType = gcm.getMessageType(intent);
if (!extras.isEmpty()) { // has effect of unparcelling Bundle
final int notificationID = (int) (Math.random() * 100000000);
if (GoogleCloudMessaging.MESSAGE_TYPE_SEND_ERROR.equals(messageType)) {
sendNotification("GCM notification: Send error", extras.toString(), notificationID);
} else if (GoogleCloudMessaging.MESSAGE_TYPE_DELETED.equals(messageType)) {
sendNotification("Deleted messages on server", extras.toString(), notificationID);
// If it's a regular GCM message, do some work.
} else if (GoogleCloudMessaging.MESSAGE_TYPE_MESSAGE.equals(messageType)) {
sendNotification(extras.getString(Utils.TICKER_TITLE_MESSAGE_KEY), extras
.getString(Utils.TICKER_TEXT_MESSAGE_KEY), notificationID);
Intent intentToBroadCast = new Intent(Utils.DISPLAY_MESSAGE_ACTION);
intentToBroadCast.putExtra(Utils.MESSAGE_EXTRA_BUNDLE_KEY, extras);
intentToBroadCast.putExtra(Utils.NOTIFICATION_ID_KEY, notificationID);
sendBroadcast(intentToBroadCast);
}
}
// Release the wake lock provided by the WakefulBroadcastReceiver.
GcmBroadcastReceiver.completeWakefulIntent(intent);
}
private void sendNotification(final String aTitle, final String aText, final int aNotificationID)
{
mNotificationManager = (NotificationManager) this
.getSystemService(Context.NOTIFICATION_SERVICE);
PendingIntent contentIntent = PendingIntent.getActivity(this, 0, new Intent(this,
DemoActivity.class), 0);
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this).setSmallIcon(
R.drawable.ic_stat_gcm).setContentTitle(aTitle).setStyle(
new NotificationCompat.BigTextStyle().bigText(aText)).setContentText(aText);
mBuilder.setContentIntent(contentIntent);
mNotificationManager.notify(aNotificationID, mBuilder.build());
}
}
And here's the Receiver in my activity, which is to display the incoming message:
public class GcmResultReceiver extends BroadcastReceiver
{
#Override
public void onReceive(Context context, Intent intent)
{
Bundle extras = intent.getBundleExtra(Utils.MESSAGE_EXTRA_BUNDLE_KEY);
String s = extras.getString(Utils.CONTENT_TITLE_MESSAGE_KEY) + "\n"
+ extras.getString(Utils.CONTENT_TEXT_MESSAGE_KEY);
mDisplay.setText(s);
int notificationID = intent.getIntExtra(Utils.NOTIFICATION_ID_KEY, -1);
if (-1 != notificationID) m_SentNotificationIDs.add(notificationID);
if (m_IsVisible) {
clearNotifications();
}
}
};
Everything was copied and adapted from the GCM example from the Google Android tutorial.
The BroadcastReceiver is triggered before the notification is displayed in the notification bar. It contains the code that displays the notification and opens the activity when it is tapped (unless it is starting an intent service that does that work).
Therefore, if you see the notification, it means the BroadcastReceiver was triggered.
You don't need an additional BroadcastReceiver for passing the notification data from the first receiver to your app. If you wish to pass the notification data to the Activity that is being launched when the notification is tapped, you can pass it to the intent used to launch that activity.
Suppose you change your sendNotification call to:
sendNotification(extras, notificationID);
Then you can implement it like this:
private void sendNotification(Bundle extras, final int aNotificationID)
{
mNotificationManager = (NotificationManager) this
.getSystemService(Context.NOTIFICATION_SERVICE);
Intent demoIntent = new Intent(this, DemoActivity.class);
demoIntent.putExtras (extras);
demoIntent.putExtra (Utils.NOTIFICATION_ID_KEY, notificationID);
PendingIntent contentIntent = PendingIntent.getActivity(this, 0, demoIntent, 0);
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this).setSmallIcon(
R.drawable.ic_stat_gcm).setContentTitle(extras.getString(Utils.TICKER_TITLE_MESSAGE_KEY)).setStyle(
new NotificationCompat.BigTextStyle().bigText(extras.getString(Utils.TICKER_TEXT_MESSAGE_KEY))).setContentText(extras.getString(Utils.TICKER_TEXT_MESSAGE_KEY));
mBuilder.setContentIntent(contentIntent);
mNotificationManager.notify(aNotificationID, mBuilder.build());
}
This way your DemoActivity will get the notification id and all the extras holding the data of the notification.
You can access them in your activity's onCreate (or perhaps it would be better to do it in onResume, in case your Activity is already started).