3

I have a background service doing some work - retrieving user location by interval (launched with startService). As soon special condition reached I'd like to do the following:

  1. If application is in foreground then start specific activity.
  2. If application is not in foreground or closed then show the notification that will start required activity on tap.

I know how to show notification and how handle intent from server with broadcast receiver for example. But how can I determint if my application is in foreground? Or may be you can suggest complete better solution?

Sergey Metlov
  • 25,747
  • 28
  • 93
  • 153

2 Answers2

1

I determint if my application is in foreground

There's couple of ways to find out what is in front, but I actually prefer to track this myself (as this helps me apply additional logic if needed). Plus it's pretty simple task. To make this happen you need static int based counter somewhere (you can use your Application object if you have one, or have it elsewhere, does not really matter). In each Activity's onResume() you increment the counter by one, and in onPause() you decrement it by one. If counter equals 0 then none of your activities is in foreground so from your perspective you are in background and you post notification. For simplicity I always do that in my ActivityBase class all my activities extend.

If you do not want to track it yourself, you can use ActivityManager to see what's currently in foreground:

public boolean isAppInForeground() {
    ActivityManager am = (ActivityManager)getSystemService(Context.ACTIVITY_SERVICE);
    List<RunningTaskInfo> services = am.getRunningTasks(Integer.MAX_VALUE);

    return (services.get(0).topActivity.getPackageName().toString()
                        .equalsIgnoreCase(getPackageName().toString()));
 }

but this requires <uses-permission android:name="android.permission.GET_TASKS" /> entry in your Manifest, so not always welcome.

Marcin Orlowski
  • 72,056
  • 11
  • 123
  • 141
  • A couple of additional questions. May I be sure static field is shared between application and service lifetime scopes? What if application is completely closed but service running? Also what if application crashed? Does doing the actions related to the opened application in broadcast receiver a good idea? – Sergey Metlov Apr 29 '15 at 18:54
  • I added `ActivityManager` based approach as well. As for your questions: you can either use `Application` object subclass if your app uses any as you always got one Application object per app. Alternatively you may keep your counter in Singleton, but please [see this question](http://stackoverflow.com/questions/2423622/volatile-vs-static-in-java) if you use Threads in your app. – Marcin Orlowski Apr 29 '15 at 19:03
  • One application object per app doesn't apply if you're running multiple processes. The same static objects will be available between the application class and services if they're in the same process. If a service in the same process as the application is running, the application will also be running. Responding to broadcasts is good, but should be aware of the security issues with them, also, the callback has to respond within 5 seconds, so need to pass any heavy work off to a service – FunkTheMonk Apr 30 '15 at 08:23
  • btw, use of getRunningTasks and friends is considered bad practice, https://code.google.com/p/android-developer-preview/issues/detail?id=29 – FunkTheMonk Apr 30 '15 at 08:30
0

An alternative to Marcin's answers is to bind and unbind your Activities to the Service. This will allow communication between the Service and Activity whilst that binding exists, and the Service will know if an Activity that is capable of handling the scenario is currently available - e.g. you may not want to launch the Activity directly if the user is in the middle of some important process (like accepting the T&Cs / EULA or something), so the Service can tell the Activity that an event has happened, but the Activity can respond to the event correctly.

FunkTheMonk
  • 10,908
  • 1
  • 31
  • 37
  • Do you mean both starting service with `startService` and `binsService` and if binder is alive then send info to it and show notification otherwise? – Sergey Metlov Apr 30 '15 at 08:31
  • Yeah that is what I mean. A bound only service will only stay alive whilst something is bound to it, so if you want the service to be active whilst the ui isn't on screen, yes start the activity and then bind to it as well. Note that a started service has to be explicitly stopped, so if it is doing anything battery draining you should have a time out or something to ensure it isn't running all of the time. – FunkTheMonk Apr 30 '15 at 08:42