Определение текущего приложения переднего плана из фоновой задачи или службы - PullRequest
101 голосов
/ 30 января 2010

Я хочу, чтобы одно приложение работало в фоновом режиме, которое знает, когда работает любое из встроенных приложений (обмен сообщениями, контакты и т. Д.)

Итак, мои вопросы:

  1. Как мне запустить приложение в фоновом режиме.

  2. Как мое фоновое приложение может узнать, какое приложение в данный момент выполняется на переднем плане.

Буду признателен за ответы от людей с опытом.

Ответы [ 13 ]

99 голосов
/ 01 октября 2012

Относительно «2. Как мое фоновое приложение может узнать, какое приложение в данный момент выполняется на переднем плане».

НЕ ИСПОЛЬЗУЙТЕ метод getRunningAppProcesses(), так как он возвращает все виды системного мусора из моего опыта, и вы получите несколько результатов с RunningAppProcessInfo.IMPORTANCE_FOREGROUND. Используйте getRunningTasks() вместо

Это код, который я использую в своем сервисе для идентификации текущего приложения переднего плана, это действительно просто:

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

Вот так, тогда вы можете легко получить доступ к деталям приложения / деятельности переднего плана:

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

Для этого требуется дополнительное разрешение в манифесте активности и работает отлично.

<uses-permission android:name="android.permission.GET_TASKS" />
38 голосов
/ 03 апреля 2011

Я должен был найти правильное решение трудным путем.приведенный ниже код является частью cyanogenmod7 (твик планшета) и тестируется на android 2.3.3 / gingerbread.

методы:

  • getForegroundApp - возвращает приложение переднего плана.
  • getActivityForApp - возвращает активность найденного приложения.
  • isStillActive - определяет, является ли ранее найденное приложение все еще активным приложением.
  • isRunningService - вспомогательная функция для getForegroundApp

это, мы надеемся, ответит на эту проблему во всех аспектах(:

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;
}
31 голосов
/ 28 декабря 2010

Попробуйте следующий код:

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

Имя процесса - это имя пакета приложения, работающего на переднем плане. Сравните это с именем пакета вашего приложения. Если это так, то ваше приложение работает на переднем плане.

Надеюсь, это ответит на ваш вопрос.

23 голосов
/ 11 июня 2015

Начиная с леденцов, это изменилось. Пожалуйста, найдите ниже код, прежде чем этот пользователь должен перейти Настройки -> Безопасность -> (Прокрутить до конца) Приложения с доступом использования -> Дать разрешения для нашего приложения

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);
}
8 голосов
/ 18 января 2017

Учитывая, что getRunningTasks() устарело, а getRunningAppProcesses() ненадежно, я решил объединить 2 подхода, упомянутых в 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();
        }
    }
6 голосов
/ 30 января 2010

Класс ActivityManager является подходящим инструментом для просмотра запущенных процессов.

Для запуска в фоновом режиме обычно требуется Сервис .

5 голосов
/ 29 августа 2016

Чтобы определить приложение переднего плана, вы можете использовать для обнаружения приложение переднего плана, вы можете использовать https://github.com/ricvalerio/foregroundappchecker. Он использует различные методы в зависимости от версии устройства для Android.

Что касается услуги, то в репозитории также указан код, который вам необходим. По сути, пусть Android Studio создаст для вас сервис, а затем при создании добавит фрагмент, который использует appChecker. Однако вам нужно будет запросить разрешение.

4 голосов
/ 08 марта 2018

Для случаев, когда нам нужно проверить из нашего собственного сервиса / background-thread, находится ли наше приложение на переднем плане или нет. Вот как я это реализовал, и он прекрасно работает для меня:

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
}

Теперь, чтобы проверить из других классов, находится ли приложение на переднем плане или нет, просто позвоните:

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

Обновление (как указано SHS ):

Не забудьте зарегистрироваться для обратных вызовов в методе onCreate класса вашего приложения.

@Override
public void onCreate() {
    ...
    registerActivityLifecycleCallbacks(this);
}
1 голос
/ 15 декабря 2014

Это сработало для меня. Но это дает только название главного меню. То есть, если пользователь открыл окно «Настройки» -> «Bluetooth» -> «Имя устройства», RunningAppProcessInfo называет его просто «Настройки». Не в состоянии сверлить Фуртур

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());
                    }               
                }
0 голосов
/ 09 августа 2017

Я объединил два решения в одном методе, и он работает для меня для API 24 и для API 21. Другие я не тестировал.

Код в Котлине:

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

и в Манифесте

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