wake-up-neo.net

Bestimmen der aktuellen Vordergrundanwendung aus einer Hintergrundaufgabe oder einem Hintergrunddienst

Ich möchte eine Anwendung haben, die im Hintergrund ausgeführt wird und weiß, wann eine der integrierten Anwendungen (Messaging, Kontakte usw.) ausgeführt wird.

Meine Fragen sind also:

  1. Wie soll ich meine Anwendung im Hintergrund ausführen?.

  2. Wie meine Hintergrundanwendung wissen kann, welche Anwendung aktuell im Vordergrund ausgeführt wird.

Antworten von Leuten mit Erfahrung werden sehr geschätzt.

95
dhaiwat

In Bezug auf "2. Wie kann meine Hintergrundanwendung wissen, welche Anwendung derzeit im Vordergrund ausgeführt wird?" 

Verwenden Sie NICHT die getRunningAppProcesses()-Methode, da dies alle Arten von Systemmüll aus meiner Erfahrung zurückgibt und Sie mehrere Ergebnisse mit RunningAppProcessInfo.IMPORTANCE_FOREGROUND erhalten. Verwenden Sie stattdessen getRunningTasks()

Dies ist der Code, den ich in meinem Service zur Identifizierung der aktuellen Vordergrundanwendung verwende. Das ist wirklich einfach:

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

Das ist es, dann können Sie leicht auf Details der App/Aktivität im Vordergrund zugreifen:

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

Dies erfordert eine zusätzliche Erlaubnis im Aktivitätsmanifest und funktioniert einwandfrei.

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

ich musste auf die harte Tour die richtige Lösung finden. Der folgende Code ist Teil von Cyanogenmod7 (das Tablet verändert sich) und wurde unter Android 2.3.3/Gingerbread getestet. 

methoden:

  • getForegroundApp - gibt die Vordergrundanwendung zurück. 
  • getActivityForApp - gibt die Aktivität der gefundenen App zurück. 
  • isStillActive - Legt fest, ob eine zuvor gefundene App noch aktiv ist.
  • isRunningService - eine Hilfsfunktion für getForegroundApp

dies beantwortet hoffentlich dieses Problem in allen Bereichen (:

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

Versuchen Sie den folgenden 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);
    }
}

Prozessname ist der Paketname der App, die im Vordergrund ausgeführt wird. Vergleichen Sie es mit dem Paketnamen Ihrer Anwendung. Wenn dies der Fall ist, läuft Ihre Anwendung im Vordergrund.

Ich hoffe, das beantwortet deine Frage.

31
Friedrich Bhaer

Ab Lollipop wurde dies geändert. Nachstehend finden Sie den Code, bevor der Benutzer Einstellungen -> Sicherheit -> (bis zum letzten Bild nach unten) aufrufen muss. Apps mit Nutzungszugriff -> Erteilen Sie der App die Berechtigungen

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

In Anbetracht der Tatsache, dass getRunningTasks() veraltet ist und getRunningAppProcesses() nicht zuverlässig ist, habe ich beschlossen, zwei in StackOverflow genannte Ansätze zu kombinieren:

   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

Die Klasse ActivityManager ist das geeignete Werkzeug, um zu sehen, welche Prozesse ausgeführt werden.

Um im Hintergrund zu laufen, möchten Sie normalerweise einen Service verwenden.

6
Charles Duffy

Um die Vordergrundanwendung zu ermitteln, können Sie zur Erkennung der Vordergrundanwendung verwenden, indem Sie https://github.com/ricvalerio/foregroundappchecker verwenden. Je nach Android-Version des Geräts werden unterschiedliche Methoden verwendet.

Für den Service stellt das Repo auch den Code bereit, den Sie dafür benötigen. Lassen Sie Android Studio den Dienst für Sie erstellen, und fügen Sie dann das Snippet hinzu, das den appChecker verwendet. Sie müssen jedoch um Erlaubnis bitten.

4
rvalerio

Für den Fall, dass wir in unserem eigenen Service/Hintergrund-Thread prüfen müssen, ob unsere App im Vordergrund steht oder nicht. So habe ich es implementiert und es funktioniert gut für mich:

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
}

Um nun von anderen Klassen zu überprüfen, ob die App im Vordergrund steht oder nicht, rufen Sie einfach Folgendes auf:

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

Das hat bei mir funktioniert. Es gibt jedoch nur den Namen des Hauptmenüs. Wenn der Benutzer den Bildschirm Einstellungen -> Bluetooth -> Gerätename geöffnet hat, ruft RunningAppProcessInfo diesen nur als Einstellungen auf. Kann nicht weiter bohren

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

So überprüfe ich, ob meine App im Vordergrund steht. Hinweis Ich verwende AsyncTask , wie von offiziellen Android Dokumentation vorgeschlagen

`

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

und führen Sie AsyncTask wie folgt aus . new CheckIfForeground().execute();

0
Hammad Tariq

In Lollipop und höher:

Zum Manifest hinzufügen:

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

Und so etwas tun:

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

Tun Sie so etwas:

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

Ich habe zwei Lösungen in einer Methode kombiniert und es funktioniert für mich für API 24 und für API 21. Andere habe ich nicht getestet. 

Der Code in 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()
}

und in Manifest

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