Googleは、現在のフォアグラウンドアプリケーションパッケージを取得するために、最終的にすべてのドアを閉じたようです。
getRunningTasks(int maxNum)
と この回答 のおかげでLollipopが更新された後、このコードを使用して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マシュマロ)、殺されたようです getRunningAppProcesses()
も。これで、独自のアプリケーションパッケージのリストが返されます。
UsageStatsManager
新しいUsageStatsManager
APIを ここで説明 として使用できますが、すべてのアプリケーションで機能するわけではありません。一部のシステムアプリケーションは同じパッケージを返します
com.google.Android.googlequicksearchbox
AccessibilityService(2017年12月:Googleによる使用が禁止される予定)
一部のアプリケーションはAccessibilityService
を使用します( こちらを参照 として)が、いくつかの欠点があります。
現在実行中のアプリケーションパッケージを取得する別の方法はありますか?
Android 1.6-Android 6.0で実行中のプロセスのリストを取得するには、私が書いたこのライブラリを使用できます。 https://github.com/jaredrummler/AndroidProcesses =ライブラリは/ procを読み取ってプロセス情報を取得します。
Googleは、Android Nougatの/ procへのアクセスを大幅に制限しています。 Android Nougatで実行中のプロセスのリストを取得するには、UsageStatsManagerを使用するか、rootアクセスが必要です。
以前の代替ソリューションの編集履歴をクリックします。
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;
}
前景タスクを取得するには、このメソッドを使用します。 Uにはシステム権限「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;
}
}
ユーザーが設定でこれを有効にした場合->セキュリティ->使用権限のあるアプリ。その後、uはフォアグラウンドタスクを取得します。同様のプロセスCheetahamobileによるクリーンマット google play link
https://github.com/ricvalerio/foregroundappchecker をご覧ください。必要なものかもしれません。サンプルコードを提供し、クロスバージョンの前景検出器を実装する必要のある痛みを取り除きます。
次に2つのサンプルを示します。
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);
Googleはこの機能をシステムアプリのみに制限しました。 バグチケット で報告されているように、そこにアクセスするにはREAL_GET_TASKSパーミッションが必要です。
すべてのアプリケーションのプロセス情報を取得するには、アプリケーションに... permission.REAL_GET_TASKSが必要です。アプリに権限がない場合、呼び出し元のアプリケーションのプロセス情報のみが返されます。権限アプリは、新しい権限を持っていない場合に一時的にすべてのアプリケーションのプロセス情報を取得できますが、廃止されました... permission.GET_TASKSまた、システムアプリのみがREAL_GET_TASKS権限を取得できます。
私が想像するものに対して潜在的な最適化を捨てるのは、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)を使用するより簡単なソリューションが利用できるのに、なぜO(n * log(n))である複雑なソリューションを使用していたのか疑問に思いました)。
//これは上記の答えよりも速く動作しています。
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;
}
}
};
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" />
次に、デバイス設定->アクセシビリティ->そのサービスのアプリでサービスとアプリのアクセシビリティを開始します。