59

I have implemented a BroadcastReceiver which is triggered by the AlarmManager. The AlarmManager is initialized on BOOT_COMPLETED. So i have to declare the receiver in the manifest.

My problem is that i want the BroadcastReceiver only to do something when none of my own activities are in the foreground (aka the user is not interacting with my application). I pull information from a remote server and don't want to notify the user if he is currently in my application anyways.

So far i have not managed to find a way to determine if my application is in the foreground. Is there a way to do such thing? The ActivityManager tells me if my application is running but not whether it is in the foreground.

The problem is pretty much the same as described here: Inform Activity from a BroadcastReceiver ONLY if it is in the foreground

SOLUTION:

After evaluating several solutions i want to quickly outline what i think is the best method to deal with activities in the background/foreground.

The preferred way is to register a broadcast receiver in the onResume method of your activity and to deregister it on the activities on onPause. Any service or other background element will than need to send a broadcast intent with a specific action that your activity will intercept.

If your activity is in the foreground it will have its intent receiver registered and is able to directly deal with the intent send from your service. If it is not in the foreground it will not receive the intent but the service that invokved the broadcast will know that nobody intercepted its broadcast intent and will be able to deal with that itself. Eg it could than launch the desired activity, show a notification etc.

Community
  • 1
  • 1
Moritz
  • 10,124
  • 7
  • 51
  • 61
  • 5
    "the service that invoked the broadcast will know that nobody intercepted its broadcast intent" - possibly a stupid question but how will it know? – ostergaard Sep 01 '13 at 12:09
  • @ajostergaard I think it goes like that: Broadcast sent "are you in foregraund" intent. When Activity is in foreground it can recieve that intent (because registers own recevier in onResume) and respones with Intent "yes, I'm in foreground". Broadcast can revevie that, thus know about Activity state. BTW. Check my answer for this question below :) – klimat Dec 05 '14 at 16:29
  • [ProcessLifecycleOwner](https://stackoverflow.com/a/54684819/6017001) is the newest solution – S.R Feb 14 '19 at 07:11

7 Answers7

27

The following answer: "Is application running in background", summarizes solutions available for background/foreground checking.

Note:
Previously this answer suggested to use ActivityManager.getRunningAppProcesses(), however that method appeared to be not completely reliable and its usage is discouraged. Check the link above for the details.

Community
  • 1
  • 1
Volo
  • 28,673
  • 12
  • 97
  • 125
12

Your activity can track its own state as to whether it is in the foreground (set boolean to true in onStart(), to false in onStop()). Alas, that boolean is not provided to you by Activity automatically.

CommonsWare
  • 986,068
  • 189
  • 2,389
  • 2,491
  • That would be possible but every Activity in my application would support that scenario. Also i don't want to couple this behavior to my activities but rather have the BroadcastReceiver determine the actual state. – Moritz Feb 23 '10 at 08:25
  • 1
    False, an activity can be backgrounded without `onStop()` being called. Read this: http://developer.android.com/reference/android/app/Activity.html – Jorge Fuentes González Jun 02 '13 at 21:21
  • @JorgeFuentesGonzález: Please quote a specific passage on that page that backs up your claims. – CommonsWare Jun 03 '13 at 11:19
  • 2
    Exactly these two phrases: `"The foreground lifetime of an activity happens between a call to onResume() until a corresponding call to onPause()"` and `"If an activity has lost focus but is still visible (that is, a new non-full-sized or transparent activity has focus on top of your activity), it is paused."` so if a transparent activity or halfwindow activity comes to front, your activity is not foreground but `onStop()` is not called. – Jorge Fuentes González Jun 03 '13 at 16:40
  • 6
    @JorgeFuentesGonzález: It depends upon your definition of "foreground". `onPause()`/`onResume()` are for input. `onStop()`/`onStart()` are for output (visibility). Since the question is ~3 years old, we are not going to be able to get clarification from the OP as to which scenario concerns them. Neither have a flag maintained by the framework, and so my answer still stands (though my `onStart()`/`onStop()` may need to be replaced with `onResume()`/`onPause()` depending on which scenario one wants). – CommonsWare Jun 03 '13 at 16:45
  • 1
    Yeah, I told that because your answer talks about checking if an activity is in the foreground with `onStart()` and `onStop()` when the documentation don't says that. Now all the users that read this answer (Like me) and don't know the difference can read about it. – Jorge Fuentes González Jun 03 '13 at 16:50
4

ActivityManager#getRunningAppProcesses() returns a List of RunningAppProcessInfo. Each RunningAppProcessInfo has a field called importance. importance equal to RunningAppProcessInfo.IMPORTANCE_FOREGROUND seems to show which activity is actively being observed by the user. There is also RunningAppProcessInfo.IMPORTANCE_VISIBLE which is lower but might be worth checking out.

jqpubliq
  • 11,874
  • 2
  • 34
  • 26
  • After investigating the possibilities of the RunningAppProcess it turned out that the importance of the processes never changes. For my activity the importance has always been IMPORTANCE_FOREGROUND (100). That applied when the activities has not been started at all, the activity is active in the foreground or the activity stack is send to the back. No changes in the importance value. So sadly this is not a solution for my problem. :( Any other ideas? – Moritz Feb 23 '10 at 22:10
  • I tried starting up one of my projects and then popping another one on top of it and the one in the background did go to IMPORTANCE_BACKGROUND(400). It only seems to show package name of the whole project as well. Is your service part of the package that you are trying to check? maybe having the debugger attached is elevating the importance or something. – jqpubliq Feb 24 '10 at 01:34
  • Interesting that you describe it to work. Maybe it makes a difference since i am checking the processes from a BroadcastReceiver and not from the activity itself. Btw, i am testing on the emulator in regular launch mode. – Moritz Feb 24 '10 at 08:51
3

check out my solution for determining if an activity is in the foreground: http://www.mannaz.at/codebase/android-activity-foreground-surveillance/

It should be easy to revert the logic from "in the foreground" to "not in the foreground".

whlk
  • 15,487
  • 13
  • 66
  • 96
3

I have implemented a BroadcastReceiver which is triggered by the AlarmManager. The AlarmManager is initialized on BOOT_COMPLETED. So i have to declare the receiver in the manifest.

My problem is that i want the BroadcastReceiver only to do something when none of my own activities are in the foreground (aka the user is not interacting with my application). I pull information from a remote server and don't want to notify the user if he is currently in my application anyways.

So far i have not managed to find a way to determine if my application is in the foreground. Is there a way to do such thing? The ActivityManager tells me if my application is running but not whether it is in the foreground.

There doesn't seem to be a direct way to determine if one of your activities is the current running foreground activity. However, you can get the desired effect by using an ordered broadcast and two broadcast receivers. One broadcast receiver needs to be registered in OnResume() and unregistered in OnPause(). The 2nd broadcast receiver will be declared in your manifest as you've already done. Set the android:priority for your receivers such that if the dynamically registered receiver is registered, it will receive the intent first, then you can eat the intent so that the broadcast receiver you registered in your manifest is never notified.

Community
  • 1
  • 1
Pastiche
  • 31
  • 1
1

I'd use ActivityLifecycleCallbacks to get much cleaner solution.

It can be insecure, read this before you decided to use example below in production. It works in 'home development' for my device and OS version.

public class App extends Application implements Application.ActivityLifecycleCallbacks {

private boolean inForeground;

@Override
public void onCreate() {
    super.onCreate();
    registerActivityLifecycleCallbacks(this);
}

@Override
public void onActivityResumed(Activity activity) {
    inForeground = activity instanceof YourActivity;
}

public boolean isInForeground() {
    return inForeground;
}

Register App in AndroidManifest:

<application
        android:name=".App" />

And the final piece of the puzzle:

public class YourReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        App app = (App) context.getApplicationContext();
        if(app.isInForeground()){
            // do some stuff
        }
    }
}
Community
  • 1
  • 1
klimat
  • 24,711
  • 7
  • 63
  • 70
1

You can test if the window has focus - but as stated in dev docs this is not the same as if activity is in foreground.

surtyaar
  • 2,532
  • 1
  • 18
  • 13