getRunningTasks在Android L中不起作用

Lig*_*Yao 50 android android-5.0-lollipop

在Android L中,Google已禁用getRunningTasks.现在它只能返回自己的应用程序任务和主启动器.我再也无法获得其他应用程序任务了.我们的应用需要该方法来确定当前的顶级应用.任何人都有另一种方法来做到这一点?

我在谷歌搜索过,除此之外没有其他相关主题:https: //code.google.com/p/android-developer-preview/issues/detail?id = 29

sun*_*086 45

对于我最近开展的项目,我还需要检测何时启动某些应用程序.我的所有研究都引出了getRunningTasks方法,该方法从Lollipop开始不推荐使用.然而,令我惊讶的是,我发现一些应用程序锁定应用仍然适用于棒棒糖设备,因此他们必须提出解决方案来解决这个问题.所以我挖了一点.这是我发现的:

    1. 在pre-L设备上,它们仍然使用getRunningTasks
    1. 在L设备上,它们使用getRunningAppProcesses,它返回当前在设备上运行的进程列表.你可能会认为"好吧,那没用".每个processInfo都有一个称为重要性的属性.当应用程序成为顶级活动时,其processInfo重要性也会更改为IMPORTANCE_FOREGROUND.因此,您可以过滤掉那些不在前台的进程.从每个ProcessInfo中,您还可以询问它加载的包列表.然后,您可以检查列表是否包含与尝试"受保护"时应用程序相同的程序包.

一些示例代码用于检测何时启动默认日历应用程序:

public class DetectCalendarLaunchRunnable implements Runnable {

@Override
public void run() {
  String[] activePackages;
  if (Build.VERSION.SDK_INT > Build.VERSION_CODES.KITKAT_WATCH) {
    activePackages = getActivePackages();
  } else {
    activePackages = getActivePackagesCompat();
  }
  if (activePackages != null) {
    for (String activePackage : activePackages) {
      if (activePackage.equals("com.google.android.calendar")) {
        //Calendar app is launched, do something
      }
    }
  }
  mHandler.postDelayed(this, 1000);
}

String[] getActivePackagesCompat() {
  final List<ActivityManager.RunningTaskInfo> taskInfo = mActivityManager.getRunningTasks(1);
  final ComponentName componentName = taskInfo.get(0).topActivity;
  final String[] activePackages = new String[1];
  activePackages[0] = componentName.getPackageName();
  return activePackages;
}

String[] getActivePackages() {
  final Set<String> activePackages = new HashSet<String>();
  final List<ActivityManager.RunningAppProcessInfo> processInfos = mActivityManager.getRunningAppProcesses();
  for (ActivityManager.RunningAppProcessInfo processInfo : processInfos) {
    if (processInfo.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND) {
      activePackages.addAll(Arrays.asList(processInfo.pkgList));
    }
  }
  return activePackages.toArray(new String[activePackages.size()]);
}
}
Run Code Online (Sandbox Code Playgroud)

注意:getRunningAppProcesses也用于调试或"构建面向用户的流程管理UI".不确定google是否会像getRunningTasks那样关闭这个后门.

所以不,你不能再获得topActivity了.但是有点破解你可以获得类似的结果.

  • @ sunxin8086不幸的是,这在Android M上不起作用.am.getRunningAppProcesses()仅返回你的app包. (7认同)
  • 我不知道这是如何为您提供顶级活动的.它使用IMPORTANCE_FOREGROUND返回多个进程,因此无法知道哪个进程位于顶部.此外,它在每个进程中返回多个包,其中任何一个都可以在顶部.那么,我错过了什么吗? (2认同)

KNa*_*ito 33

正如MKY所提到的,getRunningTasks()方法不适用于在Lollipop中获取当前应用程序.

正如sunxin8086所写,获取正在运行的应用程序的一种方法是使用getRunningAppsProcesses()方法.但是,条件info.importance == IMPORTANCE_FOREGROUND无法唯一地确定当前应用程序.

确定当前前台应用程序的更好方法可能是检查对象中的processState字段RunningAppProcessInfo.此字段是隐藏字段,但您可以在RunningAppProcessInfo课程中看到它.如果此值为ActivityManager.PROCESS_STATE_TOP(也是隐藏的静态常量),则该进程是当前的前台进程.

例如代码是

final int PROCESS_STATE_TOP = 2;
ActivityManager.RunningAppProcessInfo currentInfo = null;
Field field = null;
try {
    field = ActivityManager.RunningAppProcessInfo.class.getDeclaredField("processState");
} catch (Exception ignored) {
}
ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
List<ActivityManager.RunningAppProcessInfo> appList = am.getRunningAppProcesses();
for (ActivityManager.RunningAppProcessInfo app : appList) {
    if (app.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND 
            && app.importanceReasonCode == ActivityManager.RunningAppProcessInfo.REASON_UNKNOWN) {
        Integer state = null;
        try {
            state = field.getInt(app);
        } catch (Exception e) {
        }
        if (state != null && state == PROCESS_STATE_TOP) {
            currentInfo = app;
            break;
        }
    }
}
return currentInfo;
Run Code Online (Sandbox Code Playgroud)

注意: processState pre-Lolipop中不存在字段.请Build.VERSION.SDK_INT >= 21在运行上述代码之前检查一下.以上代码仅适用于Lollipop +.

Gaston的另一种方法(完全不同)和"当前应用"的含义与这种方法略有不同.

请选择一个用于您的目的.


[编辑]

正如Sam指出的那样,我修改START_TASK_TO_FRONTPROCESS_STATE_TOP.(两个值均为2)

[EDIT2]

山姆有一个新的发现!要唯一地确定前台应用程序,还有一个条件

process.importanceReasonCode == 0
Run Code Online (Sandbox Code Playgroud)

有必要的.上面的代码已更新.谢谢!

  • @KNaito不幸的是,这在Android M上不起作用.am.getRunningAppProcesses()仅返回您的应用程序包. (8认同)
  • 我发现你的代码也返回了多个包:包含活动的进程和这个进程**使用的进程.一个例子是Firefox应用程序,它似乎使用谷歌GMS和YouTube流程.为了解决这个问题,我在`if`语句中添加了以下检查:`process.importanceReasonCode == 0`. (3认同)
  • 很棒的发现.谢谢.重要的是要指出你应该使用app.pkgList [0]来获取当前正在运行的应用程序的包而不是app.processName.大部分时间它们都是相同但有时不一样,就像运行TuneIn Pro应用程序时一样. (3认同)

Udi*_*ahi 28

这是获取Android L/Lollipop设备和Android M/Marshmallow设备当前顶级活动的精确解决方案.

首先调用这行代码:(一次)

Intent intent = new Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS);
startActivity(intent);
Run Code Online (Sandbox Code Playgroud)

上面的代码将打开一个名为"具有使用权限的应用程序"的屏幕.只需选中单选按钮打开/ true即可使用访问权限.现在,在您的服务中或任何您想要的地方调用以下方法:

public void getTopActivtyFromLolipopOnwards() {
    String topPackageName;
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
        UsageStatsManager mUsageStatsManager = (UsageStatsManager) getSystemService(Context.USAGE_STATS_SERVICE);
        long time = System.currentTimeMillis();
        // We get usage stats for the last 10 seconds
        List < UsageStats > stats = mUsageStatsManager.queryUsageStats(UsageStatsManager.INTERVAL_DAILY, time - 1000 * 10, time);
        // Sort the stats by the last time used
        if (stats != null) {
            SortedMap < Long, UsageStats > mySortedMap = new TreeMap < Long, UsageStats > ();
            for (UsageStats usageStats: stats) {
                mySortedMap.put(usageStats.getLastTimeUsed(), usageStats);
            }
            if (mySortedMap != null && !mySortedMap.isEmpty()) {
                topPackageName = mySortedMap.get(mySortedMap.lastKey()).getPackageName();
                Log.e("TopPackage Name", topPackageName);
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

添加权限

<uses-permission android:name="android.permission.PACKAGE_USAGE_STATS"
     tools:ignore="ProtectedPermissions" />
Run Code Online (Sandbox Code Playgroud)

这将返回当前正在运行的活动的包名称,无论是facebook还是whatsapp.

这种方法唯一的复杂因素是你需要提示用户允许应用程序使用统计信息......即第一步.

希望!这有助于每个人.


use*_*293 5

private String getProcess() throws Exception {
    if (Build.VERSION.SDK_INT >= 21) {
        return getProcessNew();
    } else {
        return getProcessOld();
    }
}

//API 21 and above
private String getProcessNew() throws Exception {
    String topPackageName = null;
    UsageStatsManager usage = (UsageStatsManager) context.getSystemService(Constant.USAGE_STATS_SERVICE);
    long time = System.currentTimeMillis();
    List<UsageStats> stats = usage.queryUsageStats(UsageStatsManager.INTERVAL_DAILY, time - ONE_SECOND * 10, time);
    if (stats != null) {
        SortedMap<Long, UsageStats> runningTask = new TreeMap<Long,UsageStats>();
        for (UsageStats usageStats : stats) {
            runningTask.put(usageStats.getLastTimeUsed(), usageStats);
        }
        if (runningTask.isEmpty()) {
            return null;
        }
        topPackageName =  runningTask.get(runningTask.lastKey()).getPackageName();
    }
    return topPackageName;
}

//API below 21
@SuppressWarnings("deprecation")
private String getProcessOld() throws Exception {
    String topPackageName = null;
    ActivityManager activity = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
    List<RunningTaskInfo> runningTask = activity.getRunningTasks(1);
    if (runningTask != null) {
        RunningTaskInfo taskTop = runningTask.get(0);
        ComponentName componentTop = taskTop.topActivity;
        topPackageName = componentTop.getPackageName();
    }
    return topPackageName;
}

//required permissions
<uses-permission android:name="android.permission.PACKAGE_USAGE_STATS"/>
<uses-permission android:name="android.permission.GET_TASKS"/>
Run Code Online (Sandbox Code Playgroud)


Moh*_*hna 4

我认为不可能获得其他应用程序的任务,

\n\n

这就是文档所说的

\n\n
\n

随着即将发布的版本中引入新的并发文档和活动任务功能(请参阅下面的“最近”屏幕中的并发文档和活动),\n ActivityManager.getRecentTasks()方法现已弃用,以改善\n 用户隐私。为了向后兼容,此方法仍然返回其数据的一小部分,包括调用应用程序\xe2\x80\x99自己的\n任务以及可能的一些其他非敏感任务(例如Home)。如果您的应用使用此方法来检索自己的任务,请使用 android.app.ActivityManager.getAppTasks() 来检索该信息。

\n
\n\n

在此处查看 Android L 的 api 概述https://developer.android.com/preview/api-overview.html#Behaviors

\n