Determining the current foreground application from a background task or service

后端 未结 13 1431
我寻月下人不归
我寻月下人不归 2020-11-22 02:29

I wish to have one application that runs in the background, which knows when any of the built-in applications (messaging, contacts, etc) is running.

So my questions

相关标签:
13条回答
  • 2020-11-22 02:52

    In lollipop and up:

    Add to mainfest:

    <uses-permission android:name="android.permission.GET_TASKS" />
    

    And do something like this:

    if( mTaskId < 0 )
    {
        List<AppTask> tasks = mActivityManager.getAppTasks(); 
        if( tasks.size() > 0 )
            mTaskId = tasks.get( 0 ).getTaskInfo().id;
    }
    
    0 讨论(0)
  • 2020-11-22 02:54

    With regards to "2. How my background application can know what the application currently running in the foreground is."

    Do NOT use the getRunningAppProcesses() method as this returns all sorts of system rubbish from my experience and you'll get multiple results which have RunningAppProcessInfo.IMPORTANCE_FOREGROUND. Use getRunningTasks() instead

    This is the code I use in my service to identify the current foreground application, its really easy:

    ActivityManager am = (ActivityManager) AppService.this.getSystemService(ACTIVITY_SERVICE);
    // The first in the list of RunningTasks is always the foreground task.
    RunningTaskInfo foregroundTaskInfo = am.getRunningTasks(1).get(0);
    

    Thats it, then you can easily access details of the foreground app/activity:

    String foregroundTaskPackageName = foregroundTaskInfo .topActivity.getPackageName();
    PackageManager pm = AppService.this.getPackageManager();
    PackageInfo foregroundAppPackageInfo = pm.getPackageInfo(foregroundTaskPackageName, 0);
    String foregroundTaskAppName = foregroundAppPackageInfo.applicationInfo.loadLabel(pm).toString();
    

    This requires an additional permission in activity menifest and works perfectly.

    <uses-permission android:name="android.permission.GET_TASKS" />
    
    0 讨论(0)
  • 2020-11-22 02:54

    In order to determine the foreground application, you can use for detecting the foreground app, you can use https://github.com/ricvalerio/foregroundappchecker. It uses different methods depending on the android version of the device.

    As for the service, the repo also provides the code you need for it. Essentially, let android studio create the service for you, and then onCreate add the snippet that uses the appChecker. You will need to request permission however.

    0 讨论(0)
  • 2020-11-22 02:57

    Try the following code:

    ActivityManager activityManager = (ActivityManager) newContext.getSystemService( Context.ACTIVITY_SERVICE );
    List<RunningAppProcessInfo> appProcesses = activityManager.getRunningAppProcesses();
    for(RunningAppProcessInfo appProcess : appProcesses){
        if(appProcess.importance == RunningAppProcessInfo.IMPORTANCE_FOREGROUND){
            Log.i("Foreground App", appProcess.processName);
        }
    }
    

    Process name is the package name of the app running in foreground. Compare it to the package name of your application. If it is the same then your application is running on foreground.

    I hope this answers your question.

    0 讨论(0)
  • 2020-11-22 02:58

    For cases when we need to check from our own service/background-thread whether our app is in foreground or not. This is how I implemented it, and it works fine for me:

    public class TestApplication extends Application implements Application.ActivityLifecycleCallbacks {
    
        public static WeakReference<Activity> foregroundActivityRef = null;
    
        @Override
        public void onActivityStarted(Activity activity) {
            foregroundActivityRef = new WeakReference<>(activity);
        }
    
        @Override
        public void onActivityStopped(Activity activity) {
            if (foregroundActivityRef != null && foregroundActivityRef.get() == activity) {
                foregroundActivityRef = null;
            }
        }
    
        // IMPLEMENT OTHER CALLBACK METHODS
    }
    

    Now to check from other classes, whether app is in foreground or not, simply call:

    if(TestApplication.foregroundActivityRef!=null){
        // APP IS IN FOREGROUND!
        // We can also get the activity that is currently visible!
    }
    

    Update (as pointed out by SHS):

    Do not forget to register for the callbacks in your Application class's onCreate method.

    @Override
    public void onCreate() {
        ...
        registerActivityLifecycleCallbacks(this);
    }
    
    0 讨论(0)
  • 2020-11-22 03:10

    i had to figure out the right solution the hard way. the below code is part of cyanogenmod7 (the tablet tweaks) and is tested on android 2.3.3 / gingerbread.

    methods:

    • getForegroundApp - returns the foreground application.
    • getActivityForApp - returns the activity of the found app.
    • isStillActive - determines if a earlier found app is still the active app.
    • isRunningService - a helper function for getForegroundApp

    this hopefully answers this issue in all extend (:

    private RunningAppProcessInfo getForegroundApp() {
        RunningAppProcessInfo result=null, info=null;
    
        if(mActivityManager==null)
            mActivityManager = (ActivityManager)mContext.getSystemService(Context.ACTIVITY_SERVICE);
        List <RunningAppProcessInfo> l = mActivityManager.getRunningAppProcesses();
        Iterator <RunningAppProcessInfo> i = l.iterator();
        while(i.hasNext()){
            info = i.next();
            if(info.importance == RunningAppProcessInfo.IMPORTANCE_FOREGROUND
                    && !isRunningService(info.processName)){
                result=info;
                break;
            }
        }
        return result;
    }
    
    private ComponentName getActivityForApp(RunningAppProcessInfo target){
        ComponentName result=null;
        ActivityManager.RunningTaskInfo info;
    
        if(target==null)
            return null;
    
        if(mActivityManager==null)
            mActivityManager = (ActivityManager)mContext.getSystemService(Context.ACTIVITY_SERVICE);
        List <ActivityManager.RunningTaskInfo> l = mActivityManager.getRunningTasks(9999);
        Iterator <ActivityManager.RunningTaskInfo> i = l.iterator();
    
        while(i.hasNext()){
            info=i.next();
            if(info.baseActivity.getPackageName().equals(target.processName)){
                result=info.topActivity;
                break;
            }
        }
    
        return result;
    }
    
    private boolean isStillActive(RunningAppProcessInfo process, ComponentName activity)
    {
        // activity can be null in cases, where one app starts another. for example, astro
        // starting rock player when a move file was clicked. we dont have an activity then,
        // but the package exits as soon as back is hit. so we can ignore the activity
        // in this case
        if(process==null)
            return false;
    
        RunningAppProcessInfo currentFg=getForegroundApp();
        ComponentName currentActivity=getActivityForApp(currentFg);
    
        if(currentFg!=null && currentFg.processName.equals(process.processName) &&
                (activity==null || currentActivity.compareTo(activity)==0))
            return true;
    
        Slog.i(TAG, "isStillActive returns false - CallerProcess: " + process.processName + " CurrentProcess: "
                + (currentFg==null ? "null" : currentFg.processName) + " CallerActivity:" + (activity==null ? "null" : activity.toString())
                + " CurrentActivity: " + (currentActivity==null ? "null" : currentActivity.toString()));
        return false;
    }
    
    private boolean isRunningService(String processname){
        if(processname==null || processname.isEmpty())
            return false;
    
        RunningServiceInfo service;
    
        if(mActivityManager==null)
            mActivityManager = (ActivityManager)mContext.getSystemService(Context.ACTIVITY_SERVICE);
        List <RunningServiceInfo> l = mActivityManager.getRunningServices(9999);
        Iterator <RunningServiceInfo> i = l.iterator();
        while(i.hasNext()){
            service = i.next();
            if(service.process.equals(processname))
                return true;
        }
    
        return false;
    }
    
    0 讨论(0)
提交回复
热议问题