How to detect which app has been launched by user in my app i.e my application should get notified when Whatsapp is launched by user even if my app is not running in foreground or background.
hike messenger has achieved same functionality with accessibility service.
How can I solve this problem ?
Thanks in advance!!
Depending on the Android version running your application, you will have to use different methods.
On Pre-Lollipop devices, it is pretty straight-forward:
String[] result = new String[2];
List<ActivityManager.RunningTaskInfo> runningTasks;
ComponentName componentInfo;
runningTasks = activityManager.getRunningTasks(1);
componentInfo = runningTasks.get(0).topActivity;
result[0] = componentInfo.getPackageName();
result[1] = componentInfo.getClassName();
If you are on a Lollipop or newer device, you have to use UsageStatsManager class, which requires your application to be granted specific permissions
//no inspection ResourceType
UsageStatsManager mUsageStatsManager = (UsageStatsManager)context.getSystemService("usagestats");
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<>();
for (UsageStats usageStats : stats) {
mySortedMap.put(usageStats.getLastTimeUsed(),usageStats);
}
if(mySortedMap != null && !mySortedMap.isEmpty()) {
return mySortedMap.get(mySortedMap.lastKey()).getPackageName();
}
}
return null;
This will tell you if your apps has been granted permissions:
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 false;
}
And finally this will launch the Android permission granting activity for the user:
Intent intent = new Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS);
activity.startActivity(intent);
Hope that helps
Try this code:
ActivityManager activityManager = (ActivityManager) this.getSystemService( ACTIVITY_SERVICE );
List<RunningAppProcessInfo> procInfos = activityManager.getRunningAppProcesses();
for(int i = 0; i < procInfos.size(); i++)
{
if(procInfos.get(i).processName.equals("put the package name here"))
{
Toast.makeText(getApplicationContext(), "Notify Message", Toast.LENGTH_LONG).show();
}
}
No, this is not really possible using the public SDK.
You can get the current running process by ActivityManager#getRunningAppProcesses But it is definitely impossible to get notified .However, it isn't the most accurate, or efficient method
I am working with custom keyboard ,I need current package name when keyboard is open . This keyboard will be open with different different application ,so i need that application package name which is open currently.
I am using following code but its not working properly.
ActivityManager am = (ActivityManager) this
.getSystemService(Activity.ACTIVITY_SERVICE);
String packageName = am.getRunningTasks(1).get(0).topActivity
.getPackageName();
I know this is too late but above answer not working, and i found proper answer, so i write this,
ActivityManager mActivityManager = (ActivityManager)this.getSystemService(Context.ACTIVITY_SERVICE);
if(Build.VERSION.SDK_INT > 20){
String mPackageName = mActivityManager.getRunningAppProcesses().get(0).processName;
}
else{
String mPackageName = mActivityManager.getRunningTasks(1).get(0).topActivity.getPackageName();
}
ActivityManager am = (ActivityManager) this.getSystemService(ACTIVITY_SERVICE);
List<ActivityManager.RunningTaskInfo> taskInfo = am.getRunningTasks(1);
Log.d("topActivity", "CURRENT Activity ::" + taskInfo.get(0).topActivity.getClassName());
ComponentName componentInfo = taskInfo.get(0).topActivity;
String packageName = componentInfo.getPackageName();
You will need the following permission on your manifest:
<uses-permission android:name="android.permission.GET_TASKS"/>
Time and Name of application opened
final PackageManager pm = getPackageManager();
packages = pm.getInstalledApplications(PackageManager.GET_META_DATA);
for(ApplicationInfo packageInfo : packages )
{
String name=packageInfo.getClass().getName();
Toast.makeText(ListActivity.this, ""+ name, 0).show();
}
Try this to get the list of running apps.
ActivityManager activity_manager = (ActivityManager) context.getSystemService(Activity.ACTIVITY_SERVICE);
Use getRunningTasks() method from ActivityManager.
final ActivityManager activityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
final List<RunningTaskInfo> recentTasks = activityManager.getRunningTasks(Integer.MAX_VALUE);
for (int i = 0; i < recentTasks.size(); i++)
{
Log.d("Executed app", "Application executed : " +recentTasks.get(i).baseActivity.toShortString()+ "\t\t ID: "+recentTasks.get(i).id+"");
}
Add this permission in the manifest file.
<uses-permission android:name="android.permission.GET_TASKS" ></uses-permission>
For example, I have "music" and " speech recorder" run in my AVD background. I want to make a AlertDialog that can show the names " music, speech recorder". Who can give me some codes? Thank you.
this may help you...
public static HashSet<String> getRunningApps(Context context) {
final HashSet<String> hashSet = new HashSet<String>();
final ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
final PackageManager packageManager = context.getPackageManager();
List<RunningTaskInfo> runningTasks = activityManager.getRunningTasks(Integer.MAX_VALUE);
for (RunningTaskInfo runningTaskInfo : runningTasks) {
String packageName = runningTaskInfo.baseActivity.getPackageName();
try {
String appName = packageManager.getApplicationInfo(packageName, 0).loadLabel(packageManager).toString();
hashSet.add(appName);
} catch (NameNotFoundException exception) {
// handle Exception
}
}
return hashSet;
}
You can list all processes with the followings lines:
ActivityManager localActivityManager = (ActivityManager) getSystemService(Activity.ACTIVITY_SERVICE);
List RunningServiceInfo services = localActivityManager .getRunningServices(100);
And from RunningServiceInfo you can get details for the process.
Another way is using getRunningAppProcesses.
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 are:
How I should run my application in the background.
How my background application can know what the application currently running in the foreground is.
Responses from folks with experience would be greatly appreciated.
With regards to "2. How my background application can know what the application currently running in the foreground is."
Do NOT use the getRunningAppProcesses() method as this returns all sorts of system rubbish from my experience and you'll get multiple results which have RunningAppProcessInfo.IMPORTANCE_FOREGROUND. Use getRunningTasks() instead
This is the code I use in my service to identify the current foreground application, its really easy:
ActivityManager am = (ActivityManager) AppService.this.getSystemService(ACTIVITY_SERVICE);
// The first in the list of RunningTasks is always the foreground task.
RunningTaskInfo foregroundTaskInfo = am.getRunningTasks(1).get(0);
Thats it, then you can easily access details of the foreground app/activity:
String foregroundTaskPackageName = foregroundTaskInfo .topActivity.getPackageName();
PackageManager pm = AppService.this.getPackageManager();
PackageInfo foregroundAppPackageInfo = pm.getPackageInfo(foregroundTaskPackageName, 0);
String foregroundTaskAppName = foregroundAppPackageInfo.applicationInfo.loadLabel(pm).toString();
This requires an additional permission in activity menifest and works perfectly.
<uses-permission android:name="android.permission.GET_TASKS" />
Try the following code:
ActivityManager activityManager = (ActivityManager) newContext.getSystemService( Context.ACTIVITY_SERVICE );
List<RunningAppProcessInfo> appProcesses = activityManager.getRunningAppProcesses();
for(RunningAppProcessInfo appProcess : appProcesses){
if(appProcess.importance == RunningAppProcessInfo.IMPORTANCE_FOREGROUND){
Log.i("Foreground App", appProcess.processName);
}
}
Process name is the package name of the app running in foreground. Compare it to the package name of your application. If it is the same then your application is running on foreground.
I hope this answers your question.
i had to figure out the right solution the hard way. the below code is part of cyanogenmod7 (the tablet tweaks) and is tested on android 2.3.3 / gingerbread.
methods:
getForegroundApp - returns the foreground application.
getActivityForApp - returns the activity of the found app.
isStillActive - determines if a earlier found app is still the active app.
isRunningService - a helper function for getForegroundApp
this hopefully answers this issue in all extend (:
private RunningAppProcessInfo getForegroundApp() {
RunningAppProcessInfo result=null, info=null;
if(mActivityManager==null)
mActivityManager = (ActivityManager)mContext.getSystemService(Context.ACTIVITY_SERVICE);
List <RunningAppProcessInfo> l = mActivityManager.getRunningAppProcesses();
Iterator <RunningAppProcessInfo> i = l.iterator();
while(i.hasNext()){
info = i.next();
if(info.importance == RunningAppProcessInfo.IMPORTANCE_FOREGROUND
&& !isRunningService(info.processName)){
result=info;
break;
}
}
return result;
}
private ComponentName getActivityForApp(RunningAppProcessInfo target){
ComponentName result=null;
ActivityManager.RunningTaskInfo info;
if(target==null)
return null;
if(mActivityManager==null)
mActivityManager = (ActivityManager)mContext.getSystemService(Context.ACTIVITY_SERVICE);
List <ActivityManager.RunningTaskInfo> l = mActivityManager.getRunningTasks(9999);
Iterator <ActivityManager.RunningTaskInfo> i = l.iterator();
while(i.hasNext()){
info=i.next();
if(info.baseActivity.getPackageName().equals(target.processName)){
result=info.topActivity;
break;
}
}
return result;
}
private boolean isStillActive(RunningAppProcessInfo process, ComponentName activity)
{
// activity can be null in cases, where one app starts another. for example, astro
// starting rock player when a move file was clicked. we dont have an activity then,
// but the package exits as soon as back is hit. so we can ignore the activity
// in this case
if(process==null)
return false;
RunningAppProcessInfo currentFg=getForegroundApp();
ComponentName currentActivity=getActivityForApp(currentFg);
if(currentFg!=null && currentFg.processName.equals(process.processName) &&
(activity==null || currentActivity.compareTo(activity)==0))
return true;
Slog.i(TAG, "isStillActive returns false - CallerProcess: " + process.processName + " CurrentProcess: "
+ (currentFg==null ? "null" : currentFg.processName) + " CallerActivity:" + (activity==null ? "null" : activity.toString())
+ " CurrentActivity: " + (currentActivity==null ? "null" : currentActivity.toString()));
return false;
}
private boolean isRunningService(String processname){
if(processname==null || processname.isEmpty())
return false;
RunningServiceInfo service;
if(mActivityManager==null)
mActivityManager = (ActivityManager)mContext.getSystemService(Context.ACTIVITY_SERVICE);
List <RunningServiceInfo> l = mActivityManager.getRunningServices(9999);
Iterator <RunningServiceInfo> i = l.iterator();
while(i.hasNext()){
service = i.next();
if(service.process.equals(processname))
return true;
}
return false;
}
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);
}
In order to determine the foreground application, you can use for detecting the foreground app, you can use https://github.com/ricvalerio/foregroundappchecker. It uses different methods depending on the android version of the device.
As for the service, the repo also provides the code you need for it. Essentially, let android studio create the service for you, and then onCreate add the snippet that uses the appChecker. You will need to request permission however.
For cases when we need to check from our own service/background-thread whether our app is in foreground or not. This is how I implemented it, and it works fine for me:
public class TestApplication extends Application implements Application.ActivityLifecycleCallbacks {
public static WeakReference<Activity> foregroundActivityRef = null;
#Override
public void onActivityStarted(Activity activity) {
foregroundActivityRef = new WeakReference<>(activity);
}
#Override
public void onActivityStopped(Activity activity) {
if (foregroundActivityRef != null && foregroundActivityRef.get() == activity) {
foregroundActivityRef = null;
}
}
// IMPLEMENT OTHER CALLBACK METHODS
}
Now to check from other classes, whether app is in foreground or not, simply call:
if(TestApplication.foregroundActivityRef!=null){
// APP IS IN FOREGROUND!
// We can also get the activity that is currently visible!
}
Update (as pointed out by SHS):
Do not forget to register for the callbacks in your Application class's onCreate method.
#Override
public void onCreate() {
...
registerActivityLifecycleCallbacks(this);
}
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();
}
}
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());
}
}
An easy solution is to use LiveData.
Create a singleton LiveData variable. (probably in a plain Kotlin file).
val foregroundHelper = MutableLiveData<Unit>()
Observe From Activity or Fragment:
foregroundHelper.observe(this, Observer {}) // for Activity
foregroundHelper.observe(viewLifecycleOwner, Observer {}) // for Fragments
Now from Your Background Service, Broadcast Receiver, etc:
val appIsVisibleToTheUser = foregroundHelper.hasActiveObservers()
// Now your logic goes.
if (!appIsVisibleToUser) {
// App is in background
// So In my case:
// I'm showing Notification to the user for the error happened in Background Service.
}
Thanks.
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;
}
In lollipop and up:
Add to mainfest:
<uses-permission android:name="android.permission.GET_TASKS" />
And do something like this:
if( mTaskId < 0 )
{
List<AppTask> tasks = mActivityManager.getAppTasks();
if( tasks.size() > 0 )
mTaskId = tasks.get( 0 ).getTaskInfo().id;
}
This is how I am checking if my app is in foreground. Note I am using AsyncTask as suggested by official Android documentation.`
`
private class CheckIfForeground extends AsyncTask<Void, Void, Void> {
#Override
protected Void doInBackground(Void... voids) {
ActivityManager activityManager = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
List<ActivityManager.RunningAppProcessInfo> appProcesses = activityManager.getRunningAppProcesses();
for (ActivityManager.RunningAppProcessInfo appProcess : appProcesses) {
if (appProcess.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND) {
Log.i("Foreground App", appProcess.processName);
if (mContext.getPackageName().equalsIgnoreCase(appProcess.processName)) {
Log.i(Constants.TAG, "foreground true:" + appProcess.processName);
foreground = true;
// close_app();
}
}
}
Log.d(Constants.TAG, "foreground value:" + foreground);
if (foreground) {
foreground = false;
close_app();
Log.i(Constants.TAG, "Close App and start Activity:");
} else {
//if not foreground
close_app();
foreground = false;
Log.i(Constants.TAG, "Close App");
}
return null;
}
}
and execute AsyncTask like this.
new CheckIfForeground().execute();
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" />