I wish to have one application that runs in the background, which knows when any of the built-in applications (messaging, contacts, etc) is running.
So my questions
The ActivityManager class is the appropriate tool to see which processes are running.
To run in the background, you typically want to use a Service.
This worked for me. But it gives only the main menu name. That is if user has opened Settings --> Bluetooth --> Device Name screen, RunningAppProcessInfo calls it as just Settings. Not able to drill down furthur
ActivityManager activityManager = (ActivityManager) context.getSystemService( Context.ACTIVITY_SERVICE );
PackageManager pm = context.getPackageManager();
List<RunningAppProcessInfo> appProcesses = activityManager.getRunningAppProcesses();
for(RunningAppProcessInfo appProcess : appProcesses) {
if(appProcess.importance == RunningAppProcessInfo.IMPORTANCE_FOREGROUND) {
CharSequence c = pm.getApplicationLabel(pm.getApplicationInfo(appProcess.processName, PackageManager.GET_META_DATA));
Log.i("Foreground App", "package: " + appProcess.processName + " App: " + c.toString());
}
}
I combined two solutions in one method and it works for me for API 24 and for API 21. Others I didn't test.
The code in Kotlin:
private fun isAppInForeground(context: Context): Boolean {
val appProcessInfo = ActivityManager.RunningAppProcessInfo()
ActivityManager.getMyMemoryState(appProcessInfo)
if (appProcessInfo.importance == IMPORTANCE_FOREGROUND ||
appProcessInfo.importance == IMPORTANCE_VISIBLE) {
return true
} else if (appProcessInfo.importance == IMPORTANCE_TOP_SLEEPING ||
appProcessInfo.importance == IMPORTANCE_BACKGROUND) {
return false
}
val am = context.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
val foregroundTaskInfo = am.getRunningTasks(1)[0]
val foregroundTaskPackageName = foregroundTaskInfo.topActivity.packageName
return foregroundTaskPackageName.toLowerCase() == context.packageName.toLowerCase()
}
and in Manifest
<!-- Check whether app in background or foreground -->
<uses-permission android:name="android.permission.GET_TASKS" />
Do something like this:
int showLimit = 20;
/* Get all Tasks available (with limit set). */
ActivityManager mgr = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
List<ActivityManager.RunningTaskInfo> allTasks = mgr.getRunningTasks(showLimit);
/* Loop through all tasks returned. */
for (ActivityManager.RunningTaskInfo aTask : allTasks)
{
Log.i("MyApp", "Task: " + aTask.baseActivity.getClassName());
if (aTask.baseActivity.getClassName().equals("com.android.email.activity.MessageList"))
running=true;
}
Taking into account that getRunningTasks()
is deprecated and getRunningAppProcesses()
is not reliable, I came to decision to combine 2 approaches mentioned in StackOverflow:
private boolean isAppInForeground(Context context)
{
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP)
{
ActivityManager am = (ActivityManager) context.getSystemService(ACTIVITY_SERVICE);
ActivityManager.RunningTaskInfo foregroundTaskInfo = am.getRunningTasks(1).get(0);
String foregroundTaskPackageName = foregroundTaskInfo.topActivity.getPackageName();
return foregroundTaskPackageName.toLowerCase().equals(context.getPackageName().toLowerCase());
}
else
{
ActivityManager.RunningAppProcessInfo appProcessInfo = new ActivityManager.RunningAppProcessInfo();
ActivityManager.getMyMemoryState(appProcessInfo);
if (appProcessInfo.importance == IMPORTANCE_FOREGROUND || appProcessInfo.importance == IMPORTANCE_VISIBLE)
{
return true;
}
KeyguardManager km = (KeyguardManager) context.getSystemService(Context.KEYGUARD_SERVICE);
// App is foreground, but screen is locked, so show notification
return km.inKeyguardRestrictedInputMode();
}
}
From lollipop onwards this got changed. Please find below code, before that user has to go Settings -> Security -> (Scroll down to last) Apps with usage access -> Give the permissions to our app
private void printForegroundTask() {
String currentApp = "NULL";
if(android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
UsageStatsManager usm = (UsageStatsManager) this.getSystemService(Context.USAGE_STATS_SERVICE);
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(TAG, "Current App in foreground is: " + currentApp);
}