web-dev-qa-db-fra.com

Détermination de l'application de premier plan actuelle à partir d'une tâche ou d'un service en arrière-plan

Je souhaite avoir une application qui s'exécute en arrière-plan, qui sait quand l'une des applications intégrées (messagerie, contacts, etc.) est en cours d'exécution.

Donc mes questions sont:

  1. Comment je dois exécuter mon application en arrière-plan.

  2. Comment mon application d'arrière-plan peut savoir quelle est l'application en cours d'exécution au premier plan.

Les réponses de personnes expérimentées seraient grandement appréciées.

95
dhaiwat

En ce qui concerne "2. Comment mon application d'arrière-plan peut savoir quelle est l'application en cours d'exécution au premier plan." 

N'utilisez PAS la méthode getRunningAppProcesses() car elle renvoie toutes sortes d'ordures système issues de mon expérience et vous obtiendrez plusieurs résultats comportant RunningAppProcessInfo.IMPORTANCE_FOREGROUND. Utilisez getRunningTasks() à la place

C’est le code que j’utilise dans mon service pour identifier l’application de premier plan actuelle, c’est très simple:

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);

Voilà, alors vous pouvez facilement accéder aux détails de l'application/activité de premier plan:

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

Cela nécessite une autorisation supplémentaire dans le manifeste d'activité et fonctionne parfaitement.

<uses-permission Android:name="Android.permission.GET_TASKS" />
98
Oliver Pearmain

je devais trouver la bonne solution à la dure. le code ci-dessous fait partie de cyanogenmod7 (les modifications de la tablette) et est testé sur Android 2.3.3/Gingerbread. 

méthodes:

  • getForegroundApp - renvoie l'application de premier plan. 
  • getActivityForApp - renvoie l'activité de l'application trouvée. 
  • isStillActive - détermine si une application précédemment trouvée est toujours l'application active.
  • isRunningService - une fonction d'assistance pour getForegroundApp

cela répond, espérons-le, à tous les problèmes (:

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;
}
38
Sven Dawitz

Essayez le code suivant:

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);
    }
}

Nom du processus est le nom du package de l'application qui s'exécute au premier plan. Comparez-le au nom du package de votre application. Si c'est la même chose, votre application s'exécute au premier plan.

J'espère que cela répond à votre question.

31
Friedrich Bhaer

À partir de Lollipop, cela a changé. Veuillez trouver le code ci-dessous, avant que cet utilisateur doive aller dans Paramètres -> Sécurité -> (défiler vers le bas) Applications avec accès utilisateur -> Donner les autorisations à notre application

private void printForegroundTask() {
    String currentApp = "NULL";
    if(Android.os.Build.VERSION.SDK_INT >= Android.os.Build.VERSION_CODES.Lollipop) {
        UsageStatsManager usm = (UsageStatsManager) this.getSystemService(Context.USAGE_STATS_SERVICE);
        long time = System.currentTimeMillis();
        List<UsageStats> appList = usm.queryUsageStats(UsageStatsManager.INTERVAL_DAILY,  time - 1000*1000, time);
        if (appList != null && appList.size() > 0) {
            SortedMap<Long, UsageStats> mySortedMap = new TreeMap<Long, UsageStats>();
            for (UsageStats usageStats : appList) {
                mySortedMap.put(usageStats.getLastTimeUsed(), usageStats);
            }
            if (mySortedMap != null && !mySortedMap.isEmpty()) {
                currentApp = mySortedMap.get(mySortedMap.lastKey()).getPackageName();
            }
        }
    } else {
        ActivityManager am = (ActivityManager)this.getSystemService(Context.ACTIVITY_SERVICE);
        List<ActivityManager.RunningAppProcessInfo> tasks = am.getRunningAppProcesses();
        currentApp = tasks.get(0).processName;
    }

    Log.e(TAG, "Current App in foreground is: " + currentApp);
}
21
Suman

Compte tenu du fait que getRunningTasks() est obsolète et que getRunningAppProcesses() n'est pas fiable, j'ai pris la décision de combiner deux approches mentionnées dans StackOverflow:

   private boolean isAppInForeground(Context context)
    {
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Lollipop)
        {
            ActivityManager am = (ActivityManager) context.getSystemService(ACTIVITY_SERVICE);
            ActivityManager.RunningTaskInfo foregroundTaskInfo = am.getRunningTasks(1).get(0);
            String foregroundTaskPackageName = foregroundTaskInfo.topActivity.getPackageName();

            return foregroundTaskPackageName.toLowerCase().equals(context.getPackageName().toLowerCase());
        }
        else
        {
            ActivityManager.RunningAppProcessInfo appProcessInfo = new ActivityManager.RunningAppProcessInfo();
            ActivityManager.getMyMemoryState(appProcessInfo);
            if (appProcessInfo.importance == IMPORTANCE_FOREGROUND || appProcessInfo.importance == IMPORTANCE_VISIBLE)
            {
                return true;
            }

            KeyguardManager km = (KeyguardManager) context.getSystemService(Context.KEYGUARD_SERVICE);
            // App is foreground, but screen is locked, so show notification
            return km.inKeyguardRestrictedInputMode();
        }
    }
8
Sa Qada

La classe ActivityManager est l'outil approprié pour voir quels processus sont en cours d'exécution.

Pour exécuter en arrière-plan, vous voulez généralement utiliser un Service .

6
Charles Duffy

Afin de déterminer l'application de premier plan, vous pouvez utiliser pour détecter l'application de premier plan, vous pouvez utiliser https://github.com/ricvalerio/foregroundappchecker . Il utilise différentes méthodes en fonction de la version Android de l'appareil.

En ce qui concerne le service, le référentiel fournit également le code dont vous avez besoin. Pour l’essentiel, laissez Android studio créer le service pour vous, puis onCreate, ajoutez l’extrait de code qui utilise appChecker. Vous devrez toutefois demander une autorisation.

4
rvalerio

Dans les cas où nous devons vérifier depuis notre propre service/background-thread si notre application est au premier plan ou non. Voici comment je l'ai implémenté et cela fonctionne très bien pour moi:

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
}

Maintenant, pour vérifier à partir d'autres classes, si l'application est au premier plan ou non, appelez simplement:

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

Cela a fonctionné pour moi. Mais il ne donne que le nom du menu principal. C'est-à-dire que si l'utilisateur a ouvert l'écran Paramètres -> Bluetooth -> Nom du périphérique, RunningAppProcessInfo l'appelle uniquement en tant que paramètres. Pas capable de creuser furthur

ActivityManager activityManager = (ActivityManager) context.getSystemService( Context.ACTIVITY_SERVICE );
                PackageManager pm = context.getPackageManager();
                List<RunningAppProcessInfo> appProcesses = activityManager.getRunningAppProcesses();
                for(RunningAppProcessInfo appProcess : appProcesses) {              
                    if(appProcess.importance == RunningAppProcessInfo.IMPORTANCE_FOREGROUND) {
                        CharSequence c = pm.getApplicationLabel(pm.getApplicationInfo(appProcess.processName, PackageManager.GET_META_DATA));
                        Log.i("Foreground App", "package: " + appProcess.processName + " App: " + c.toString());
                    }               
                }
1
NakulSargur

Voici comment je vérifie si mon application est au premier plan. Remarque J'utilise AsyncTask comme suggéré par le fonctionnaire Android documentation.`

`

    private class CheckIfForeground extends AsyncTask<Void, Void, Void> {
    @Override
    protected Void doInBackground(Void... voids) {

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

                if (mContext.getPackageName().equalsIgnoreCase(appProcess.processName)) {
                    Log.i(Constants.TAG, "foreground true:" + appProcess.processName);
                    foreground = true;
                    // close_app();
                }
            }
        }
        Log.d(Constants.TAG, "foreground value:" + foreground);
        if (foreground) {
            foreground = false;
            close_app();
            Log.i(Constants.TAG, "Close App and start Activity:");

        } else {
            //if not foreground
            close_app();
            foreground = false;
            Log.i(Constants.TAG, "Close App");

        }

        return null;
    }
}

et exécutez AsyncTask comme ceci . new CheckIfForeground().execute();

0
Hammad Tariq

En sucette et plus:

Ajouter au manifeste:

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

Et fais quelque chose comme ça:

if( mTaskId < 0 )
{
    List<AppTask> tasks = mActivityManager.getAppTasks(); 
    if( tasks.size() > 0 )
        mTaskId = tasks.get( 0 ).getTaskInfo().id;
}
0
rubmz

Faites quelque chose comme ça:

int showLimit = 20;

/* Get all Tasks available (with limit set). */
ActivityManager mgr = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
List<ActivityManager.RunningTaskInfo> allTasks = mgr.getRunningTasks(showLimit);
/* Loop through all tasks returned. */
for (ActivityManager.RunningTaskInfo aTask : allTasks) 
{                  
    Log.i("MyApp", "Task: " + aTask.baseActivity.getClassName()); 
    if (aTask.baseActivity.getClassName().equals("com.Android.email.activity.MessageList")) 
        running=true;
}
0
ChristianS

J'ai combiné deux solutions dans une méthode et cela fonctionne pour moi pour API 24 et pour API 21. D'autres solutions n'ont pas été testées. 

Le code en Kotlin: 

private fun isAppInForeground(context: Context): Boolean {
    val appProcessInfo = ActivityManager.RunningAppProcessInfo()
    ActivityManager.getMyMemoryState(appProcessInfo)
    if (appProcessInfo.importance == IMPORTANCE_FOREGROUND ||
            appProcessInfo.importance == IMPORTANCE_VISIBLE) {
        return true
    } else if (appProcessInfo.importance == IMPORTANCE_TOP_SLEEPING ||
            appProcessInfo.importance == IMPORTANCE_BACKGROUND) {
        return false
    }

    val am = context.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
    val foregroundTaskInfo = am.getRunningTasks(1)[0]
    val foregroundTaskPackageName = foregroundTaskInfo.topActivity.packageName
    return foregroundTaskPackageName.toLowerCase() == context.packageName.toLowerCase()
}

et en manifeste

<!-- Check whether app in background or foreground -->
<uses-permission Android:name="Android.permission.GET_TASKS" />