getRunningTasks 在 Android L 中不起作用
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/24625936/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
getRunningTasks doesn't work in Android L
提问by Ligen Yao
In Android L, Google has disabled getRunningTasks. Now it can only return own apps task and the home launcher. I can no longer get other apps tasks. Our app needs that method to determine current top app. Any one has another method to do this?
在 Android L 中,谷歌禁用了 getRunningTasks。现在它只能返回自己的应用程序任务和主启动器。我无法再获得其他应用程序任务。我们的应用程序需要该方法来确定当前的热门应用程序。任何人都有另一种方法来做到这一点?
I have searched in Google, no more topics about this except this: https://code.google.com/p/android-developer-preview/issues/detail?id=29
我在谷歌搜索过,除了这个没有更多关于这个的主题:https: //code.google.com/p/android-developer-preview/issues/detail?id=29
回答by sunxin8086
For a recent project that I worked on, I also need to detect when certain applications are launched. All my research lead to the getRunningTasks method, which is deprecated starting from Lollipop. However, to my surprises, I discovered that some of the app lock apps still work on lollipop devices, so they must have come up with a solution to get around this. So I dug a little deeper. Here is what I found out:
对于我最近参与的一个项目,我还需要检测某些应用程序何时启动。我所有的研究都导致了 getRunningTasks 方法,该方法从 Lollipop 开始已被弃用。然而,令我惊讶的是,我发现一些应用程序锁定应用程序仍然可以在棒棒糖设备上运行,所以他们一定想出了一个解决方案来解决这个问题。所以我挖得更深一些。这是我发现的:
- On pre-L devices, they still use getRunningTasks
- On L devices, they use getRunningAppProcesses, which returns a list of processes currently running on the devices. You might think "well, that is not useful". Each processInfo has a attributed called importance. When an app becomes top activity, its processInfo importance also changes to IMPORTANCE_FOREGROUND. So you can filter out those processes that are not in foreground. From a each ProcessInfo, you can also ask a list of packages it loaded. You can then check if the list contains the same package that the app when are trying "protected".
- 在 pre-L 设备上,他们仍然使用 getRunningTasks
- 在 L 台设备上,它们使用 getRunningAppProcesses,它返回当前在设备上运行的进程列表。你可能会想“好吧,那没有用”。每个 processInfo 都有一个称为重要性的属性。当一个应用成为顶级活动时,它的 processInfo 重要性也会更改为 IMPORTANCE_FOREGROUND。所以你可以过滤掉那些不在前台的进程。从每个 ProcessInfo 中,您还可以询问它加载的包列表。然后,您可以检查列表是否包含与应用程序在尝试“受保护”时相同的包。
Some sample code to detect when the default calendar app is launched:
一些用于检测默认日历应用程序何时启动的示例代码:
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()]);
}
}
Note: getRunningAppProcesses is also intended for debugging or "building a user-facing process management UI". Not sure if google will close this backdoor the similar way they did to getRunningTasks.
注意:getRunningAppProcesses 还用于调试或“构建面向用户的进程管理 UI”。不确定谷歌是否会像关闭 getRunningTasks 一样关闭这个后门。
So no, you can't get the topActivity anymore. But with a little bit hack you can achieve similar result.
所以不,你不能再得到 topActivity 了。但是通过一点点hack,您可以获得类似的结果。
回答by KNaito
As MKY mentioned, getRunningTasks()
method does not work for getting the current application in Lollipop.
正如 MKY 所提到的,getRunningTasks()
方法不适用于在 Lollipop 中获取当前应用程序。
As sunxin8086 wrote, the one way for getting the running applications is by using getRunningAppsProcesses()
method. However, the condition info.importance == IMPORTANCE_FOREGROUND
can not determine the current app uniquely.
正如 sunxin8086 所写,获取正在运行的应用程序的一种方法是使用getRunningAppsProcesses()
方法。但是,条件info.importance == IMPORTANCE_FOREGROUND
不能唯一确定当前应用程序。
The better approach to determine the current foreground application may be checking the processState
field in RunningAppProcessInfo
object. This field is a hidden field, but you can see it in the RunningAppProcessInfo
class. If this value is ActivityManager.PROCESS_STATE_TOP
(which is also
hidden static constant), the process is the current foreground process.
确定当前前台应用程序的更好方法可能是检查对象中的processState
字段RunningAppProcessInfo
。这个字段是一个隐藏字段,但是你可以在RunningAppProcessInfo
类中看到它。如果该值为ActivityManager.PROCESS_STATE_TOP
(也是隐藏静态常量),则该进程为当前前台进程。
For example the code is
例如代码是
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;
Note:processState
field does not exist in pre-Lolipop. Please check that Build.VERSION.SDK_INT >= 21
before running the above code. The above code works only for Lollipop+.
注意:processState
Lolipop 之前的字段不存在。请Build.VERSION.SDK_INT >= 21
在运行上述代码之前检查。以上代码仅适用于 Lollipop+。
The other approach, by Gaston (which is quite different), and the meaning of 'current application' is slightly different from this approach.
Gaston 提出的另一种方法(完全不同),“当前应用程序”的含义与这种方法略有不同。
Please choose one for your purpose.
请根据您的目的选择一种。
[EDIT]
[编辑]
As Sam pointed out, I modified START_TASK_TO_FRONT
by PROCESS_STATE_TOP
. (Both values are 2)
正如 Sam 指出的那样,我修改START_TASK_TO_FRONT
了PROCESS_STATE_TOP
. (两个值都是 2)
[EDIT2]
[编辑2]
Sam has a new find! To determine the foreground application uniquely, one more condition
山姆有了新发现!要唯一确定前台应用程序,还有一个条件
process.importanceReasonCode == 0
is necessary. The above code has been updated. Thanks!
是必要的。上面的代码已经更新。谢谢!
回答by Udit Kapahi
Here's an exact solution to get current top activity on your Android L/Lollipop devices and Android M/Marshmallow devices.
这是在您的 Android L/Lollipop 设备和 Android M/Marshmallow 设备上获取当前热门活动的确切解决方案。
First call this line of code:(One time)
首先调用这行代码:(一次)
Intent intent = new Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS);
startActivity(intent);
The above code will open a screen named "Apps with usage access". Just check the radio button to on/true to allow usage access. Now call the following method in your service or anywhere you want:
上面的代码将打开一个名为“具有使用权限的应用程序”的屏幕。只需将单选按钮选中为 on/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);
}
}
}
}
add permission
添加权限
<uses-permission android:name="android.permission.PACKAGE_USAGE_STATS"
tools:ignore="ProtectedPermissions" />
This will return the package name of currently running activity , whether it is facebook or whatsapp.
这将返回当前正在运行的活动的包名称,无论是 facebook 还是 whatsapp。
The only complication of this method is you need to prompt user for allowing app usage stats ... i.e. the first step.
这种方法的唯一复杂之处是您需要提示用户允许应用程序使用统计信息……即第一步。
Hope! this helps everyone.
希望!这对每个人都有帮助。
回答by user4759293
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"/>
回答by Mohan Krishna
I Think its not possible to get other app's tasks,
我认为不可能获得其他应用程序的任务,
This is what documentation says
这就是文档所说的
With the introduction of the new concurrent documents and activities tasks feature in the upcoming release (see Concurrent documents and activities in Recents screen below), the ActivityManager.getRecentTasks()method is now deprecated to improve user privacy. For backward compatibility, this method still returns a small subset of its data, including the calling application's own tasks and possibly some other non-sensitive tasks (such as Home). If your app is using this method to retrieve its own tasks, use android.app.ActivityManager.getAppTasks() instead to retrieve that information.
随着在即将发布的版本中引入新的并发文档和活动任务功能(请参阅下面最近屏幕中的并发文档和活动), 现在不推荐使用ActivityManager.getRecentTasks()方法以提高用户隐私。为了向后兼容,此方法仍返回其数据的一小部分,包括调用应用程序自己的任务和可能的其他一些非敏感任务(例如 Home)。如果您的应用使用此方法来检索自己的任务,请改用 android.app.ActivityManager.getAppTasks() 来检索该信息。
Check out the api overview of Android L here https://developer.android.com/preview/api-overview.html#Behaviors
在此处查看 Android L 的 api 概述https://developer.android.com/preview/api-overview.html#Behaviors