Android change view with GCM push notification - android

When app is notified, i need an some action in app like change view, set text from GCMIntentService. For example, when push notified while app is running, the icon will be red.
I tried these codes but nothing changed.
In GCMIntentService.java
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View view = inflater.inflate(R.layout.main_fragment_activity, null);
ImageView img = (ImageView) view.findViewById(R.id.main_tab_home_btn);
img.setBackgroundColor(Color.RED);
Also
Handler h = new Handler(Looper.getMainLooper());
h.post(new Runnable(){
#Override
public void run() {
//some codes
}
});

Your question is slightly confusing- i'm assuming what you're saying is that you want to add functionality so that when a notification is clicked by the user, you can be navigated to a specific view in your application.
Your best option is probably to let the GCMIntentService.java class handle the intent, and have the intent be carried out by some other class. Since your going to change the view based on that notifications intent, I would recommend putting it in whatever your main activity class is.
If i'm not mistaken, this kind of activity is really part of a pending intent- the active intent being to actually notify the user, but eventually, to load your application in some unique way.
So, in your GCMIntentServices class, wherever you're handling the notification (or this could be in your Receiver class, it's really up to you)
Intent myIntent = new Intent(context, DummyActivity.class);
Then, you'll want to establish a Pending intent to be issued after passing the first intent to DummyActivity.class
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, myIntent, 0);
Now, It is important that in whichever class you have that extends Activity, you establish some function that can get this pending intent and do what you want (in this case, load some View)
In DummyActivity.class:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
handleNewIntent(getIntent());
}
Then, the method for handleNewIntent:
public void handleNewIntent(Intent intent) {
Bundle payload = intent.getExtras();
//You could add some string to uniquely identify each message and what you want it to
//do
String wheretogo = intent.getStringExtra("something");
if (wheretogo == "blah") {
//LayoutInflater
View v = inflater.inflate(R.layout.wheretogo, null);
} else {
//otherwise load something different
}
Hope this helps. To add something to your message pending intent, in your receiver class or in the intent, wherever you're unloading the payload, just do something like
pendingIntent.putExtra("something","blah");

Related

How can I handle a push notification intent with changing activities after creation?

I have a two-activity android app (the activities are both single-top) and I am handling push notifications. Every push notification scenario is handled perfectly for me except for one, which is because of how the push notification intents are constructed.
The scenario that does not perform as desired is when the user is in one activity when the push notification comes in, and then they navigate to a different activity, at which point they then decide to select the push notification from their phone's dropdown bar. My problem is that the app then attempts to go back to the activity that was active when the notification was created, which isn't what I want. I want it to still do everything that it would do with the notification and its data the same way, but instead do it on the current activity and not switch back.
I know why it is happening, because the notification creation code is designed like this:
// create notification
val builder = NotificationCompat.Builder(context,
channelId)
// more things are done to set up the builder...
// here is why the problem is happening
val notificationIntent = if (we_are_in_activity_one)
Intent(context, ActivityOne::class.java)
else
Intent(context, ActivityTwo::class.java)
notificationIntent.putExtras(data_from_notification)
builder.setContentIntent(PendingIntent.getActivity(context,
notificationId,
notificationIntent,
PendingIntent.FLAG_UPDATE_CURRENT))
//Auto cancel
builder.setAutoCancel(true)
builder.priority = NotificationCompat.PRIORITY_HIGH
//Return the generated notification
return builder
What I am wondering is what can be done or changed so that when the user selects the notification, it doesn't automatically start up the activity that it was originally bundled with if circumstances have changed. Is there maybe an obvious flag I am missing that I can use?
Another piece of info that may be helpful is that it is only a problem when they are in activity 2, as activity 1 is the launcher activity. So if the notification is created while in 2, but they navigate back to 1, Activity 2 won't be active anymore. When they tap the notification, it restarts activity 2, which isn't what I want. I would only want the notification to actually go back to Activity 2 if it is still active (aka the user is still on it).
Thanks in advance and let me know if I can provide any more helpful information
If I understand correctly, do you want to receive notification on the user's current activity?
You can do it as follows.
You need to verify that the second activity is running. If it is not, your notification will open on the main screen. If it is, the notification will be opened on it in onNewIntent().
An easy way to achieve this would be:
public static boolean isActivityActive(Activity activity) {
return !activity.isFinishing() && !activity.isDestroyed();
}
and then
Intent intent = new Intent(context, !isActivityActive(new ActivityTwo()) ? ActivityOne.class : ActivityTwo.class);
This method will return true if the activity is open.
Alternatively you can use:
activity.getWindow().getDecorView().isShown();
in isActivityActive(Activity) The value returned by this expression changes in onStart() / onStop()
If the method above does not provide the result you expect, you can create a class for reuse and save the activity state to shared keys that you can use in any activity.
Only a few lines of code are needed.
First do the following:
public class MyPreference {
private Context c;
private SharedPreferences.Editor editor;
private SharedPreferences preferences;
public MyPreference (Context c) {
this.c = c;
preferences = c.getSharedPreferences("shared_preferences", Context.MODE_PRIVATE);
}
public void save (String preference, boolean value) {
editor = preferences.edit();
editor.putBoolean(preference, value);
editor.apply();
}
public boolean boo (String preference) {
return preferences.getBoolean(preference, false);
}
public String is_second_activity_active = "is_second_activity_active";
}
You can now save the life cycles of your second activity by starting MyPreference as follows:
public class ActivityTwo extends AppCompatActivity {
MyPreference p;
#Override
protected void onCreate(Bundle state) {
super.onCreate(state);
p = new MyPreference(context);
// some source...
}
#Override
protected void onStart() {
super.onStart();
p.save(p.is_second_activity_active, true);
// your activity is active
}
#Override
protected void onStop() {
super.onStop();
p.save(p.is_second_activity_active, false);
// your activity is not active
}
}
You can understand the life cycle of the Activity here
Finally, in your notification class, retrieve the status of your second activity:
// create notification
// ...
MyPreference p = new MyPreference(context);
Intent intent = new Intent
(context, p.boo(p.is_second_activity_active) ? ActivityTwo.class : ActivityOne.class);
// continue...
Sorry my English, i am not fluent. I hope you understand.
I don't write in kotlin, so you can convert the code.
Let me know if it helped you.
Thank you. > <
 
CHANGE
It is not possible to change the behavior of a notification after it has been created in one way. You can update the notification when circumstances change.
You need to define setOnlyAlertOnce (true)in your NotificationCompat.Builder, and then send a new notification with the same id as the old notification.
If the id is the same, and setOnlyAlertOnce (true), your notification will be updated without a pop-up, sound or vibration warning. You can use the same Builder for each update.
Although this works well, the documentation itself warns that if the notification is updated several times in a short period of time, some notifications will not be packaged.
Caution: Android applies a rate limit when updating a notification. If you post updates to a notification too frequently (many in less than one second), the system might drop some updates.
Documentation
In your case, the notification would need to be updated whenever the user signs in and out of ActivityTwo.class, and that would not be a good thing.
Alternatively, I recommend that you try this.
Instead of opening the activity directly by notification, open it from a BroadcastReceiver,
and then decide which activity to open..
To broadcast your notification, your Intent needs to look like this
// create notification
// ...
Intent intent = new Intent();
intent.setAction(MyNotification.ACTION_OPEN);
intent.putExtra("get", "something");
// use getBroadCast instead of getActivity
PendingIntent pIntent = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
builder.setContentIntent(pIntent);
// configure your builder normally
Now in your BroadcastReceiver, make sure the user opened their notification, and what activity they were in when they did it.
public class MyNotification extends BroadcastReceiver {
public static String ACTION_OPEN = "com.example.intent.action.NOTIFICATION_OPEN";
#Override
public void onReceive(Context context, Intent intent) {
MyPreference m = new MyPreference(context);
boolean open_notification = ACTION_OPEN.equals(intent.getAction());
if (open_notification ) {
boolean is_active = m.boo(m.is_second_activity_active);
String log = is_active ? "Open in ActivityTwo" : "Open in ActivityOne";
Intent new_intent = new Intent(context, is_active ? two.class : one.class);
new_intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP);
new_intent.putExtra("get", intent.getExtras());
context.startActivity(new_intent);
Log.e("log", log);
}
}
}
If you prefer, use your method to find out if the user is in the second activity, or use the examples I mentioned earlier.
NOTE: The onStart () and onStop () methods are actually better than onResume () and onDestroy () to check if the user is still in the activity.
onDestroy () is never called when the user closes the application, from recent applications.
Finally, declare your broadcast in your AndroidManifest.xml
<receiver android:name=".MyNotification"
android:exported="false">
<intent-filter>
<action android:name="com.example.intent.action.NOTIFICATION_OPEN" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>
Do not forget add android:launchMode="singleTop" to your ActivityOne and ActivityTwo
The notification will open according to the user's activity, no matter where it was created.
Thus, if the activity is the only thing that changes, there is no need to update notifications whenever circumstances change.
It should work now. x-x

Generic Listener when a notification is clicked or dismissed in Android

I want to know is there a way for the NotificationListenerService to know if a Notification has been clicked or it has been dismissed. I can see that the Inner class NotificationListenerWrapper in NotificationListenerService has a onNotificationClick() method , but since the NotificationListenerWrapper is hidden with #hide annotation I'm not able to use that.
My question is Can I write a Listener which basically keeps track of whether a notification has been clicked or dismissed.
Basically I want to track if the notifications of my App is being dismissed or they are clicked without any intrusive code in each and every Notification.
P.S. NotificationListenerService provides only onNotificationPosted() and onNotificationRemoved(), but my requirement is to know if notifications are clicked or Removed.
Thanks
When you create and show a notification, you provide a PendingIntent for when it is clicked (using .setContentIntent). You can also define a PendingIntent for when it gets dismissed(using .setDeleteIntent(PendingIntent).
If you want to be able to track your Notifications, you need to pass a PendingIntent (like a BroadcastReceiver or IntentService) and pass a few parameters like notificationId and isDismissed and do your work in the BroadcastReceiver.
You can see the complete code in this answer.
I don't think there is a listener for this. But you can implement this logic in another way using PendingIntent and BroadcastReceiver
For OnClick
add a ContentIntent and BroadcastReceiver. So you will know that your notification is clicked or not in the BroadcastReceiver
Intent onClickIntent = new Intent(this, OnClickBroadcastReceiver.class);
PendingIntent onClickPendingIntent = PendingIntent.getBroadcast(this.getApplicationContext(), 0, onClickIntent, 0);
mBuilder.setContentIntent(onClickPendingIntent);
And inside the BroadcastReceiver you can write your logic
public class OnClickBroadcastReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
//Open your activity here
Intent mainIntent = new Intent(context, YourActivity.class);
context.startActivity(mainIntent);
// Do your onClick related logic here
}
}
For onDismiss
For this you need to add a DeleteIntent into your notification builder
Intent onCancelIntent = new Intent(this, OnCancelBroadcastReceiver.class);
PendingIntent onDismissPendingIntent = PendingIntent.getBroadcast(this.getApplicationContext(), 0, onCancelIntent, 0);
mBuilder.setDeleteIntent(onDismissPendingIntent);
and BroadcastReceiver for this is
public class OnCancelBroadcastReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
//Do your logic here
}
}
Don't forget to register these BroadcastReceiver to AndroidManifest

Get the PendingIntent event when notification is clicked

I'm trying to get the event click when a notification is clicked.
What I have
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
String MyText = "Test";
Notification mNotification = new Notification(R.drawable.notification_template_icon_bg, MyText, System.currentTimeMillis() );
String MyNotificationTitle = "Test!";
String MyNotificationText = "Test!";
Intent MyIntent = new Intent(WifiManager.ACTION_PICK_WIFI_NETWORK);
PendingIntent StartIntent = PendingIntent.getActivity(getApplicationContext(),0,MyIntent, PendingIntent.FLAG_CANCEL_CURRENT);
makeToast(StartIntent.getIntentSender().toString());
mNotification.setLatestEventInfo(getApplicationContext(), MyNotificationTitle, MyNotificationText, StartIntent);
notificationManager.notify( NOTIFY_ME_ID, mNotification);
This is working perfect, but the thing that I don't know how to do is get the click on that notification.
What I've tried
I tried to do something on onUserInteraction() that if I'm not wrong seems to get fired when Intent starts a new activity, but didn't work.
Also I've tried on onActivityResult() but I don't know how to get that current Intent.
And the last thing that I've tried is doing something like this
BroadcastReceiver call_method = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
String action_name = intent.getAction();
if (action_name.equals("MyIntent")) {
//STUFF HERE
}
};
};
registerReceiver(call_method, new IntentFilter("MyIntent"));
Also instead of put MyIntent that is the Intent, I've tried to put the PendingIntent but doesn't work.
By the way on my code appears this when I try to create a Notification
And this when I try to call the setLatestEventInfo()
But I don't know if it may be the cause of the problem or if it could bring problems in the future.
What I'm doing wrong?
EDIT
I've just created a sample what my app does at the moment. It's simple when I press a Button it pop ups a Notification. On my real APP I don't have to click a Button but it's the same. The thing that I want is get the event of the click on the Notification and make things with that event. The thing that I've done is create another Activity where I put the things that I want and then on onCreate() at the end of the things that I want to do I call Finish() method to finish that Activity, but I don't know if it's the best approach. I want another way to do it I don't want to use two Activities...
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
Button btnoti;
private static final int NOTIFY_ME_ID=1337;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btnoti = (Button)findViewById(R.id.btnoti);
btnoti.setOnClickListener(this);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
#Override
public void onClick(View v) {
if (v.getId() == R.id.btnoti){
addNotification();
}
}
private void addNotification() {
//We get a reference to the NotificationManager
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
String MyText = "Test";
Notification mNotification = new Notification(R.mipmap.ic_launcher, MyText, System.currentTimeMillis() );
String MyNotificationTitle = "Test!";
String MyNotificationText = "Test!";
Intent MyIntent = new Intent(WifiManager.ACTION_PICK_WIFI_NETWORK);
PendingIntent StartIntent = PendingIntent.getActivity(getApplicationContext(),0,MyIntent, PendingIntent.FLAG_CANCEL_CURRENT);
mNotification.setLatestEventInfo(getApplicationContext(), MyNotificationTitle, MyNotificationText, StartIntent);
notificationManager.notify( NOTIFY_ME_ID, mNotification);
}
Edit 2 (Three fast questions) to go ahead with my code...
I hope you don't mind to solve to me that three fast questions...
Since now I've used Thread.sleep() to do a task for example every 30 seconds with a while(true) but I don't know if it's the best way because I want to let the user choose the time, for example time could be 5 min or 5h... And I don't know what's the best way to take, I've read that theres a method or something called AlarmManager is the correct way to repeat tasks? Is there any source sample to know how to use this Alarm Manager?
I've to know when the user make a "finish()" from the Intent (ACTION_PICK_WIFI_NETWORK) I mean when I'm back to my APP after close that Intent I've have used onResume() but I don't know if it's the correct way to work with, isn't it? (If you don't understand what I'm traying to say it's simple, I want to know the name of the event that know when the user closes the Wifi network picker)
Is this a way to make your APP that still alive once you go to another APP? I mean you can go to another APP and your APP is still working without user interact? Because since now, If I go to another APP my app is like sleep or something and doesn't keep running....
I've read something to call the tasks with a Service and I think it goes well, and it still running even if the APP isn't in the Recent APP...
Thanks, if you can't answer me I can make a post for each question but I think those question could be fast to answer.
Normally when we start an Activity from a push notification, the Intent is recovered in the started Activity's onCreate() method.
In your case, you are starting a system-defined Activity using the WifiManager.ACTION_PICK_WIFI_NETWORK action. We do not have access to the onCreate() of this Activity, so it doesn't seem possible to recover the Intent from it.
Because you have created a PendingIntent using getActivity(), its not possible to intercept the Intent using a BroadcastReceiver. A BroadcastReceiver is triggered by a PendingIntent created using getBroadcast().
Also, it is most certainly wrong to use a PendingIntent in place of an Intent (or vice-versa). These two are not really objects of the same type. As such they are not interchangeable. If you observe their namespace classification, it is android.app.PendingIntent versus android.content.Intent.
I know that this is not a "real" answer to your question, but its all I have for now. I will update this answer if I can think of a solution ... Best.

Change android notification text dynamically

I am trying to make a notification for a music player with controls. I am successfully listening to the button click events and functions are being fired properly. Only problem i am facing is changing the text of notification on these click events.
Here's what i am trying.
This is the receiver successfully receiving the calls and firing each and every line perfectly. But i cant the text changing. I think i have to reset the content view to Notification. If so, how do i do that?
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action.equals("stop")) {
ABCFragment.stopSong();
Log.d("Notification","Stopping");
}else if (action.equals("play")) {
ABCFragment.togglePlayPause();
Log.d("Notification","Toggle Play/Pause");
RemoteViews contentView = new RemoteViews(context.getPackageName(),R.layout.notification_layout);
contentView.setTextViewText(R.id.songName, "SOME NEW SONG");
}else if (action.equals("next")) {
ABCFragment.playNextSong();
Log.d("Notification","Next");
}
}
Solution :
I updated my Notification class constructor to pass an extra arguments and got it working!
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action.equals("stop")) {
ABCFragment.stopSong();
Log.d("Notification","Stopping");
}else if (action.equals("play")) {
ABCFragment.togglePlayPause();
Log.d("Notification","Toggle Play/Pause");
new ABCNotification(context, "SOME NEW SONG");
}else if (action.equals("next")) {
ABCFragment.playNextSong();
Log.d("Notification","Next");
}
}
constructor is handling the new passed arguments.
you can't really change stuff on notification. It's a bit annoying for sure, you just have to replace the current notification with a new one with the new text.
My app there's an upload process and every 3 seconds we're updating the notification to change percentage.
so simply re-build the notification and call notify() on the NotificationManager with the same ID.

how to use delete intent to perform some action on clear notification?

I want to reset a variable of my service when user clears my notification: that's all!
Looking around I see that everyone suggest to add a delete intent on my notification, but intent is used to start an activity, a service o whatever while I just need a thing like this:
void onClearPressed(){
aVariable = 0;
}
how to obtain this result?
Notifications are not managed by your app and all things like showing notifications and clearing them are actually happening in another process. You can't make another app directly execute a piece of code just because of security reasons.
The only possibility in your case is to provide a PendingIntent which just wraps around a regular Intent and will be started on behalf of your app when notification is cleared.
You need to use PendingIntent for sending broadcast or starting a service and then doing what you want in the broadcast receiver or in the service. What exactly to use depends on from which application component you are showing notifications.
In case of broadcast receiver you can just create an anonymous inner class for broadcast receiver and register it dynamically before showing notification. It will look something like that:
public class NotificationHelper {
private static final String NOTIFICATION_DELETED_ACTION = "NOTIFICATION_DELETED";
private final BroadcastReceiver receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
aVariable = 0; // Do what you want here
unregisterReceiver(this);
}
};
public void showNotification(Context ctx, String text) {
Intent intent = new Intent(NOTIFICATION_DELETED_ACTION);
PendingIntent pendintIntent = PendingIntent.getBroadcast(ctx, 0, intent, 0);
registerReceiver(receiver, new IntentFilter(NOTIFICATION_DELETED_ACTION));
Notification n = new Notification.Builder(mContext).
setContentText(text).
setDeleteIntent(pendintIntent).
build();
NotificationManager.notify(0, n);
}
}
Andrei is correct.
If you want multiple messages back such as:
you want to know if the message was clicked
you attached an action with an icon that you want to catch
AND you want to know if the message was canceled
you must register each of those response filters:
public void showNotification(Context ctx, String text) ()
{
/… create intents and pending intents same format as Andrie did../
/… you could also set up the style of your message box etc. …/
//need to register each response filter
registerReceiver(receiver, new IntentFilter(CLICK_ACTION));
registerReceiver(receiver, new IntentFilter(USER_RESPONSE_ACTION));
registerReceiver(receiver, new IntentFilter(NOTIFICATION_DELETED_ACTION));
Notification n = new Notification.Builder(mContext)
.setContentText(text)
.setContentIntent(pendingIntent) //Click action
.setDeleteIntent(pendingCancelIntent) //Cancel/Deleted action
.addAction(R.drawable.icon, "Title", pendingActionIntent) //Response action
.build();
NotificationManager.notify(0, n);
}
Then you can catch the different responses with if, else statements (as Andrei did), or with a switch statement.
Note: I make this response primarily because I could not find this anywhere, and I had to figure it out on my own. (perhaps I will remember it better for that :-) Have Fun!

Categories

Resources