getRunningTasks在Android L中不起作用

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

我在Google中search过,除此之外,没有更多的话题可以参考: https : //code.google.com/p/android-developer-preview/issues/detail?id = 29

对于我最近开发的一个项目,我还需要检测何时启动某些应用程序。 我所有的研究都是以getRunningTasks方法为基础的,这个方法从Lollipop开始已经被废弃了。 然而,令我惊讶的是,我发现一些应用程序locking应用程序仍然在棒棒糖设备上工作,所以他们必须想出一个解决scheme来解决这个问题。 所以我挖了一点。 这是我发现的:

    1. 在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()]); } } 

注意:getRunningAppProcesses也用于debugging或“构build面向用户的stream程pipe理UI”。 不知道谷歌是否会像使用getRunningTasks一样来closures这个后门。

所以不,你不能得到topActivity了。 但有一点点破解你可以达到类似的结果。

正如MKY提到的, getRunningTasks()方法不适用于获取棒棒糖中的当前应用程序。

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

确定当前前台应用程序的更好方法可能是检查RunningAppProcessInfo对象中的processState字段。 这个字段是一个隐藏的字段,但你可以在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; 

注意: pre-Lolipop中不存在processState字段。 在运行上面的代码之前,请检查Build.VERSION.SDK_INT >= 21 。 上面的代码只适用于棒棒糖+。

加斯顿的另一种方法(与此截然不同)和“当前应用”的含义与这种方法略有不同。

请为您的目的select一个。


[编辑]

正如Sam指出的,我通过PROCESS_STATE_TOP修改了START_TASK_TO_FRONT 。 (两个值都是2)

[EDIT2]

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

 process.importanceReasonCode == 0 

是必要的。 上面的代码已经更新。 谢谢!

这里有一个确切的解决scheme,以获得您的Android L / Lollipop设备和Android M /棉花糖设备上的当前顶级活动。

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

 Intent intent = new Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS); startActivity(intent); 

上面的代码将打开一个名为“使用访问权限的应用程序”的屏幕。 只需检查单选button以开启/允许使用访问。 现在在您的服务或任何你想要的地方调用以下方法:

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

添加权限

 <uses-permission android:name="android.permission.PACKAGE_USAGE_STATS" tools:ignore="ProtectedPermissions" /> 

这将返回当前正在运行的活动的包名称,无论是Facebook或WhatsApp。

这种方法的唯一的复杂性是你需要提示用户允许应用程序使用统计…即第一步。

希望! 这有助于每个人。

 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"/> 

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

这是文档说的

通过在即将发布的版本中引入新的并发文档和活动任务function(请参阅下面的“最近的并发文档和活动”屏幕 ),现在不推荐使用ActivityManager.getRecentTasks()方法来提高用户的隐私性。 为了向后兼容,这个方法仍然返回一小部分数据,包括调用应用程序自己的任务以及其他一些非敏感的任务(比如Home)。 如果您的应用程序使用此方法来检索自己的任务,请使用android.app.ActivityManager.getAppTasks()来检索该信息。

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