I am using onesignal and firebase to push notifications from wordpress blog to Android app and when I click on notification that just arrived, application will open only if it run in the background. If it is completely closed, clicking on notification will do nothing. How do I achieve clicking on notification opens app even if app is not in the background opened?
Below is the code that handles notifications:
class nyonNotificationOpenedHandler implements OneSignal.NotificationOpenedHandler {
// This fires when a notification is opened by tapping on it.
#Override
public void notificationOpened(OSNotificationOpenResult result) {
OSNotificationAction.ActionType actionType = result.action.type;
JSONObject data = result.notification.payload.additionalData;
String customKey;
if (data != null) {
customKey = data.optString("customkey", null);
if (customKey != null)
Log.i("OneSignalnyon", "customkey set with value: " + customKey);
}
if (actionType == OSNotificationAction.ActionType.ActionTaken)
Log.i("OneSignalnyon", "Button pressed with id: " + result.action.actionID);
// The following can be used to open an Activity of your choice.
// Replace - getApplicationContext() - with any Android Context.
Intent intent = new Intent(getApplicationContext(), MainActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT | Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
The code which I am using for opening app on the click of notification, which is working perfectly fine :
Intent resultIntent = new Intent(getApplicationContext(), YourActivity.class);
resultIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
//if you want to send some data
resultIntent.putExtra(AppConstants.NOTIFICATION, data);
Now you have to create PendingIntent
PendingIntent: As per docs by creating pending intent means you are granting it the right to perform the operation you have specified as if the other application was yourself. https://developer.android.com/reference/android/app/PendingIntent
PendingIntent resultPendingIntent = PendingIntent.getActivity(context, 0, intent,
PendingIntent.FLAG_CANCEL_CURRENT
);
Now when you are creating your Notification set this pending intent setContentIntent(resultPendingIntent) to that notification.
Notification notification;
notification = mBuilder.setSmallIcon(icon).setTicker(title).setWhen(0)
.setAutoCancel(true)
.setContentTitle(title)
.setContentIntent(resultPendingIntent)
.setStyle(inboxStyle)
.setWhen(getTimeMilliSec(System.currentTimeMillis() + ""))
.setSmallIcon(R.drawable.ic_app_icon)
.setLargeIcon(BitmapFactory.decodeResource(context.getResources(), icon))
.setContentText(message)
.setChannelId(CHANNEL_ID)
.build();
Well to solve this problem, first thing is to read documentation more clearly (what I didn't do) so here it is:
By default OneSignal will open or resume your launcher Activity when a notification is tapped on. You can disable this behavior by adding the meta-data tag com.onesignal.NotificationOpened.DEFAULT set to DISABLE inside your application tag in your AndroidManifest.xml.
Make sure that you register it inside android manifest, e.g.:
<application ...>
<meta-data android:name="com.onesignal.NotificationOpened.DEFAULT" android:value="DISABLE" />
</application>
Create handler for opened notifications, e.g.:
public class MyNotificationOpenedHandler implements OneSignal.NotificationOpenedHandler {
private final Context context;
public MyNotificationOpenedHandler(Context context) {
this.context = context;
}
#Override
public void notificationOpened(OSNotificationOpenResult result) {
if (result.action.type == OSNotificationAction.ActionType.Opened) {
JSONObject data = result.notification.payload.additionalData;
if (data == null) {
return;
}
String category = data.optString("category", null);
if (category == null) {
return;
}
if (category.equals("global")) {
Intent intent = new Intent(context, NotificationDetailsActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT | Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
}
}
}
}
Next point is:
Make sure you are initializing OneSignal with setNotificationOpenedHandler in the onCreate method in your Application class. You will need to call startActivity from this callback.
You'll need to extend Application class, e.g.:
public class MyApplication extends Application {
#Override
public void onCreate() {
super.onCreate();
OneSignal.startInit(this)
.inFocusDisplaying(OneSignal.OSInFocusDisplayOption.Notification)
.setNotificationOpenedHandler(new MyNotificationOpenedHandler(getApplicationContext()))
.unsubscribeWhenNotificationsAreDisabled(true)
.init();
}
}
Set application name inside android manifest, e.g.:
<application
android:name=".MyApplication"
android:icon="#mipmap/ic_launcher"
android:roundIcon="#mipmap/ic_launcher_round"
android:theme="#style/AppTheme">
And you're ready to handle notifications when app is closed.
Set "setNotificationOpenedHandler"
OneSignal.startInit(this)
.inFocusDisplaying(OneSignal.OSInFocusDisplayOption.Notification)
.setNotificationOpenedHandler(new NotificationOpenedHandler())
.init();
Add this class to your launcher activity ( make sure notification have "additionalData" )
public class NotificationOpenedHandler implements OneSignal.NotificationOpenedHandler {
// This fires when a notification is opened by tapping on it.
#Override
public void notificationOpened(OSNotificationOpenResult result) {
//OSNotificationAction.ActionType actionType = result.action.type;
JSONObject data = result.notification.payload.additionalData;
String customKey;
if (data != null) {
customKey = data.optString("Data", null);
if (customKey != null)
{
Log.d("LOGGED", "notificationOpened: " + customKey);
if(customKey.equals("Notification"))
{
Intent intent = new Intent(getApplicationContext(), MainActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT | Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
}
else
{
Intent intent = new Intent(getApplicationContext(), MainActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
}
//Toast.makeText(MainActivity.this, "Value is : " + customKey, Toast.LENGTH_SHORT).show();
}
}
More Info
https://documentation.onesignal.com/docs/android-native-sdk#section--notificationopenedhandler-
Add the following to your AndroidManifest.xml to prevent the launching of your main Activity
<application ...>
<meta-data android:name="com.onesignal.NotificationOpened.DEFAULT" android:value="DISABLE" />
</application>
Related
I read about this all day long with different kind of solutions but non worked so far.
I have an upload service (IntentService) that sends updates to a ResultReceiver. The receiver creates and manages the Notification.
After clicking on the notification (error or success) the MainActivity is loaded. But the bundle is always null. How can I change my code to access/get the bundle?
This happens if I'am in another Activity, if the App is in background and if the app is stopped.
CustomResultReceiver:
private Context mContext;
private NotificationManager mNotificationManager;
private NotificationCompat.Builder mBuilder;
public static final String RETURN_MESSAGE = "RETURN_MESSAGE";
public static final String RETURN_STATUS = "RETURN_STATUS";
private final int id = 1;
public CustomResultReceiver(Handler handler, Context context) {
super(handler);
mContext = context;
mNotificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
mBuilder = new NotificationCompat.Builder(context);
mBuilder.setContentTitle("Upload data")
.setContentText("uploading...")
.setSmallIcon(R.mipmap.ic_launcher);
}
Creates the Notification. In onReceiveResult I notify the notification and if an error occured or the upload is successful I add a ContentIntent.
protected void onReceiveResult(int resultCode, Bundle resultData) {
super.onReceiveResult(resultCode, resultData);
String message;
boolean success;
switch (resultCode) {
case RESULT_ERROR:
message = resultData.getString(BROADCAST_MESSAGE, null);
boolean failed = resultData.getBoolean(EXTENDED_ACTION_FAILED, false);
if (failed) {
mBuilder.setProgress(0, 0, false);
mBuilder.setContentText("Aborted! Error while uploading.");
mBuilder.setContentIntent(createContentIntent(message, false));
mNotificationManager.notify(id, mBuilder.build());
}
break;
case RESULT_FINISHED:
message = resultData.getString(UPLOAD_MESSAGE, null);
success = resultData.getBoolean(UPLOAD_STATUS, false);
if (success) {
mBuilder.setProgress(0, 0, false);
mBuilder.setContentText("Upload successful");
mBuilder.setContentIntent(createContentIntent(message, true));
mNotificationManager.notify(id, mBuilder.build());
}
break;
}
}
createContentIntent() provides a PendingIntent with a result message and a success boolean:
private PendingIntent createContentIntent(String message, boolean success) {
Intent intent = new Intent(mContext, MainActivity.class);
intent.putExtra(RETURN_MESSAGE, message);
intent.putExtra(RETURN_STATUS, success);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP);
intent.setAction("NOTIFIY RESPONSE");
return PendingIntent.getActivity(mContext, 1, intent, PendingIntent.FLAG_UPDATE_CURRENT);
}
In the receiver I'am using:
android.app.NotificationManager;
android.app.PendingIntent;
android.content.Context;
android.content.Intent;
android.os.Bundle;
android.os.Handler;
android.os.ResultReceiver;
android.support.v4.app.NotificationCompat;
The MainActivity is an android.support.v7.app.AppCompatActivity.
For the creation of the PendingIntent I already tried several different Flag combinations.
Here are some snippets from the manifest:
My permissions:
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.CAMERA"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-feature android:name="android.hardware.camera"/>
The Activity that I open via the Notification:
<activity
android:name=".views.activities.MainActivity"
android:label="#string/title_activity_main"
android:screenOrientation="landscape"
android:theme="#style/AppTheme.NoActionBar"
android:windowSoftInputMode="stateHidden">
<intent-filter>
<action android:name="android.intent.action.RUN"/>
</intent-filter>
</activity>
Here the Service:
<service android:name=".services.UploadService"/>
For when I launch the activity from the ResultReceiver following happens:
The activity starts and onCreate is called where i check for the bundle like this:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.act_main);
...
Intent old = getIntent();
if (old != null) {
Bundle extras = old.getExtras();
if (extras != null) {
Log.d(MainActivity.class.getSimpleName(), "Message: " + extras.getString(CustomResultReceiver.RETURN_MESSAGE, "empty"));
Log.d(MainActivity.class.getSimpleName(), "Status: " + extras.getBoolean(CustomResultReceiver.RETURN_STATUS, false));
}
}
...
}
So I finally found the problem. After debugging several flag options and changing request codes. The request code here is irrelevant to the problem.
Responsible for the empty (not null) bundle is the flag ACTIVITY_NEW_TASK.
If I went with all other tested flags for the Intent or the PendingIntent everything works fine.
The android doc says following for ACTIVITY_NEW_TASK:
When using this flag, if a task is already running for the activity
you are now starting, then a new activity will not be started;
instead, the current task will simply be brought to the front of the
screen with the state it was last in. See FLAG_ACTIVITY_MULTIPLE_TASK
for a flag to disable this behavior.
This seems to indicate that the old Intent is still present and not the new one which I build in the receiver. Funny fact: even if I closed the app and then started the PendingIntent the bundle was empty. The doc as for my understanding would state it otherwise (activity not in a task? -> new task with new activity).
I followed this developer tutorial, and have Geofencing working within my app, as expected.
A notification is sent when a Geofence Transition occurs, from within an IntentService:
#Override
protected void onHandleIntent(Intent intent) {
GeofencingEvent geofencingEvent = GeofencingEvent.fromIntent(intent);
...
sendNotification(geofenceTransitionDetails);
}
private void sendNotification(String notificationDetails) {
// Create an explicit content Intent that starts the main Activity.
Intent notificationIntent = new Intent(getApplicationContext(), MainActivity.class);
// Construct a task stack.
TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
// Add the main Activity to the task stack as the parent.
stackBuilder.addParentStack(MainActivity.class);
// Push the content Intent onto the stack.
stackBuilder.addNextIntent(notificationIntent);
// Get a PendingIntent containing the entire back stack.
PendingIntent notificationPendingIntent =
stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);
// Get a notification builder that's compatible with platform versions >= 4
NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
// Define the notification settings.
builder.setSmallIcon(R.mipmap.ic_launcher)
// In a real app, you may want to use a library like Volley
// to decode the Bitmap.
.setLargeIcon(BitmapFactory.decodeResource(getResources(),
R.mipmap.ic_launcher))
.setColor(Color.RED)
.setContentTitle(notificationDetails)
.setContentText("Return to app")
.setContentIntent(notificationPendingIntent);
// Dismiss notification once the user touches it.
builder.setAutoCancel(true);
// Get an instance of the Notification manager
NotificationManager mNotificationManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
// Issue the notification
mNotificationManager.notify(0, builder.build());
}
This is cookie-cutter from the tutorial. The intent is set-up in the Main activity:
private PendingIntent getGeofencePendingIntent() {
// Reuse the PendingIntent if we already have it.
if (mGeofencePendingIntent != null) {
return mGeofencePendingIntent;
}
Intent intent = new Intent(this, GeofenceTransitionsIntentService.class);
// We use FLAG_UPDATE_CURRENT so that we get the same pending intent back when calling
// addGeofences() and removeGeofences().
return PendingIntent.getService(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
}
How can I add functionality that suppresses the notifications if the app is open, and instead displays an AlertDialog to the user? Ideally, I'd like to be able to execute different tasks, depending on which view the user is currently in when the Geofence Transition occurs. Can I monitor/intercept the transition from within each view, or somehow globally?
Thanks in advance.
Some of the answers were incomplete, and so here is the complete solution to what I was looking for.
First off, set up MyApplication class, that implements ActivityLifecycleCallbacks:
public class MyApplication extends Application implements Application.ActivityLifecycleCallbacks {
private static boolean isActive;
#Override
public void onCreate() {
super.onCreate();
registerActivityLifecycleCallbacks(this);
}
public static boolean isActivityVisible(){
return isActive;
}
#Override
public void onActivityResumed(Activity activity) {
isActive = true;
}
#Override
public void onActivityPaused(Activity activity) {
isActive = false;
}
... no other methods need to be used, but there are more that
... must be included for the ActivityLifecycleCallbacks
}
Be sure to name this in your manifest (only name line was added, rest is default):
<application
android:name=".MyApplication"
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme"
android:hardwareAccelerated="true">
What was done above is used to track the lifecycle of your app. You can use this to check if your app is currently in the foreground or not.
Next is to set up a BroadcastReceiver, wherever you would like code to run (in the event that the app is open when the trigger occurs). In this case, it is in my MainActivity:
protected BroadcastReceiver mNotificationReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
... Do whatever you want here
Toast.makeText(...).show();
}
};
Register the receiver in your onCreate of the same activity:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
LocalBroadcastManager.getInstance(this).registerReceiver(mNotificationReceiver, new IntentFilter("some_custom_id"));
}
And don't forget to unregister it:
#Override
protected void onDestroy() {
LocalBroadcastManager.getInstance(this).unregisterReceiver(mNotificationReceiver);
super.onDestroy();
}
When a broadcast is received, the code within the receiver is executed.
Now, to check if the app is in the foreground, and send a broadcast if it is. Inside of the IntentService:
#Override
protected void onHandleIntent(Intent intent) {
GeofencingEvent geofencingEvent = GeofencingEvent.fromIntent(intent);
if (geofencingEvent.hasError()) {
String errorMessage = getErrorString(this,
geofencingEvent.getErrorCode());
return;
}
int geofenceTransition = geofencingEvent.getGeofenceTransition();
// Test that the reported transition was of interest.
if (geofenceTransition == Geofence.GEOFENCE_TRANSITION_ENTER ||
geofenceTransition == Geofence.GEOFENCE_TRANSITION_EXIT) {
...
if(MyApplication.isActivityVisible()){
Intent intnt = new Intent("some_custom_id");
intnt.putExtra("message", geofenceTransitionDetails);
LocalBroadcastManager.getInstance(this).sendBroadcast(intnt);
}else{
sendNotification(geofenceTransitionDetails);
}
} else {
// Log the error.
}
}
The important bit is the last nested if-statement:
if(MyApplication.isActivityVisible()){
Intent intnt = new Intent("some_custom_id");
intnt.putExtra("message", geofenceTransitionDetails);
LocalBroadcastManager.getInstance(this).sendBroadcast(intnt);
}else{
sendNotification(geofenceTransitionDetails);
}
Check if the app is in the foreground using MyApplication.isActivityVisible(), as defined above, and then either send the notification, or send a broadcast. Just make sure that your intent code (i.e. "some_custom_id") matches on your sender and receiver.
And that's about it. If the app is in the foreground (specifically the MainActivity), I execute some code. If the app is not in the foreground, I send a notification.
The easiest way would be to use LocalBroadcastManager or some event bus.
So when transition happens you should send local broadcast from IntentService and catch it with some component X in between IntentService and any of your Activity's. Component X must track if any of your Activity's is in foreground and
if yes - pass other local broadcast up (to the foreground Activity),
if not - show notification.
Please note that in Android you cannot track easily if your app is in foreground or not (and if you have more than 1 Activity, you cannot do it properly in my opinion) but you can try.
a) You can notify your service of the activity's lifecycle events.
b) You can keep the current state of your UI in a static field in the activity and check it from the service before showing the notification.
Currently I am working on GCM (Google Cloud message), it allow user to push the message to user device. And I would like achieve the following requirement :
if the user has already enter app , ignore it
if the user has not enter the app , click on notification to enter the app
And the work flow of my app is:
WelcomePage (download json and create data set from it) => MainPage (Display base on the data set)
The code to handle notification
private void sendNotification(String msg) {
mNotificationManager = (NotificationManager) this.getSystemService(Context.NOTIFICATION_SERVICE);
String notifyMsg = "";
JSONTokener tokener = new JSONTokener(msg);
if (tokener != null) {
try {
notifyMsg = new JSONObject(tokener).getString("msg");
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Intent myintent = new Intent(this, WelcomePageActivity.class);
myintent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
PendingIntent contentIntent = PendingIntent.getActivity(this, 0, myintent, PendingIntent.FLAG_UPDATE_CURRENT);
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this)
.setSmallIcon(R.drawable.ic_launcher)
.setContentTitle(getResources().getString(R.string.notification_title))
.setStyle(new NotificationCompat.BigTextStyle()
.bigText(notifyMsg))
.setContentText(notifyMsg)
.setContentIntent(contentIntent);
mNotificationManager.notify(NOTIFICATION_ID, mBuilder.build());
}
The problem is if I use WelcomePageActivity class , it will create a new activity if I am at the main page, how can I adjust the code to fit my requirement ?
Thanks
For
1. if the user has already enter app , ignore it:
in the onReceive() , check if your app is running, do not notify.
It can be checked with something like:
ActivityManager activityManager =(ActivityManager)gpsService.this.getSystemService(ACTIVITY_SERVICE);
List<ActivityManager.RunningServiceInfo> serviceList= activityManager.getRunningServices(Integer.MAX_VALUE);
if((serviceList.size() > 0)) {
boolean found = false;
for(int i = 0; i < serviceList.size(); i++) {
RunningServiceInfo serviceInfo = serviceList.get(i);
ComponentName serviceName = serviceInfo.service;
if(serviceName.getClassName().equals("Packagename.ActivityOrServiceName")) {
//Your service or activity is running
break;
}
}
if the user has not enter the app , click on notification to enter the app
from the code above, you'l know if you would like to resume the app or launch - call Splash Screen or in your case WelcomeActivity.
About the workflow of your app, i'd suggest check whether you need to download the data every time or not. Can save it maybe or update/download only when required, and rest of flow works as it is.
In your AndroidManifest.xml, define your WelcomePageActivity with the flag android:launchMode="singleTop". From the definition of this flag:
A new instance of a "singleTop" activity may also be created to handle
a new intent. However, if the target task already has an existing
instance of the activity at the top of its stack, that instance will
receive the new intent (in an onNewIntent() call); a new instance is
not created.
So with this flag, your activity will not be created again, rather it will receive a call in the onNewIntent() function with the Intent you used to create the PendingIntent for the notification. You could override this function, and use the intent to pass the activity new information.
You will not able to receive any notification click event so,
try this code :
Intent myintent = new Intent(this, TestActivity.class);
myintent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
PendingIntent contentIntent = PendingIntent.getActivity(this, 0, myintent, PendingIntent.FLAG_UPDATE_CURRENT);
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this)
.setSmallIcon(R.drawable.ic_launcher)
.setContentTitle(getResources().getString(R.string.notification_title))
.setStyle(new NotificationCompat.BigTextStyle()
.bigText(notifyMsg))
.setContentText(notifyMsg)
.setContentIntent(contentIntent);
mNotificationManager.notify(NOTIFICATION_ID, mBuilder.build());
}
public class TestActivity extends Activity{
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// check for your app state is running or not
if(appRunning == false) {
// start your WelcomePage activity.
}
}
}
1.Create an object in GcmIntentService
public static final Object CURRENTACTIVIYLOCK = new Object();
//for storing current activity
public static Activity currentActivity;
2.Update this object value in onPause and onResume of MainActivity to recognize Activity is running or not.
#Override
public void onResume() {
super.onResume();
System.out.println("onResume Home page");
synchronized (GcmIntentService.CURRENTACTIVIYLOCK) {
GcmIntentService.currentActivity = this;
}
}
#Override
public void onPause() {
super.onPause();
synchronized (GcmIntentService.CURRENTACTIVIYLOCK) {
GcmIntentService.currentActivity = null;
}
}
3.In GcmIntentService class, check for the current activity in onHandleIntent method.
synchronized (CURRENTACTIVIYLOCK) {
if (currentActivity != null) {
if (currentActivity.getClass() == HomePageActivity.class) {
} else {
sendNotification(extras.getString("message"));
}
} else {
sendNotification(extras.getString("message"));
}
I'm sure this will help you.
I have implemented a download manager which shows the completion notification on the navigation bar and when users touch the notification it automatically lanches my main activity.
Now the problem is when I press back button on main activity, it returns to previous activity which I don't want to happen.
The CODES I have tried are:
on Main Class:
#Override
public void onBackPressed() {
super.onBackPressed();
finish();
}
and this:
#Override
public void onBackPressed() {
super.onBackPressed();
Intent startMain = new Intent(Intent.ACTION_MAIN);
startMain.addCategory(Intent.CATEGORY_HOME);
startMain.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(startMain);
}
This is my Download Receiver Code:
private BroadcastReceiver downloadReceiver = new BroadcastReceiver() {
public void onReceive(Context ctxt, Intent i) {
if (DownloadManager.ACTION_NOTIFICATION_CLICKED.equals(i.getAction()))
startActivity(new Intent(getApplicationContext(),MainActivity.class));
else if (DownloadManager.ACTION_DOWNLOAD_COMPLETE.equals(i.getAction())) {
Toast.makeText(ctxt,"Done!",Toast.LENGTH_SHORT).show();
Log.i("download status: ", "Download Completed!");
MyNotificationManager.ShowNotification((Activity) ctxt, MainActivity.GetTheActivity(), R.drawable.ic_launcher, "package " + downloadedFileName),
"package" + downloadedFileName + " is downloaded!"), MyNotificationManager.SoundsType.System);
Log.i("download status: ", "Notification shown!");
DoBackgroundDatabaseOperations proceedDownload = new DoBackgroundDatabaseOperations();
proceedDownload.execute();// Sending the package
}
}
};
This is my MyNotificationManager class which has the following method to show Notification:
public static enum SoundsType
{
System,
My
}
public SoundsType SoundType;
static Uri soundUri;
public static void ShowNotification(Activity curActivity,Activity targetActivity,int icon,String title,String decs,SoundsType sound)
{
if (sound == SoundsType.System)
soundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
else if (sound == SoundsType.My)
soundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
Intent notificationIntent = new Intent(curActivity, targetActivity.getClass());
PendingIntent contentIntent = PendingIntent.getActivity(curActivity, 0, notificationIntent,PendingIntent.FLAG_UPDATE_CURRENT);
NotificationCompat.Builder builder = new NotificationCompat.Builder(curActivity)
.setSmallIcon(icon)
.setContentTitle(title)
.setContentText(decs)
.setSound(soundUri)
.setAutoCancel(true)
.setContentIntent(contentIntent);
NotificationManager manager = (NotificationManager) curActivity.getSystemService(Context.NOTIFICATION_SERVICE);
manager.notify(0, builder.build());
}
Now What should I do in order to handle back button properly so it goes to previous app which could have been running, or home screen if user has launched my app from there?
I know this is more of a question than a code problem but I suppose this is a question of many others...
When you create the notification, you need to set the following flags on the `Intent:
Intent notificationIntent = new Intent(curActivity, targetActivity.getClass());
notificationIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
If your application is not already running, this will launch the target activity. If your application is already running and your target activity is still active (ie: not finished) then this will clear all activities in the task that are on top of the target activity and start a new instance of the target activity.
From your description this sounds like what you want.
I have created a big view style notification in a service
I intend to put a button that will pass some info back to the activity but it seems the activity just can't get the extras I set before.
Here's the code that I used to show the notification:
public class TestService extends Service {
...
#Override
public void onCreate() {
showNotification();
}
private void showNotification() {
PendingIntent contentIntent = PendingIntent.getActivity(this, 0,
new Intent(this, TestActivity.class), PendingIntent.FLAG_UPDATE_CURRENT);
Intent discardIntent = new Intent(this, TestActivity.class);
discardIntent.putExtra("piAction", "discard");
PendingIntent piDiscard = PendingIntent.getActivity(this, 0, discardIntent, PendingIntent.FLAG_CANCEL_CURRENT);
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this);
mBuilder.setSmallIcon(R.drawable.ic_launcher);
mBuilder.setContentTitle("Test Notification");
mBuilder.addAction(R.drawable.content_discard, "Discard", piDiscard);
mBuilder.setStyle(new NotificationCompat.BigTextStyle().bigText("Test service is running"));
mBuilder.setContentIntent(contentIntent);
Notification notification = mBuilder.build();
notification.flags |= Notification.FLAG_AUTO_CANCEL;
mNotificationManager.notify(0, notification);
}
...
}
And here's the activity that will catch the info sent by the button in notification
public class TestActivity extends Activity {
...
#Override
protected void onResume() {
super.onResume();
Log.i("Activity Resume", "onResume");
Bundle extras = getIntent().getExtras();
if (extras != null) {
Log.i(TAG, "extras not null");
if (extras.containsKey("piAction")) {
Log.i("Intent Received", "piAction");
}
}
}
...
}
Please note, when launching TestActivity, it will also start TestService. What I intend to do is when the discard button inside the notification is clicked, it will pass the previously put extra back to TestActivity. However, after a few tests, I found TestActivity can be launched successfully, but it can't get the extras I set before.
So where's the possible problems in my code?
If you require any other details, please state in the comment, I'll update my question with those details accordingly.
I had face same type of problem when I was passing string from my notification to my launching activity to solve that
1) take a one String e.g. public String temp field in your application extended class
now instead of this
discardIntent.putExtra("piAction", "discard");
use this
YourApplication app = (YourApplication)getApplicationContext();
app.temp = "discard";
in your activity
instead of this
Bundle extras = getIntent().getExtras();
if (extras != null) {
Log.i(TAG, "extras not null");
if (extras.containsKey("piAction")) {
Log.i("Intent Received", "piAction");
}
}
get your piAction status from YourApplication
YourApplication app = (YourApplication)getApplicationContext();
String stringFromNotification = app.temp;