18

I have a timer that start a notification when it ends. But I would like to fire a notification using notificationManager only if the app is not currently visible, and to show an alertDialog if the timer ends while the app is in foreground.

I've already tried with this :

ActivityManager actMngr = (ActivityManager) ValeoMobileApplication.getContext().getSystemService(Activity.ACTIVITY_SERVICE);
List<RunningAppProcessInfo> runningAppProcesses = actMngr.getRunningAppProcesses();
Tools.log("TimerBroadcastReceiver", "onReceive", "All running processes are listed below :");
for (RunningAppProcessInfo pi : runningAppProcesses) {
    //Check pi.processName and do your stuff
    //also check pi importance - check if process is in foreground or background
    Tools.log("TimerBroadcastReceiver", "onReceive", pi.processName + " importance = "+pi.importance);
    if(pi.processName.equalsIgnoreCase("MY_APP_PROCESS_NAME")){
        if (pi.importance == RunningAppProcessInfo.IMPORTANCE_FOREGROUND) {
            isApplicationInForeground = true;
        }
    }
}

But it seems that it doesn't matter if the app is foreground or not. How can I do this?

Tunaki
  • 132,869
  • 46
  • 340
  • 423
PhilippeAuriach
  • 2,418
  • 2
  • 22
  • 41
  • [ProcessLifecycleOwner](https://stackoverflow.com/a/54684819/6017001) is the newest solution – S.R Feb 14 '19 at 07:08

4 Answers4

26

But I would like to fire a notification using notificationManager only if the app is not currently visible, and to show an alertDialog if the timer ends while the app is in foreground.

Use an ordered broadcast, with the activity having a high-priority receiver if it is in the foreground, plus a manifest-registered receiver for the cases when it is not in the foreground.

Here is a blog post outlining this technique.

UPDATE 2018-01-04: The approach described above works, but it involves system broadcasts, which is not a great choice for most (single-process) apps. An event bus (LocalBroadcastManager, greenrobot's EventBus) can be used instead, with better performance and security. See this sample app that uses LocalBroadcastManager and this sample app that uses greenrobot's EventBus, both of which implement this pattern.

CommonsWare
  • 986,068
  • 189
  • 2,389
  • 2,491
  • 3
    This doesn't work well, if your main activity, is launching another new activity. At that time, un-register will happen as onPause is triggered. However, from end user point of view, the app is still visible. – Cheok Yan Cheng Apr 11 '13 at 03:29
  • As I understand, this approach doesn't work anymore with Android Oreo. Because it's not possible to register implicit receiver via manifest anymore. – MyDogTom Jan 04 '18 at 13:59
  • 1
    @MyDogTom: This approach would still work, as you would be using an explicit `Intent`, not an implicit `Intent`. That being said, there are better approaches nowadays (e.g., event buses). – CommonsWare Jan 04 '18 at 14:01
11

You can detect whether your app is visible or not the following way:

In all your your Activity, set:

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

    myVisibilityManager.setIsVisible(true);
}

@Override
protected void onPause() {
    myVisibilityManager.setIsVisible(false);

    super.onPause();
}

(this may lead you to define a superclass to all your activities that would implement this behaviour)

Then create a VisibilityManager (this one is very basic, you may need something more advanced):

public class VisibilityManager {
    private boolean mIsVisible = false;

    public void setIsVisible(boolean visible) { 
         mIsVisible = visible; 
    }

    public boolean getIsVisible() {
         return mIsVisible;
    }
}

And then, in your timer thread, when the countdown reached zero:

if (VisibilityManager.getIsVisible()) {
    showAlertDialog();
}
else {
    showNotification();
}

EDIT: but I even prefer the CommonsWare's approach described here in this page. It is more elegant.

Shlublu
  • 10,917
  • 4
  • 51
  • 70
  • CommonsWare approach was clever and interesting. However, this approach is straight forward. We may probably want to know whether the application is on the foreground elsewhere. So I am choosing this. – rpattabi May 10 '15 at 14:34
  • methods and var in VisibilityManager should be static – Lester Aug 26 '15 at 15:17
0

I would advise you use a Service rather than an activity in this case.

A service runs in the background and is not affected by the activity lifecycle if it is started correctly.

One important thing to remember is that when you go back to the UI, the service must explicitly call the UI thread, otherwise you will get ANR errors, as the UI thread is not threadsafe.

Please read through that document, it should help you get a better solution for what you're trying to do!

Hope this helped

Codeman
  • 12,157
  • 10
  • 53
  • 91
-1

Here is the solution:

public static boolean uygulamaCalisiyormu(Context context)
    {
        ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
        List<ActivityManager.RunningAppProcessInfo> islemler = activityManager.getRunningAppProcesses();
        for (ActivityManager.RunningAppProcessInfo uygulamaIslemi : islemler)
        {
            if (uygulamaIslemi.processName.equals(context.getPackageName()))
            {
                if (uygulamaIslemi.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE || uygulamaIslemi.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND)
                {
                    return true;
                }
            }
        }
        return false;
    }


...
 if (uygulamaCalisiyormu(getApplicationContext()))
        {
            Log.d("asd","App Already Started");
        }
      else
        {
Log.d("asd","App Started");
}

EDIT: If you want to check specific activity (class) use this;

  if (uygulamaIslemi.processName.equals("com.TRSoft.timetab:PIN"))
            {
                if (uygulamaIslemi.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE || uygulamaIslemi.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND) // Lanet olasıca şey Visible ile Foreground arasındaki fark ne oç illaha ya da yı kullanarak olduğunu keşfetmem mi lazım!
                {
                    return true;
                }
            }

And at your Manifest File:

 <activity android:name=".PINSayfasi"
            android:process=":PIN"></activity>

So the main logic is opening and reading process.