In my Activity when the user says they want to enable notifications I call the following method:
private Intent buildRegistrationIntent(boolean register) {
String intentName = "com.google.android.c2dm.intent." + (register ? "REGISTER" : "UNREGISTER");
Intent intent = new Intent(intentName);
intent.putExtra("app", PendingIntent.getBroadcast(this, 0, new Intent(), 0)); // boilerplate
intent.putExtra("sender", "xxxxx#gmail.com");
intent.putExtra("TEST", "test extras");
return intent;
}
In my C2DM BroadcastReceiver I have this:
#Override
public void onReceive(Context context, Intent intent) {
log.fine(Boolean.toString(intent.getExtras().containsKey("TEST")));
log.fine(Boolean.toString(intent.getExtras().containsKey("registration_id")));
if (intent.getAction().equals("com.google.android.c2dm.intent.REGISTRATION")) {
handleRegistration(context, intent);
} else if (intent.getAction().equals("com.google.android.c2dm.intent.RECEIVE")) {
handleMessage(context, intent);
}
}
The problem is, the "TEST" extra never gets sent to the C2DM BroadcastReceiver. The output from the below lines is "False" then "True" i.e. it has the registration_id, but not TEST.
Is there any way to pass some user defined data to the BroadcastReceiver or does the C2DM infrastructure eat the original intent and create a new one with just the registration_id?
Why you send TEST via Intent?
You need send push notification messages not via intents.
Please look at onHandleIntent(Intent intent) method in C2DMBaseReceiver.java class. You can override method onMessage() in your C2DMReceiver.java class extended C2DMBaseReceiver.java
It looks like this is impossible. Whatever receives the REGISTER intent doesn't pass it on to onReceive.
Related
I want some methods to execute when I click on Notification Action Button.
I have searched on this site, but everything seems to be in order and my IntentService is not being called.
My Action-Button Intent
Intent off = new Intent();
off.setAction("action");
off.putExtra("test", "off");
PendingIntent pOff = PendingIntent.getService(context, 22, off, 0);
Notification Builder
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(context)
.setSmallIcon(/**/)
.setContentTitle(/**/)
.setContentText(/**/)
.addAction(/**/, "Off", pOff)
.setContentIntent(pendingIntent)
.setDefaults(Notification.DEFAULT_SOUND)
.setAutoCancel(true);
Intent Service Class
public class NotificationServiceClass extends IntentService {
public NotificationServiceClass(String name) {
super(name);
}
public NotificationServiceClass () {
super("NotificationServiceClass");
}
#Override
protected void onHandleIntent(Intent intent) {
Log.i("test", "onHandle");
if (intent.getAction().equals("action")) {
Log.i("test", "action");
Bundle bundle = intent.getExtras();
if (bundle != null) {
Log.i("test", "onHandleBundleNotNull");
if (bundle.containsKey("test")) {
Log.i("test", bundle.getString("test"));
}
}
}
}
}
XML Declaration for Service class
<service
android:name=".Manager.NotificationServiceClass"
android:exported="false">
</service>
Per the Intents and Intent Filters training, the Intent you've built is an implicit Intent:
Implicit intents do not name a specific component, but instead declare a general action to perform, which allows a component from another app to handle it. For example, if you want to show the user a location on a map, you can use an implicit intent to request that another capable app show a specified location on a map.
What you actually want is an explicit intent: one that specifies the component to start by name as per the note on the same page:
Note: When starting a Service, you should always specify the component name. Otherwise, you cannot be certain what service will respond to the intent, and the user cannot see which service starts.
When constructing your Intent, you should use
// Note how you explicitly name the class to use
Intent off = new Intent(context, NotificationServiceClass.class);
off.setAction("action");
off.putExtra("test", "off");
PendingIntent pOff = PendingIntent.getService(context, 22, off, 0);
In looking at your code, I do not see you telling the PendingIntent what class to use for your service.
You should add:
off.setClass(this, NotificationServiceClass.class);
Otherwise the PendingIntent has nothing to do.
Hi i have function like when user hit on notification i have to check my application is in foreground if it so, just close the notification. Otherwise need to open up the application.
I have use concept of ordered broadcast to achieve but i am stuck to call ordered broadcast receiver from pending intent.
To send an ordered broadcast using a PendingIntent, use one of the send() methods, for example this one, that takes a PendingIntent.OnFinished argument. This capability is not explicitly documented and only the description of the parametersto PendingIntent.OnFinished gives some hint that ordered broadcasts are supported.
Here is example for sending an ordered broadcast:
Intent i = new Intent("com.my.package.TEST_ACTION");
PendingIntent.OnFinished listener = new PendingIntent.OnFinished() {
#Override
public void onSendFinished(PendingIntent pendingIntent, Intent intent,
int resultCode, String resultData, Bundle resultExtras) {
Log.i("TEST", String.format("onSendFinished(): result=%d action=%s",
resultCode, intent.getAction()));
}
};
PendingIntent pi = PendingIntent.getBroadcast(this, 0, i, 0);
int initResult = -1;
try {
pi.send(initResult, listener, null);
} catch (PendingIntent.CanceledException e) {
e.printStackTrace();
}
I confirmed that this produces an ordered broadcast by defining a number of receivers with this general form, registered in the manifest with different priorities:
public class ReceiverA extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Log.i("AAAA", String.format("result=%d ordered=%b", getResultCode(), isOrderedBroadcast()));
setResultCode(1111);
}
}
The logcat output confirmed that the receivers were invoked in the expected order, that isOrderedBroadcast() is true for each, and the result code set by setResultCode() is passed to the next receiver, and finally to the PendingIntent.OnFinished callback.
I have "ComposeActivity" which calls the "SendSMS" method after onClick, which than calls metod in SMS class. I had also registered two BroadcastReceiver: SmsDeliveredReceiver and SmsSentReceiver, similar to: https://stackoverflow.com/a/17164931/1888738. How can I inform ComposeActivity, that sms was succesfullly sent, and that activity can clean some EditText's, and maybe show crouton with information that sms was sent or not(and why)? My codes: http://pastebin.com/LNRuSeBu
If you have receivers to handle when the SMS messages are sent or not sent. You could modify the onReceive of both of the receivers to send and intent to the ComposeActivity by creating an intent and calling intent.setComponent to specify where the intent should go. with some data that tells the ComposeActivity the result of trying to send the message.
Update:
public void onReceive(Context context, Intent arg1) {
Intent i = new Intent(action);
i.setComponent(new ComponentName("com.mypackage.compose","ComposeActivity"));
switch (getResultCode()) {
case Activity.RESULT_OK:
Log.d(getClass().getSimpleName(), "SMS delivered");
intent.setAction("com.mypackage.compose.SMS_SENT"); // String you define to match the intent-filter of ComposeActivity.
break;
case Activity.RESULT_CANCELED:
Log.d(getClass().getSimpleName(), "SMS not delivered");
intent.setAction("com.mypackage.compose.SMS_FAILED"); // String you define to match the intent-filter of ComposeActivity.
break;
}
startActivity(intent); // you may not necessarily have to call startActivity but call whatever method you need to to deliver the intent.
}
At that point it should just be matter of addind an intent-filter and a receiver to your compose activity either via the manifest or programatically. Your call. The strings I used were made up but you could pick an exiting intent action string or declare strings that you use in the intent filter. Again up to you. May also be helpful to look at questions about sending explicit intents to components like Android explicit intent with target component
or looking at the android docs.
Ok, after 5 hours of trying, I've already solved this:
in BroadcastReceiver in onReceive:
Intent intent = new Intent();
intent.setAction("SOMEACTION");
context.sendBroadcast(intent);
in Activity:
public BroadcastReceiver receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action.equals("SOMEACTION")) {
Log.d(TAG, "Sent");
}
}
};
and in onCreate Activity I registered BroadcastReceiver:
registerReceiver(receiver, new IntentFilter("SOMEACTION"));
Thats all...
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!
Hi I've been having an issue with Broadcast Receivers and passing information to another activity. I'm trying to create an application that will capture incoming SMS messages, look for a website in the text, then pop up an Alert Dialog box asking if the user wants to go to the website.
public class TextReceiver extends BroadcastReceiver{
public void onReceive(Context context, Intent intent)
{
// .. other code that
// sets received SMS into message
Toast toast = Toast.makeText(context,
"Received Text: " + message.getMessageBody(), Toast.LENGTH_LONG);
toast.show();
}
So that code works fine, receive a text it pops up a toast with the message. The toast is useless but it shows the receiver works. But I want to communicate with an activity to show an Alert Dialog and start up a webView. I already programmed the code that will take a string search for the website and open the webView. Is it possible to get the string from the broadcast receiver and do something like this?:
public class ReceiveText extends Activity{
public void onCreate(Bundle savedInstanceState) {
// Somehow pass the string from the receiver into this activity,
//stored in variable messages
findOpen(messages);
// is that possible?
}
public class findOpen(string messages){
// do stuff ... open alert...open site if OK
}
So basically I just want to pass a string from a Broadcast Receiver to another activity that will use that string. The rest of the code is basically in place all I need is that string... I'm new to this and Java and any help would be much appreciated. Thanks
Instantiate a BroadcastReceiver in the activity you want to get your data to, for example:
private BroadcastReceiver mServiceReceiver = new BroadcastReceiver(){
#Override
public void onReceive(Context context, Intent intent)
{
//Extract your data - better to use constants...
String IncomingSms=intent.getStringExtra("incomingSms");//
String phoneNumber=intent.getStringExtra("incomingPhoneNumber");
}
};
Unregister your receiver on onPause():
#Override
protected void onPause() {
super.onPause();
try {
if(mServiceReceiver != null){
unregisterReceiver(mServiceReceiver);
}
} catch (Exception e) {
e.printStackTrace();
}
}
Register it on onResume():
protected void onResume() {
super.onResume();
IntentFilter filter = new IntentFilter();
filter.addAction("android.intent.action.SmsReceiver");
registerReceiver(mServiceReceiver , filter);
}
Broadcast your data from the service via an Intent, for Example:
Intent i = new Intent("android.intent.action.SmsReceiver").putExtra("incomingSms", message);
i.putExtra("incomingPhoneNumber", phoneNumber);
context.sendBroadcast(i);
and that's it! goodLuck!
If you have your activity named ReceiveText, then in your BroadcastReceiver, you should do the following:
Intent i = new Intent(context, ReceiveText.class);
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
i.putExtra("message", message.getMessageBody());
context.startActivity(i);
Then, in your activity, you will need to getExtra as so:
Intent intent = getIntent();
String message = intent.getStringExtra("message");
And then you will use message as you need.
If you simply want the ReceiveText activity to show the message as a dialog, declare <activity android:theme="#android:style/Theme.Dialog" /> in your manifest for ReceiveText and then set the message to a textview in the activity.
EDIT: This restarts your activity. this answer is likely a better solution for most people.
We can send the data from onReceive to another activity using LocalBroadcastManager.
It means you are again broadcasting the data using the context
#Override
public void onReceive(Context context, Intent intent) {
Log.d("Broadcast", "wifi ConnectivityReceiver");
Bundle extras = intent.getExtras();
Intent intent = new Intent("broadCastName");
// Data you need to pass to another activity
intent .putExtra("message", extras.getString(Config.MESSAGE_KEY));
context.sendBroadcast(intent );
}