Michael A
Michael A

Reputation: 5840

Starting app only if its not currently running

I am sending push notification to users which when clicking on it opens the app.

My problem is that when the app is already open, clicking on the notification start the app again.

I only want it to start the app if its not already running.

I am using Pending Intent in the notification:

PendingIntent contentIntent = PendingIntent.getActivity(this, 0, new Intent(this, Splash.class), 0);

I saw posts which say use:

<activity 
android:name=".Splash"
android:launchMode="singleTask"

but the thing is that my running app is running other activity then the splash which is finished after 7 seconds from app start, so when the app is running Splash is not the current activity

Upvotes: 30

Views: 15877

Answers (11)

chris hu
chris hu

Reputation: 458

For those who use Xamarin.Android. The Xamarin version of David Wasser's answer is below:

        //Create notification
        var notificationManager = GetSystemService(Context.NotificationService) as NotificationManager;
        Intent uiIntent = PackageManager.GetLaunchIntentForPackage("com.company.app");

        //Create the notification
        var notification = new Notification(Android.Resource.Drawable.SymActionEmail, title);

        //Auto-cancel will remove the notification once the user touches it
        notification.Flags = NotificationFlags.AutoCancel;

        //Set the notification info
        //we use the pending intent, passing our ui intent over, which will get called
        //when the notification is tapped.
        notification.SetLatestEventInfo(this, title, desc, PendingIntent.GetActivity(this, 0, uiIntent, PendingIntentFlags.OneShot));

        //Show the notification
        notificationManager.Notify(0, notification);

Upvotes: 3

Use Splash as Fragment instead of Activity. Keep Splash fragment(7 seconds), replace the same with the desired one(landing page).

Add launchMode="singleTask" to the manifest.

As already stated by Rahul, onNewIntent() get called if application is already running else onCreate()

@Override
protected void onNewIntent(Intent intent) 
{   
    super.onNewIntent(intent);
}

OR

Go with David's answer, seems promising.

Upvotes: 1

Rahul
Rahul

Reputation: 479

notificationIntent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP|Intent.FLAG_ACTIVITY_CLEAR_TOP|Intent.FLAG_ACTIVITY_NEW_TASK );

notificationIntent.putExtras(bundle);
PendingIntent pintent = PendingIntent.getActivity(context, 0, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT);

Upvotes: 0

Haris Qurashi
Haris Qurashi

Reputation: 2124

String appPackageName = "";

private void isApplicationInForeground() throws Exception {
    ActivityManager am = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
        final List<ActivityManager.RunningAppProcessInfo> processInfos = am
                .getRunningAppProcesses();
        ActivityManager.RunningAppProcessInfo processInfo = processInfos
                .get(0);
        // for (ActivityManager.RunningAppProcessInfo processInfo : processInfos) {
        if (processInfo.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND) {
            // getting process at 0th index means our application is on top on all apps or currently open 
            appPackageName = (Arrays.asList(processInfo.pkgList).get(0));
        }
        // }
    }
    else {
        List<ActivityManager.RunningTaskInfo> taskInfo = am.getRunningTasks(1);
        ComponentName componentInfo = null;
        componentInfo = taskInfo.get(0).topActivity;
        appPackageName = componentInfo.getPackageName();
    }
}

private void notifyMessage(String text) {
    if (appPackageName.contains("com.example.test")) {
        // do not notify
    }
    else {          
        // create notification and notify user  
    }
}

Upvotes: 3

tachyonflux
tachyonflux

Reputation: 20211

You can use an ordered broadcast to accomplish this.

1) Change your PendingIntent to start a BroadcastReceiver which will decide whether to start the activity or do nothing:

PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, new Intent(this, DecisionReceiver.class), 0);

2) Create the decision BroadcastReceiver:

public class DecisionReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        context.sendOrderedBroadcast(new Intent(MainActivity.NOTIFICATION_ACTION), null, new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                if (getResultCode() == MainActivity.IS_ALIVE) {
                    // Activity is in the foreground
                }
                else {
                    // Activity is not in the foreground
                }
            }
        }, null, 0, null, null);
    }
}

3) Create a BroadcastReceiver in your activity that will signal that it is alive:

public static final String NOTIFICATION_ACTION = "com.mypackage.myapplication.NOTIFICATION";
public static final int IS_ALIVE = 1;
private BroadcastReceiver mAliveReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        setResultCode(IS_ALIVE);
    }
};

// Register onResume, unregister onPause
// Essentially receiver only responds if the activity is the foreground activity
@Override
protected void onResume() {
    super.onResume();
    registerReceiver(mAliveReceiver, new IntentFilter(NOTIFICATION_ACTION));
}

@Override
protected void onPause() {
    super.onPause();
    unregisterReceiver(mAliveReceiver);
}

Upvotes: 0

Elltz
Elltz

Reputation: 10859

first of all set a default Task android:taskAffinity="com.example.testp.yourPreferredName" in your Application element in the Manifest file. Maintain your android:launchMode="singleTask" on your SplashActivity. Now since your SplashActivity is your main entry add this code to both onResume(), onNewIntent() and onCreate() (on a second thought onResume() is not recomended) -follow the comments in the code

//Note these following lines of code will work like magic only if its UPVOTED.
//so upvote before you try it.-or it will crash with SecurityException
ActivityManager am = (ActivityManager) this.getSystemService(ACTIVITY_SERVICE);

List< ActivityManager.RunningTaskInfo > taskInfo = am.getRunningTasks(1000);    
    for(int i =0; i< taskInfo.size(); i++){
        String PackageName = taskInfo.get(i).baseActivity.getPackageName();
        if(PackageName.equals("packagename.appname")){// suppose stackoverflow.answerer.Elltz
            //if the current runing actiivity is not the splash activity. it will be 1
            //only if this is the first time your <taskAffinity> is be called as a task
            if(taskInfo.get(i).numActivities >1){
                //other activities are running, so kill this splash dead!! reload!!                 
                finish();
                // i am dying in onCreate..(the user didnt see nothing, that's the good part)
                //about this code. its a silent assassin
            }
            //Operation kill the Splash is done so retreat to base.
            break;
        }
    }

This code will not work on api 21+; to make it work you need to use AppTask, this will save you extra lines of code as you will not be in a Loop to find your Task.

Hope it helps

Upvotes: -2

Tazz
Tazz

Reputation: 801

Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT

And maybe don't start the Splash Activity and reopen (bring to front) the MainActivity and update the UI with a listener that tells you, that you have a new notification (with a flag - boolean or with an Interface to make a listener).

Upvotes: 0

krunal shah
krunal shah

Reputation: 364

when notification clicked and your code that redirect to your desire screen just replace that code by calling this method and redirect to particular screen on "true/false" result basis.

    private boolean isAppOnForeground(Context context) {
    ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
    List<RunningAppProcessInfo> appProcesses = activityManager.getRunningAppProcesses();
    if (appProcesses == null) {
      return false;
    }
    final String packageName = context.getPackageName();
    for (RunningAppProcessInfo appProcess : appProcesses) {
      if (appProcess.importance == RunningAppProcessInfo.IMPORTANCE_FOREGROUND && appProcess.processName.equals(packageName)) {
        return true;
      }
    }
    return false;
  }

Upvotes: 0

ponnex
ponnex

Reputation: 848

try adding this to your intent to bring activity to front if it is running in the background

Intent intent = new Intent(this, Splash.class); intent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT); PendingIntent contentIntent = PendingIntent.getActivity(this, 0, intent, 0);

Upvotes: -1

David Wasser
David Wasser

Reputation: 95578

Use a "launch Intent" for your app, like this:

PackageManager pm = getPackageManager();
Intent launchIntent = pm.getLaunchIntentForPackage("your.package.name");
PendingIntent contentIntent = PendingIntent.getActivity(this, 0, launchIntent, 0);

Replace "your.package.name" with the name of your package from the Android manifest.

Also, you should remove the special launchMode="singleTask" from your manifest. Standard Android behaviour will do what you want.

Upvotes: 31

Kartheek
Kartheek

Reputation: 7214

Instead of showing the Splash activity on notification click, show your MainActivity because your splash activity will closed after some time but MainActivity will be remain open and

<activity 
android:name=".MainActivity"
android:launchMode="singleTask"

Upvotes: 1

Related Questions