在Android L中,谷歌已禁用了getRunningTasks方法。现在它只能返回自己应用的任务和主屏幕启动器,我不能再获取其他应用的任务了。 我们的应用需要该方法来确定当前顶部应用程序。 有没有其他方法可以做到这一点?
我在谷歌上搜索过,除了这个问题之外,没有更多关于此的话题: https://code.google.com/p/android-developer-preview/issues/detail?id=29
在Android L中,谷歌已禁用了getRunningTasks方法。现在它只能返回自己应用的任务和主屏幕启动器,我不能再获取其他应用的任务了。 我们的应用需要该方法来确定当前顶部应用程序。 有没有其他方法可以做到这一点?
我在谷歌上搜索过,除了这个问题之外,没有更多关于此的话题: https://code.google.com/p/android-developer-preview/issues/detail?id=29
最近我参与的一个项目中,需要检测某些应用程序何时启动。我的所有研究都指向了getRunningTasks方法,但这个方法从Lollipop开始就已经被弃用了。
不过,令我惊讶的是,我发现一些应用锁定应用程序在lollipop设备上仍然有效,所以他们必须想出了解决办法。因此,我深入挖掘了一下。以下是我的发现:
以下是检测默认日历应用程序启动的示例代码:
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也是用于调试或“构建用户界面进程管理”的,不确定Google是否会像他们对getRunningTasks所做的那样关闭这个后门。
因此,现在无法获取topActivity。但是通过一点点的技巧,您可以实现类似的结果。
正如MKY所提到的,getRunningTasks()
方法在Lollipop中不能用来获取当前应用程序。
正如sunxin8086所写的那样,获取运行中应用程序的一种方法是使用getRunningAppProcesses()
方法。然而,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;
注意:在Lolipop版本之前,processState
字段不存在。请确保在运行上述代码之前检查Build.VERSION.SDK_INT >= 21
。上述代码仅适用于Lollipop及以上版本。
另一种方法是由Gaston提出的(与此方法相差甚远),并且“当前应用程序”的含义与此方法略有不同。
请选择适合您目的的方法。
[编辑]
正如Sam所指出的,我将START_TASK_TO_FRONT
修改为PROCESS_STATE_TOP
。(两个值都为2)
[编辑2]
Sam有一个新发现!要唯一确定前台应用程序,还需要一个条件
process.importanceReasonCode == 0
是必要的。上面的代码已经更新。谢谢!
if
语句中加入了以下检查:process.importanceReasonCode == 0
。 - Sam以下是获取 Android L/Lollipop 和 Android M/Marshmallow 设备上当前顶部活动的确切解决方案。
首先调用此行代码:(仅一次)
Intent intent = new Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS);
startActivity(intent);
上述代码将打开一个名为“具有使用权限的应用程序”的屏幕。只需勾选单选按钮以打开/启用使用权限。 现在在您的服务或任何您想要的地方调用以下方法:
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"/>
Constant.USAGE_STATS_SERVICE
的值是什么?这段代码能在后台服务中运行吗? - maddy d