Home » Android » How can I tell if Android app is running in the foreground?

How can I tell if Android app is running in the foreground?

Posted by: admin November 30, 2017 Leave a comment

Questions:

I am doing a status bar notification in my android app that is triggered by c2dm. I don’t want to display the notification if the app is running. How do you determine if the app is running and is in the foreground?

Answers:

Make a global variable like private boolean mIsInForegroundMode; and assign a false value in onPause() and a true value in onResume().

Sample code:

private boolean mIsInForegroundMode;

@Override
protected void onPause() {
    super.onPause();
    mIsInForegroundMode = false;
}

@Override
protected void onResume() {
    super.onResume();
    mIsInForegroundMode = true;
}

// Some function.
public boolean isInForeground() {
    return mIsInForegroundMode;
}

Questions:
Answers:

Alternately, you can check with the ActivityManager what tasks are running by getRunningTasks method. Then check with the first task(task in the foreground) in the returned List of tasks, if it is your task.
Here is the code example:

public Notification buildNotification(String arg0, Map<String, String> arg1) {

    ActivityManager activityManager = (ActivityManager) appContext.getSystemService(Context.ACTIVITY_SERVICE);
    List<RunningTaskInfo> services = activityManager
            .getRunningTasks(Integer.MAX_VALUE);
    boolean isActivityFound = false;

    if (services.get(0).topActivity.getPackageName().toString()
            .equalsIgnoreCase(appContext.getPackageName().toString())) {
        isActivityFound = true;
    }

    if (isActivityFound) {
        return null;
    } else {
        // write your code to build a notification.
        // return the notification you built here
    }

}

And don’t forget to add the GET_TASKS permission in the manifest.xml file in order to be able to run getRunningTasks() method in the above code:

<uses-permission android:name="android.permission.GET_TASKS" />

p/s : If agree this way, please to note that this permission now is deprecated.

Questions:
Answers:

This is a pretty old post but still quite relevant. The above accepted solution may work but is wrong. As Dianne Hackborn wrote:

These APIs are not there for applications to base their UI flow on, but to do things like show the user the running apps, or a task manager, or such.

Yes there is a list kept in memory for these things. However, it is off in another process, managed by threads running separately from yours, and not something you can count on (a) seeing in time to make the correct decision or (b) have a consistent picture by the time you return. Plus the decision about what the “next” activity to go to is always done at the point where the switch is to happen, and it is not until that exact point (where the activity state is briefly locked down to do the switch) that we actually know for such what the next thing will be.

And the implementation and global behavior here is not guaranteed to remain the same in the future.

The correct solution is to implement : ActivityLifeCycleCallbacks.

This basically needs an Application Class and the handler can be set in there to identify the state of your activities in the app.

Questions:
Answers:

As Vinay says, probably the best solution (to support newer android versions, 14+) is to use ActivityLifecycleCallbacks in the Application class implementation.

package com.telcel.contenedor.appdelegate;

import android.app.Activity;
import android.app.Application.ActivityLifecycleCallbacks;
import android.os.Bundle;

/** Determines global app lifecycle states. 
 * 
 * The following is the reference of activities states:
 * 
 * The <b>visible</b> lifetime of an activity happens between a call to onStart()
 * until a corresponding call to onStop(). During this time the user can see the
 * activity on-screen, though it may not be in the foreground and interacting with 
 * the user. The onStart() and onStop() methods can be called multiple times, as 
 * the activity becomes visible and hidden to the user.
 * 
 * The <b>foreground</b> lifetime of an activity happens between a call to onResume()
 * until a corresponding call to onPause(). During this time the activity is in front
 * of all other activities and interacting with the user. An activity can frequently
 * go between the resumed and paused states -- for example when the device goes to
 * sleep, when an activity result is delivered, when a new intent is delivered -- 
 * so the code in these methods should be fairly lightweight. 
 * 
 * */
public class ApplicationLifecycleManager implements ActivityLifecycleCallbacks {

    /** Manages the state of opened vs closed activities, should be 0 or 1. 
     * It will be 2 if this value is checked between activity B onStart() and
     * activity A onStop().
     * It could be greater if the top activities are not fullscreen or have
     * transparent backgrounds.
     */
    private static int visibleActivityCount = 0;

    /** Manages the state of opened vs closed activities, should be 0 or 1
     * because only one can be in foreground at a time. It will be 2 if this 
     * value is checked between activity B onResume() and activity A onPause().
     */
    private static int foregroundActivityCount = 0;

    /** Returns true if app has foreground */
    public static boolean isAppInForeground(){
        return foregroundActivityCount > 0;
    }

    /** Returns true if any activity of app is visible (or device is sleep when
     * an activity was visible) */
    public static boolean isAppVisible(){
        return visibleActivityCount > 0;
    }

    public void onActivityCreated(Activity activity, Bundle bundle) {
    }

    public void onActivityDestroyed(Activity activity) {
    }

    public void onActivityResumed(Activity activity) {
        foregroundActivityCount ++;
    }

    public void onActivityPaused(Activity activity) {
        foregroundActivityCount --;
    }


    public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
    }

    public void onActivityStarted(Activity activity) {
        visibleActivityCount ++;
    }

    public void onActivityStopped(Activity activity) {
        visibleActivityCount --;
    }
}

And in Application onCreate() method:

registerActivityLifecycleCallbacks(new ApplicationLifecycleManager());

Then ApplicationLifecycleManager.isAppVisible() or ApplicationLifecycleManager.isAppInForeground() would be used to know the desired state.

Questions:
Answers:

FYI, if you use Gadenkan solution (which is great!!) don’t forget to add

<uses-permission android:name="android.permission.GET_TASKS" />

to the manifest.

Questions:
Answers:

Slightly cleaned up version of Gadenkan’s solution. Put it any Activity, or maybe a base class for all your Activities.

protected boolean isRunningInForeground() {
    ActivityManager manager = 
         (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
    List<ActivityManager.RunningTaskInfo> tasks = manager.getRunningTasks(1);
    if (tasks.isEmpty()) {
        return false;
    }
    String topActivityName = tasks.get(0).topActivity.getPackageName();
    return topActivityName.equalsIgnoreCase(getPackageName());
}

To be able to call getRunningTasks(), you need to add this in your AndroidManifest.xml:

<uses-permission android:name="android.permission.GET_TASKS"/>

Do note what ActivityManager.getRunningTasks() Javadoc says though:

Note: this method is only intended for debugging and presenting task
management user interfaces.
This should never be used for core logic
in an application, such as deciding between different behaviors based
on the information found here. Such uses are not supported, and will
likely break in the future.

Update (Feb 2015)

Note that getRunningTasks() was deprecated in API level 21!

As of LOLLIPOP, this
method is no longer available to third party applications: the
introduction of document-centric recents means it can leak person
information to the caller. For backwards compatibility, it will still
return a small subset of its data: at least the caller’s own tasks,
and possibly some other tasks such as home that are known to not be
sensitive.

So what I wrote earlier is even more relevant:

In many cases you can probably come up with a better solution. For example, doing something in onPause() and onResume(), perhaps in a BaseActivity for all your Activities.

(In our case we didn’t want an offline alert activity to be launched if we are not in the foreground, so in BaseActivity onPause() we simply unsubscribe from the RxJava Subscription listening for “went offline” signal.)

Questions:
Answers:

Since API 16 you can do it like this:

static boolean shouldShowNotification(Context context) {
    RunningAppProcessInfo myProcess = new RunningAppProcessInfo();
    ActivityManager.getMyMemoryState(myProcess);
    if (myProcess.importance != RunningAppProcessInfo.IMPORTANCE_FOREGROUND)
        return true;

    KeyguardManager km = (KeyguardManager) context.getSystemService(Context.KEYGUARD_SERVICE);
    // app is in foreground, but if screen is locked show notification anyway
    return km.inKeyguardRestrictedInputMode();
}

Questions:
Answers:

Following up on Gadenkan’s reply I needed something like this so I could tell if my app wasn’t running in the foreground, but I needed something that was app wide and didn’t require me setting/unsetting flags throughout my application.

Gadenkan’s code pretty much hit the nail on the head but it wasn’t in my own style and felt it could be tidier, so in my app its condensed down to this.

if (!context.getPackageName().equalsIgnoreCase(((ActivityManager)context.getSystemService(Context.ACTIVITY_SERVICE)).getRunningTasks(1).get(0).topActivity.getPackageName()))
{
// App is not in the foreground
}

(Side note: You can just remove the ! if you want the check to work the other way around)

Although with this approach you need the GET_TASKS permission.

Questions:
Answers:

I would like to add that a safer way to do this – than checking if your app is in the background before creating a notification – is to just disable and enable the Broadcast Receiver onPause() and onResume() respectively.

This method gives you more control in the actual application logic and is not likely to change in the future.

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

@Override
protected void onResume() {
    super.onResume();
    registerReceiver(mHandleMessageReceiver, new IntentFilter(DISPLAY_MESSAGE_ACTION));
}

Questions:
Answers:

I found a more simpler and accurate way to check if the application is in foreground or background by mapping the activities to boolean.

Check the complete gist here

Questions:
Answers:

This is useful only when you want to perform some action just when your activity starts and its where you want to check if app is in foreground or background.

Instead of using Activity manager there is a simple trick which you can do through code.
If you observe the activity cycle closely, the flow between two activities and foreground to background is as follows.
Suppose A and B are two activities.

When transition from A to B:
1. onPause() of A is called
2. onResume() of B is called
3. onStop() of A is called when B is fully resumed

When app goes into background:
1. onPause() of A is called
2. onStop() of A is called

You can detect your background event by simply putting a flag in activity.

Make an abstract activity and extend it from your other activities, so that you wont have to copy paste the code for all other activities wherever you need background event.

In abstract activity create flag isAppInBackground.

In onCreate() method:
isAppInBackground = false;

In onPause() method:
isAppInBackground = false;

In onStop() method:
isAppInBackground = true;

You just to need to check in your onResume() if isAppInBackground is true.
n after you check your flag then again set isAppInBackground = false

For transition between two activities since onSTop() of first will always called after second actvity resumes, flag will never be true and when app is in background, onStop() of activity will be called immediately after onPause and hence the flag will be true when you open the app later on.

There is one more scenario though in this approach.
If any of your app screen is already open and you put the mobile idle then after some time mobile will go into sleep mode and when you unlock mobile, it will be treated at background event.

Questions:
Answers:

Here is a method that I use (and supporting method):

private boolean checkIfAppIsRunningInForeground() {
    ActivityManager activityManager = (ActivityManager)getSystemService(Context.ACTIVITY_SERVICE);
    for(ActivityManager.RunningAppProcessInfo appProcessInfo : activityManager.getRunningAppProcesses()) {
        if(appProcessInfo.processName.contains(this.getPackageName())) {
            return checkIfAppIsRunningInForegroundByAppImportance(appProcessInfo.importance);
        }
    }
    return false;
}

private boolean checkIfAppIsRunningInForegroundByAppImportance(int appImportance) {
    switch (appImportance) {
        //user is aware of app
        case ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND:
        case ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE:
            return true;
        //user is not aware of app
        case ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND:
        case ActivityManager.RunningAppProcessInfo.IMPORTANCE_EMPTY:
        case ActivityManager.RunningAppProcessInfo.IMPORTANCE_PERCEPTIBLE:
        case ActivityManager.RunningAppProcessInfo.IMPORTANCE_SERVICE:
        default:
            return false;
    }
}

Questions:
Answers:

Based on the various answers and comments, here is a more inlined version that you can add to a helper class:

public static boolean isAppInForeground(Context context) {
  List<RunningTaskInfo> task =
      ((ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE))
          .getRunningTasks(1);
  if (task.isEmpty()) {
    return false;
  }
  return task
      .get(0)
      .topActivity
      .getPackageName()
      .equalsIgnoreCase(context.getPackageName());
}

As mentioned in other answers you need to add the following permission to your AndroidManifest.xml .

<uses-permission android:name="android.permission.GET_TASKS"/>

Questions:
Answers:

Here’s the code for nice simple solution described above by @user2690455 . Although it looks a bit verbose, you’ll see overall it’s actually quite light-weight

In my case we also use AppCompatActivity, so I had to have 2 base classes.

public class BaseActivity extends Activity {

    /**
     * Let field be set only in base class
     * All callers must use accessors,
     * and then it's not up to them to manage state.
     *
     * Making it static since ..
     * 1. It needs to be used across two base classes
     * 2. It's a singleton state in the app
     */
    private static boolean IS_APP_IN_BACKGROUND = false;

    @Override
    protected void onResume() {
        super.onResume();

        BaseActivity.onResumeAppTracking(this);

        BaseActivity.setAppInBackgroundFalse();
    }

    @Override
    protected void onStop() {
        super.onStop();

        BaseActivity.setAppInBackgroundTrue();
    }

    @Override
    protected void onPause() {
        super.onPause();

        BaseActivity.setAppInBackgroundFalse();
    }

    protected static void onResumeAppTracking(Activity activity) {

        if (BaseActivity.isAppInBackground()) {

            // do requirements for returning app to foreground
        }

    }

    protected static void setAppInBackgroundFalse() {

        IS_APP_IN_BACKGROUND = false;
    }

    protected static void setAppInBackgroundTrue() {

        IS_APP_IN_BACKGROUND = true;
    }

    protected static boolean isAppInBackground() {

        return IS_APP_IN_BACKGROUND;
    }
}

Questions:
Answers:

The previous approaches mentioned here are not optimal. The task based approach requires a permission that might not be desired and “Boolean” approach is prone to concurrent modification mess ups.

The approach I use and which (I believe) works quite well in most cases:

Have a “MainApplication” class to track activity count in AtomicInteger:

import android.app.Application;

import java.util.concurrent.atomic.AtomicInteger;

public class MainApplication extends Application {
    static class ActivityCounter {
        private static AtomicInteger ACTIVITY_COUNT = new AtomicInteger(0);

        public static boolean isAppActive() {
            return ACTIVITY_COUNT.get() > 0;
        }

        public static void activityStarted() {
            ACTIVITY_COUNT.incrementAndGet();
        }

        public static void activityStopped() {
            ACTIVITY_COUNT.decrementAndGet();
        }
    }
}

And create a base Activity class that other activities would extend:

import android.app.Activity;
import android.support.annotation.CallSuper;

public class TestActivity extends Activity {
    @Override
    @CallSuper
    protected void onStart() {
        MainApplication.ActivityCounter.activityStarted();
        super.onStart();
    }

    @Override
    @CallSuper
    protected void onStop() {
        MainApplication.ActivityCounter.activityStopped();
        super.onStop();
    }
}

Questions:
Answers:

There is no global callback for this, but for each activity it is onStop(). You don’t need to mess with an atomic int. Just have a global int with the number of started activities, in every activity increment it in onStart() and decrement it in onStop().

Follow this

Questions:
Answers:
     public static boolean isAppRunning(Context context) {

 // check with the first task(task in the foreground)
 // in the returned list of tasks

   ActivityManager activityManager = (ActivityManager)
   context.getSystemService(Context.ACTIVITY_SERVICE);
 List<RunningTaskInfo> services =
 activityManager.getRunningTasks(Integer.MAX_VALUE);
     if
     (services.get(0).topActivity.getPackageName().toString().equalsIgnoreCase(context.getPackageName().toString()))
     {
     return true;
     }
     return false;
     }