0

I have an App with a LoginScreen. The App also logout the User after a certain amount of time. I use a AlarmManager and a BroadcastReceiver for doing this. But in my BroadcastReceiver.onReceive() i need to know is my App in foreground or not!!

I've found some source like this:

private boolean isAppInBackground(){
 boolean retValue = true;
 ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
    List<ActivityManager.RunningAppProcessInfo> runningProcesses = am.getRunningAppProcesses();
    for (ActivityManager.RunningAppProcessInfo processInfo : runningProcesses) {
        if (processInfo.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND) {
            for (String activeProcess : processInfo.pkgList) {
                if (activeProcess.equals(context.getPackageName())) {
                    retValue = false;
                }
            }
        }
    }
 return retValue;
}

it works on my API 21 Device... but it always brings false at my API 18 Device!!

Question 1 is: what can I do for a API18 Device?

Question 2 is: Will I get a reject from Google if I go to the PlayStore with this App?? Because Google said here

Note: this method is only intended for debugging or building a user-facing process management UI.

And one Comment from here said something from "reject"

UPDATE:

To be a bit more clear: For Example after 5 minutes the Broadcast Receiver get's BroadcastReceiver.onReceive(). Now the LoginActivity has to be called and the User must login again to use the App.

But if the User has my App not in Foreground (because he is using Maps or EMail at this Time) the Login Activity should NOT popup in Foreground so i send it in Background with

moveTaskToBack(true);

But i look for a way to clearly find out is my app in Background or Foreground in the Moment when BroadcastReceiver.onReceive() comes up.

Community
  • 1
  • 1
HowardS
  • 75
  • 1
  • 9

2 Answers2

0

Involve some EventBus in your application. Maybe one from GreenRobot.

In your BroadcastReceiver just send an event that time has elapsed and then in your Activities register for this event. If some Activity is visible and active - it will receive that event and then you can logout your user. You won't have to check that your app is in background because when you register and unregister your Activities from EventBus in right time they would react only when they are in Foreground.

Right time to register on unregister I meant onResume and onPause methods (or onCreate/onDestroy).

PS. With this solution you shouldn't get rejected from Play Store.

Pawel Urban
  • 1,316
  • 1
  • 12
  • 28
  • THIS is a nice suggestion ... also because I use already the EventBus... BUT it solves not really my Problem to know is my App in foreground or not. Okay the Event is not received because I unregister the EventBus but first of all I need the Event to logout from my App if the Timer comes and then how i solve the Foreground/Background issue with that?? Could be i misunderstood your Solution... sorry – HowardS Sep 17 '15 at 15:59
  • @HowardS OK, but you didn't mention what logout action and Foreground/background action has in common. Maybe you should extend your description of your application login for us to understand what is your point ? – Pawel Urban Sep 18 '15 at 06:19
0

After Years of investigation i found a Solution for MY special Problem.

Inspired by this Answer u start using ActivityLifecycleCallbacks like this:

public class MyLifecycleHandler implements Application.ActivityLifecycleCallbacks {    
private static ActivityNames activityNameList = new ActivityNames();

@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
    activityNameList.add(activity.getLocalClassName().hashCode());
}

@Override
public void onActivityDestroyed(Activity activity) {
    activityNameList.remove(activity.getLocalClassName().hashCode());
}

@Override
public void onActivityResumed(Activity activity) {
    activityNameList.add(activity.getLocalClassName().hashCode());
}

@Override
public void onActivityPaused(Activity activity) {
    activityNameList.remove(activity.getLocalClassName().hashCode());
}

@Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
    activityNameList.remove(activity.getLocalClassName().hashCode());
}

@Override
public void onActivityStarted(Activity activity) {
    activityNameList.add(activity.getLocalClassName().hashCode());
}

@Override
public void onActivityStopped(Activity activity) {
    activityNameList.remove(activity.getLocalClassName().hashCode());
}

public static boolean isApplicationInBackground() {
    return activityNameList.isApplicationInBackground();
}

private static class ActivityNames {
    private List<Integer> nameList;

    void add(int value){
        if(nameList == null){
            nameList = new ArrayList<>();
        }

        if(nameList.contains(value)) return;

        nameList.add(value);
    }

     void remove(Integer value){
         if(nameList == null || nameList.size() < 1) return;
         nameList.remove(value);
     }

    boolean isApplicationInBackground(){
        if(nameList == null) return true;
        if(nameList.size() == 0) return true;

        return false;
    }
  }
}

My BroadcastReceiver to receive the AlarmManager looks like this:

public class LogoutReceiver extends BroadcastReceiver {
   @Override
   public void onReceive(Context context, Intent intent) {
       ContextUtils.appIsInBackground = MyLifecycleHandler.isApplicationInBackground();
       EventBus.getDefault().post(new AutoLogoutEvent());
    }
}

ContextUtils() just hold the Value in the Moment when the Receiver gets called for later use.

AutoLogoutEvent() is catched and calls this Intent Function:

public void showAuthentication(Activity context) {

    Intent i = new Intent(context, LoginActivity.class);

    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
        ContextUtils.appIsInBackground = false;
    }

    context.startActivity(i);
}

Special here: Android Versions prior KITKAT (API19) didn't start the Activity if the App is in Background. So i have to set back this ContextUtils.appIsInBackground because if not so, and you try to get Back the App to Foreground in this Moment the onCreate() of the Activity is called but has the wrong Value and the App comes not to Foreground the first time... you have to click twice. Here the Activity:

public class LoginActivity extends MosbyActivity {

   @Override
   protected void onCreate(Bundle savedInstanceState) {        
       boolean appIsInBackground = false;

       appIsInBackground = ContextUtils.appIsInBackground;
       ContextUtils.appIsInBackground = false;

       if(appIsInBackground){
           moveTaskToBack(true);
       }

       super.onCreate(savedInstanceState);

       setContentView(R.layout.activity_login);

       if (savedInstanceState == null) {
           getSupportFragmentManager().beginTransaction()
                .replace(R.id.fragmentContainer, new LoginFragment())
                .commit();
       }
   }

   ....
}

so this WORKS for ME. May you find a better Solution... Please let me know!!!

Community
  • 1
  • 1
HowardS
  • 75
  • 1
  • 9