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.
Related
I am developing an Android app. In my app, I am showing notification that is fired from inside of a broadcast receiver. Showing notification from receiver is working fine. But I am having a little problem with what I want it to be. It is a self-cancel notification. Cannot be closed by user.
What is happening now is when it is fired, it does not append as new notification in notification bar if one is already existing. Just existing one is keep showing. What I want is I want it appended whenever it is fired no matter how many notifications made from that notification manager inside receiver exist.
This is my receiver that fire self-close notification
public class GalleryImageUploadReceiver extends BroadcastReceiver {
private Context context;
private NotificationCompat.Builder notification;
private static final int NOTIFICATION_ID = 1;
private NotificationManager nm;
#Override
public void onReceive(Context pContext, Intent intent) {
this.context = pContext;
initialize(intent);
showProcessNotification();
uploadImagesToServer();
}
private void initialize(Intent intent)
{
//initialize data
}
private void uploadImagesToServer()
{
// do async task and close itself
if(nm!=null)
{
nm.cancel(NOTIFICATION_ID);
}
}
public void showProcessNotification()
{
try{
notification = new NotificationCompat.Builder(context);
notification.setAutoCancel(true);
notification.setSmallIcon(R.mipmap.ic_launcher);
notification.setWhen(System.currentTimeMillis());
notification.setTicker("Uploading image(s)...");
notification.setContentTitle(context.getResources().getString(R.string.app_name));
notification.setContentTitle("Uploading image(s)...");
notification.setAutoCancel(true);
notification.setOngoing(true);
notification.setDefaults(Notification.FLAG_ONGOING_EVENT);
nm = (NotificationManager)context.getApplicationContext().getSystemService(context.getApplicationContext().NOTIFICATION_SERVICE);
nm.notify(NOTIFICATION_ID,notification.build());
}
catch (Exception e)
{
}
}
public void uploadImages(Context context,Intent intent)
{
onReceive(context,intent);
}
}
This is how I am firing notification using receiver in activity
//inside a click listener
GalleryImageUploadReceiver receiver = new GalleryImageUploadReceiver();
receiver.uploadImages(getBaseContext(),intent);
The problem with that code is, when I click button, new notification overrides to the existing one and so only one notification is displayed in the screen. No matter how many times I click it. For example, if notification last 5 seconds, when I click the button again 2 seconds after first one is fired, that existing one will last 7 seconds. New one is not appended in the notification bar. How can I make it to append as new one whenever the button is clicked.
Use a unique notification id for each notification. Because you are using the constant 'NOTIFICATION_ID' new notifications override the existing ones.
I want to create an empty service that will just run in the background once a certain fragment is open - the service will fill an array in the background but is not used in the current (calling fragment):
Code to create the service:
Intent intent = new Intent();
intent.putExtra(ServiceActions.class.getName(), ServiceActions.GET_LIST_FROM_API);
intent.putExtra("api_code_id", "12345");
managerProvider.getRequestManager().startRetrievalService(intent);
Register & Unregister listener:
manager.registerReceiver(backgroundListReceiver , new IntentFilter(ServiceBroadcasts.GET_LIST_FROM_API_RESULT.name()));
manager.unregisterReceiver(backgroundListReceiver );
Then handle the receiver:
backgroundListReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
boolean result = extras.getBoolean(ServiceBroadcasts.GET_LIST_FROM_API_RESULT.name());
// DO Nothing here as the list is loading in the background
// and stored in the application class
}
};
I do register and unregister it in fragment, I guess I asking is this correct way to do it or is there another better process? The reason for doing it here is that the chance of the user selecting the list is quite high so I'm trying to preload the list prior to them selecting it.
Code to handle loading list in background:
private void getListInBackground() {
RequestResponse response = RestAPI.getListInBackground();
if (response.isSuccessful()) {
mApp.setBackgroundList(JacksonMapper.deserBackgroundList(response.getResponseString()));
}
Intent broadcast = new Intent(ServiceBroadcasts.GET_LIST_FROM_API_RESULT.name());
broadcast.putExtra(ServiceBroadcasts.GET_LIST_FROM_API_RESULT.name(), response.isSuccessful());
mManager.sendBroadcast(broadcast);
}
i am having a group chat feature.every person in the group will receive the push(even the sender of the message).
if the person has opened the group i.e the chatting area is visible, then i want that the push does not show up in the notification bar and it directly update the chat (which i am showing in a listview ).
Initially the chat history i get from web service (when the user open the chat area)
Hope i am able to make you guys clear with what i want to achieve .thanks in advance
First of all, when you get message in onMessage() of GCMIntentService, send brodcast. Like,
Intent i = new Intent();
i.setAction("appendChatScreenMsg");
i.putExtra("sender_id", b.getString("sender_id"));
i.putExtra("message", b.getString("message"));
i.putExtra("time", getCurrentTime());
i.putExtra("date", getCurrentDate());
this.sendBroadcast(i);
Next, Make BroadcastReceiver in your Chat activity or Chat Fragment. Like,
BroadcastReceiver appendChatScreenMsgReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
Bundle b = intent.getExtras();
if (b != null) {
int totalItems = adapter.getCount() - 1;
ChatModel model = new ChatModel("" + sharedPreferences.getString(VariableBag.USERID, ""), ""+ b.getString("sender_id"), "" + b.getString("message"), b.getString("date"), b.getString("time"));
arrChat.add(model);
if (adapter != null) {
if (lstChat.getLastVisiblePosition() == totalItems) {
adapter.notifyDataSetChanged();
lstChat.setSelection(adapter.getCount());
} else {
adapter.notifyDataSetChanged();
}
} else {
adapter = new ChatAdapter(getActivity());
lstChat.setAdapter(adapter);
adapter.notifyDataSetChanged();
lstChat.setSelection(adapter.getCount());
}
}
}
};
Next, Register BroadcastReceiver in onCreate(). Like
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getActivity().registerReceiver(this.appendChatScreenMsgReceiver, new IntentFilter("appendChatScreenMsg"));
}
Next, unregisterReceiver in onDestroy(). Like,
#Override
public void onDestroy() {
super.onDestroy();
getActivity().unregisterReceiver(appendChatScreenMsgReceiver);
}
Explanation :
1.) When message is received in GCMIntentService(), first of all, check weather
you are in chat screen or not.
2.) If you are in chat screen, broadcast your message using Intent and Broadcast.
3.) Now, Create your BroadcastReceiver() in chat screen.
4.) Register your BroadcastReceiver() in onCreate() and unregister in onDestroy().
5.) When message is broadcast and you are in chat screen, this broadcast receiver get your bundle.
6.) Now Whatever you want to do.
7.) If you are not in chat screen, then show respected message in notification. Don't broadcast.
Note: Be sure in which screen you are currently.
I think you should use Observer Design Pattern.
set a listener where you display messages and in your service where you get your messages from server check for listener, if listener wasnt null call a update method from listener and update your list else show notification.
example of this patern :
http://www.vogella.com/tutorials/DesignPatternObserver/article.html
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!
So I'm working on a simple music player. The music player as it names states, can play a song, pause playback, forward to next song, go back to previous song, and stop playback completely. When you play a song, there will be a notification displayed with the Artist Name, and the Song Name; this notification also has three buttons (Actions): Stop, Pause an Next.
What I'm having issues with is making sure that when either action is clicked, the playback control related to the Action is triggered, and well, I have absolutely no idea on how to do that. I searched the Android Notification: http://developer.android.com/guide/topics/ui/notifiers/notifications.html but It does not clarifies, or dedicates too much info on Notification Actions.
Here is a simple action for instance (which should be associated with the "Next" button click on the notification: Note: All of the code described below is written under the following package: com.deadpixels.light.player and the Activity is called: PlayerActivity
public void nextSong() {
if (position == songs.size() -1) {
Toast.makeText(this, "No more songs on queue", Toast.LENGTH_SHORT).show();
if(mPlayer.isPlaying()) {
return;
}
else {
buttonPlay.setImageResource(R.drawable.button_play);
}
return;
}
else {
position++;
playSong(songs.get(position));
}
}
Here is what I tried to do:
Intent nextIntent = new Intent(KEY_NEXT);
PendingIntent nextPendingIntent = createPendingResult(0, nextIntent, 0);
Where the action for the NextIntent is:
public static final String KEY_NEXT = "com.deadpixels.light.player.PlayerActivity.nextSong";
and then I add that to the Notification via addAction():
mBuilder.addAction(R.drawable.not_action_next, "Next", nextPendingIntent);
Do you guys know what else I could try? Using what I explained above does nothing at all, the notification shows up, and has three action buttons, but clicking on them does nothing for me.
At one point I thought maybe if I added the intent filters with the action names, but then I thought, well, they are all on the same namespace, why should I?
I've solved this problem using broadcasts. For example, to send a broadcast that advances to the next song, you can use the following:
Intent nextIntent = new Intent(KEY_NEXT);
PendingIntent nextPendingIntent = PendingIntent.getBroadcast(this, 0, nextIntent, 0);
Then, register a BroadcastReceiver within your Activity:
IntentFilter filter = new IntentFilter();
filter.addAction(KEY_NEXT);
// Add other actions as needed
receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(KEY_NEXT)) {
nextSong();
} else if (...) {
...
}
...
}
}
registerReceiver(receiver, filter);
If you're using a service to manage background playback, then you'll want to register the BroadcastReceiver in the service instead of the activity. Be sure to store the receiver instance somewhere so that you can unregister it when the activity or service is shut down.