50

How can a Service check if one of it's application's Activity is running in foreground?

Pratik Butani
  • 60,504
  • 58
  • 273
  • 437
Taranfx
  • 10,361
  • 17
  • 77
  • 95
  • This question doesn't quite make sense, because I'm not sure I understand the motivation or use case for it? You can bind and unbind whenever the service goes into foreground / background by simply making appropriate calls at onPause/onResume, etc.., this seems like the hackier solution to a more basic underlying problem. – Kristopher Micinski Aug 29 '12 at 06:36
  • 10
    My service runs for a much longer time than activity does, Its only the one of the operation that needs to identify if activity is running. Service terminates and can be re-invoked via a system Broadcast event. Its then when service checks if activity is running. – Taranfx Aug 29 '12 at 07:18
  • 7
    I have the same issue: A push receiving service needs to decide between poping a notification or some sort of a popup on the app – Adriano Apr 23 '15 at 13:44

9 Answers9

64

Use the below method with your package name. It will return true if any of your activities is in foreground.

public boolean isForeground(String myPackage) {
    ActivityManager manager = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
    List<ActivityManager.RunningTaskInfo> runningTaskInfo = manager.getRunningTasks(1); 
    ComponentName componentInfo = runningTaskInfo.get(0).topActivity;
    return componentInfo.getPackageName().equals(myPackage);
}

Update:

Add Permission:

<uses-permission android:name="android.permission.GET_TASKS" />
Community
  • 1
  • 1
Rasel
  • 15,499
  • 6
  • 40
  • 50
14

Use SharedPreferences to save the status of your app in onResume, onPause etc.

like so:

 @Override
public void onPause() {
    super.onPause();
    PreferenceManager.getDefaultSharedPreferences(this).edit().putBoolean("isActive", false).commit();
}

@Override
public void onDestroy() {
    super.onDestroy();
    PreferenceManager.getDefaultSharedPreferences(this).edit().putBoolean("isActive", false).commit();
}

@Override
public void onResume() {
    super.onResume();
    PreferenceManager.getDefaultSharedPreferences(this).edit().putBoolean("isActive", true).commit();
}

and then in the service:

if (PreferenceManager.getDefaultSharedPreferences(this).getBoolean("isActive", false)) {
            return;
}

i used both onPause and onDestroy because sometimes it jumps straight to onDestroy:) it's basically all voodoo

anyway, hope that helps someone

eiran
  • 1,378
  • 15
  • 16
7

Starting from Lollipop, getRunningTasks is deprecated:

 * <p><b>Note: this method is only intended for debugging and presenting
 * task management user interfaces</b>.  This should never be used for
 * core logic in an application, such as deciding between different
 * behaviors based on the information found here.</p>
 *
 * @deprecated As of {@link android.os.Build.VERSION_CODES#LOLLIPOP}, this method
 * is no longer available to third party applications.

One way to do this is to bind to the service on app start. Then: 1. If you need to check any of the app's activity is running, you can create a base class for your activities and override onPause and onResume. In onPause, call a service method to let it know it is on the background. In onResume, call a service method to let it know it is on the foreground. 2. If you only need to do this on some specific activity, just override onResume and onPause on those activities or create a base activity for those activities.

Comtaler
  • 1,580
  • 1
  • 15
  • 26
3

Erian has the correct answer, but its not safe to use "getDefaultSharedPreferences". When you start a Service it use a differente instance that the Activity. Any changes of preferences in the activity, doesnt update the default shared preferences in the Service. So i will change Erian code with ".getSharedPreferences" like this:

In Activity:

    @Override
    public void onPause() {
        super.onPause();
        getApplicationContext().getSharedPreferences("preferences", MODE_MULTI_PROCESS).edit().putBoolean("isActive", false).commit();;
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        getApplicationContext().getSharedPreferences("preferences", MODE_MULTI_PROCESS).edit().putBoolean("isActive", false).commit();
    }

    @Override
    public void onResume() {
        super.onResume();
        getApplicationContext().getSharedPreferences("preferences", MODE_MULTI_PROCESS).edit().putBoolean("isActive", false).commit();
    }

In Service:

    if (getApplicationContext().getSharedPreferences("preferences", MODE_MULTI_PROCESS).getBoolean("isActive", false)) {
        return;
    }
nnyerges
  • 563
  • 4
  • 15
2

There is one flaw to most of the answers above, if your activity has some feature which triggers another activity over the top, e.g. sending an email

enter image description here

the topActivity will not return your package name but instead the Android activity selector package name.

Thus, it is better to check for the baseActivity instead of the topActivity.

public boolean isMainActivityRunning(String packageName) {
    ActivityManager activityManager = (ActivityManager) getSystemService (Context.ACTIVITY_SERVICE);
    List<RunningTaskInfo> tasksInfo = activityManager.getRunningTasks(Integer.MAX_VALUE); 

    for (int i = 0; i < tasksInfo.size(); i++) {
        if (tasksInfo.get(i).baseActivity.getPackageName().toString().equals(packageName)
            return true;
    }

    return false;
} 
ShadowGod
  • 7,891
  • 3
  • 28
  • 31
ForceMagic
  • 6,230
  • 12
  • 66
  • 88
1

getRunningTasks() is Deprecated

getRunningTask() is deprecated by android and now we can use getRunningAppProcesses(). This returns a List or RunningAppProcessInfo where we can check for the importance of the first process.

See the official documentation for more details: https://developer.android.com/reference/android/app/ActivityManager#getRunningAppProcesses()

Code:

 public boolean isAppInForeground() {
        ActivityManager manager = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
        List<ActivityManager.RunningAppProcessInfo> runningTaskInfo = manager.getRunningAppProcesses();
        if (runningTaskInfo.size() > 0)
            return runningTaskInfo.get(0).importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
        return false; // no running process
    }
Shubham Gupta
  • 1,123
  • 11
  • 16
0

With Android Architecture Components it is quite straight forward to check this

annotationProcessor 'android.arch.lifecycle:compiler:1.1.1'
implementation 'android.arch.lifecycle:extensions:1.1.1'

The lifecycle observer class, keeping a pref flag

public class AppLifecycleObserver implements LifecycleObserver {

public static final String TAG = "AppLifecycleObserver";

@OnLifecycleEvent(Lifecycle.Event.ON_START)
void onEnterForeground() {
    Log.d(TAG, "onEnterForeground");
    PreferencesUtils.save(Constants.IN_FOREGROUND, true);
}

@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
void onEnterBackground() {
    Log.d(TAG, "onEnterBackground");
    PreferencesUtils.save(Constants.IN_FOREGROUND, false);
  }
}

Application Class observers the lifecycle

public class App extends Application {


private static App instance;

public static App getInstance() {
    return instance;
}

@Override
public void onCreate() {
    super.onCreate();

    AppLifecycleObserver appLifecycleObserver = new AppLifecycleObserver();
    ProcessLifecycleOwner.get().getLifecycle().addObserver(appLifecycleObserver);
}

Now, you can use the Pref flag to check anywhere you please.

Veeresh Charantimath
  • 4,641
  • 5
  • 27
  • 36
-1

I think you can getRunninTasks on Android and check with your packagename if the task is running or not.

public boolean isServiceRunning() { 

ActivityManager activityManager = (ActivityManager)Monitor.this.getSystemService (Context.ACTIVITY_SERVICE); 
List<RunningTaskInfo> services = activityManager.getRunningTasks(Integer.MAX_VALUE); 
isServiceFound = false; 
for (int i = 0; i < services.size(); i++) { 
    if (services.get(i).topActivity.toString().equalsIgnoreCase("ComponentInfo{com.lyo.AutoMessage/com.lyo.AutoMessage.TextLogList}")) {
        isServiceFound = true;
    }
} 
return isServiceFound; 
} 
VendettaDroid
  • 3,131
  • 2
  • 28
  • 41
-2

Use the below method to get full class name (package+class name) of the current activity and check if it is equal to full class name (package+class name) of activity you want:

 public String getCurrentClass() {

    ActivityManager manager = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
    List<ActivityManager.RunningTaskInfo> runningTaskInfo = manager.getRunningTasks(1);

    ComponentName componentInfo = runningTaskInfo.get(0).topActivity;
    String className = componentInfo.getClassName();
    return className;
 }
ForceMagic
  • 6,230
  • 12
  • 66
  • 88
Abdulla
  • 9
  • 1
  • 5
    Welcome on SO, FYI this is not blogging and your answer is pretty much the same that was answered before. I suggest you have a look to the Help section : http://stackoverflow.com/help/answering – ForceMagic Jan 19 '15 at 13:38