Google似乎最终关闭了获取当前前台应用程序包的所有大门。
在Lollipop更新后,getRunningTasks(int maxNum)
并且感谢this answer,我使用此代码从Lollipop获取前台应用程序包:
final int PROCESS_STATE_TOP = 2;
RunningAppProcessInfo currentInfo = null;
Field field = null;
try {
field = RunningAppProcessInfo.class.getDeclaredField("processState");
} catch (Exception ignored) {
}
ActivityManager am = (ActivityManager) this.getSystemService(Context.ACTIVITY_SERVICE);
List<RunningAppProcessInfo> appList = am.getRunningAppProcesses();
for (RunningAppProcessInfo app : appList) {
if (app.importance == RunningAppProcessInfo.IMPORTANCE_FOREGROUND &&
app.importanceReasonCode == 0 ) {
Integer state = null;
try {
state = field.getInt( app );
} catch (Exception ignored) {
}
if (state != null && state == PROCESS_STATE_TOP) {
currentInfo = app;
break;
}
}
}
return currentInfo;
Android 5.1.1及以上版本(6.0 Marshmallow)似乎也杀死了getRunningAppProcesses()
。它现在返回您自己的应用程序包的列表。
UsageStatsManager
我们可以将新的UsageStatsManager
API用作described here,但它并不适用于所有应用。某些系统应用程序将返回相同的包
com.google.android.googlequicksearchbox
AccessibilityService (2017年12月:将被谷歌禁止使用)
某些应用程序使用AccessibilityService
(作为seen here),但它有一些缺点。
是否有另一种获取当前正在运行的应用程序包的方法?
答案 0 :(得分:91)
要获取Android 1.6上运行进程的列表 - Android 6.0,您可以使用我写的这个库:https://github.com/jaredrummler/AndroidProcesses库读取/ proc以获取进程信息。
Google在Android Nougat中严格限制了对/ proc的访问权限。要获取Android Nougat上正在运行的进程列表,您需要使用UsageStatsManager或具有root访问权限。
点击以前替代解决方案的修改历史记录。
答案 1 :(得分:19)
private String printForegroundTask() {
String currentApp = "NULL";
if(android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
UsageStatsManager usm = (UsageStatsManager)this.getSystemService("usagestats");
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("adapter", "Current App in foreground is: " + currentApp);
return currentApp;
}
使用此方法获取前台任务。 你需要一个系统权限“android:get_usage_stats”
public static boolean needPermissionForBlocking(Context context){
try {
PackageManager packageManager = context.getPackageManager();
ApplicationInfo applicationInfo = packageManager.getApplicationInfo(context.getPackageName(), 0);
AppOpsManager appOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
int mode = appOpsManager.checkOpNoThrow(AppOpsManager.OPSTR_GET_USAGE_STATS, applicationInfo.uid, applicationInfo.packageName);
return (mode != AppOpsManager.MODE_ALLOWED);
} catch (PackageManager.NameNotFoundException e) {
return true;
}
}
如果用户在设置中启用此功能 - &gt;安全性 - &GT;具有使用权限的应用。之后你将获得前台任务。类似工艺由Cheetahamobile清洁matser google play link
答案 2 :(得分:6)
看看https://github.com/ricvalerio/foregroundappchecker,它可能就是你所需要的。提供示例代码,消除了必须实现跨版本前景检测器的痛苦。
以下是两个样本:
AppChecker appChecker = new AppChecker();
String packageName = appChecker.getForegroundApp();
或定期检查:
AppChecker appChecker = new AppChecker();
appChecker
.when("com.other.app", new AppChecker.Listener() {
@Override
public void onForeground(String packageName) {
// do something
}
)
.when("com.my.app", new AppChecker.Listener() {
@Override
public void onForeground(String packageName) {
// do something
}
)
.other(new AppChecker.Listener() {
@Override
public void onForeground(String packageName) {
// do something
}
)
.timeout(1000)
.start(this);
答案 3 :(得分:4)
Google仅针对系统应用限制此功能。如bug ticket中所述,您需要 REAL_GET_TASKS 权限才能访问。
应用程序现在必须具有... permission.REAL_GET_TASKS才能够 获取所有应用程序的进程信息。只有这个过程 如果应用程序将返回调用应用程序的信息 没有权限。权限应用程序将暂时可用 获取所有申请的流程信息,如果他们没有 新的权限,但已弃用... permission.GET_TASKS此外,仅限 系统应用程序可以获得REAL_GET_TASKS权限。
答案 4 :(得分:2)
将潜在的优化放到我想象中的是用于检测Android M上最顶层应用程序的大量复制粘贴代码。
此
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
UsageStatsManager usm = (UsageStatsManager)this.getSystemService("usagestats");
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();
}
}
}
可简化为此
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
UsageStatsManager usm = (UsageStatsManager) context.getSystemService(
Context.USAGE_STATS_SERVICE);
long time = System.currentTimeMillis();
List<UsageStats> appStatsList = usm.queryUsageStats(UsageStatsManager.INTERVAL_DAILY,
time - 1000 * 1000, time);
if (appStatsList != null && !appStatsList.isEmpty()) {
currentApp = Collections.max(appStatsList, (o1, o2) ->
Long.compare(o1.getLastTimeUsed(), o2.getLastTimeUsed())).getPackageName();
}
}
我发现自己在2秒的循环中使用了这段代码,并想知道为什么我在Collections.max()中提供了一个更简单的解决方案时使用了O(n * log(n))的复杂解决方案。为O(n)。
答案 5 :(得分:0)
public class AccessibilityDetectingService extends AccessibilityService {
@Override
protected void onServiceConnected() {
super.onServiceConnected();
//Configure these here for compatibility with API 13 and below.
AccessibilityServiceInfo config = new AccessibilityServiceInfo();
config.eventTypes = AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED;
config.feedbackType = AccessibilityServiceInfo.FEEDBACK_GENERIC;
if (Build.VERSION.SDK_INT >= 16)
//Just in case this helps
config.flags = AccessibilityServiceInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS;
setServiceInfo(config);
}
@Override
public void onAccessibilityEvent(final AccessibilityEvent event) {
if (event == null ) {
return;
} else if(event.getPackageName() == null && event.getClassName() == null){
return;
}
if (activityInfo != null){
Log.d("CurrentActivity", componentName.flattenToShortString());
}
}
private ActivityInfo tryGetActivity(ComponentName componentName) {
try {
return getPackageManager().getActivityInfo(componentName, 0);
} catch (PackageManager.NameNotFoundException e) {
return null;
}
}
@Override
public void onInterrupt() {
}
}
}//`enter code here`uses-permission android:name="android.permission.BIND_ACCESSIBILITY_SERVICE" />
<uses-permission android:name="android.permission.GET_TASKS" />
然后在您的设备中启动服务和应用程序辅助功能 设置 - &GT; accessibility-&GT;应用 在那项服务上。
答案 6 :(得分:0)
//这比上面的答案快。
String mforegoundPppPackageName;
UsageStatsManager usage = (UsageStatsManager) context.getSystemService(Context.USAGE_STATS_SERVICE);
long time = System.currentTimeMillis();
List<UsageStats> stats = usage.queryUsageStats(UsageStatsManager.INTERVAL_DAILY, 0, time);
Collections.sort(stats, usageStatsComparator);
if (stats != null && stats.size() > 0) {
if (stats.get(stats.size()).getPackageName().equals("android")) {
stats.remove(stats.size());
}
mforegoundPppPackageName = stats.get(stats.size()).getPackageName();
} else {
mforegoundPppPackageName = "";
}
**//How to sort**
Comparator<UsageStats> usageStatsComparator = new Comparator<UsageStats>() {
@Override
public int compare(UsageStats o1, UsageStats o2) {
if (o1.getLastTimeUsed() > o2.getLastTimeUsed()) {
return 1;
} else if (o1.getLastTimeUsed() < o2.getLastTimeUsed()) {
return -1;
} else {
return 0;
}
}
};
答案 7 :(得分:-3)
请尝试使用getRunningServices()
代替getRunningAppProcesses()
方法。
ActivityManager mActivityManager = (ActivityManager) getSy stemService(Context.ACTIVITY_SERVICE);
List<ActivityManager.RunningServiceInfo> appProcessInfoList = mActivityManager.getRunningServices(Integer.MAX_VALUE);