How to get recent tasks on Android "L"?
Asked Answered
T

4

26

Background

My app allows to sort an apps list by the time they were recently launched .

The problem

As of Android "L" , the function getRecentTasks will just return the list of apps that the current app has launched, as written in the documentation:

If your app uses ActivityManager.getRecentTasks()...

With the introduction of the new concurrent documents and activities tasks feature in the upcoming release (see Concurrent documents and activities in Recents screen below), the ActivityManager.getRecentTasks() method is now deprecated to improve user privacy. For backward compatibility, this method still returns a small subset of its data, including the calling application’s own tasks and possibly some other non-sensitive tasks (such as Home). If your app is using this method to retrieve its own tasks, use android.app.ActivityManager.getAppTasks() instead to retrieve that information.

Same is written when using ADT to show the documentation of this function (not currently available on the Internet) :

This method is deprecated. As of L, this method is no longer available to third party applications: as the introduction of document-centric recents means it can leak personal information to the caller. For backwards compatibility, it will still return a small subset of its data: at least the caller's own tasks (though see getAppTasks() for the correct supported way to retrieve that information), and possibly some other tasks such as home that are known to not be sensitive.

I don't get why this act was taken, as it's easy to see which apps the user has, and even without any permission.

Thing is, this is a big restriction for this feature that I've added, so I hope there is a way to overcome this.

What I've tried

For now, I only used a heuristic way about which apps were recently launched - I get the list of running processes instead.

I could also use the importance value of the processes and maybe the "importanceReasonComponent" , but this is just all heuristics and guesses ...

The question

Is there a way to overcome this restriction? Any workaround I haven't thought of?

Maybe it's possible with root? Or BusyBox ?

Trochlear answered 5/7, 2014 at 21:1 Comment(16)
Well they say the reason: the ActivityManager.getRecentTasks() method is now deprecated to improve user privacyVi
I don't really have an answer, but for the "I don't get why this was removed" part, I guess that with the new "document-centric" tasks introduced by L you would've been able to know what documents or individual web pages the user had open.Honaker
@Vi Yes I read it. I just don't agree that it helps privacy, hence my small remark on it.Trochlear
@Honaker Yes, I've read it all (or at least what i've posted here), and also watched the videos, but I ask here for an alternative way, or a workaround, even if root/BusyBox is needed. getting what the current app has launched doesn't help much...Trochlear
Starring this issue and hoping Google change their mind before L officially releases seems the best bet.Glassco
@ChrisLacy I've made a similar thread here: code.google.com/p/android-developer-preview/issues/… . At least they could make it an admin permission, or a system app only permission...Trochlear
@androiddeveloper IMHO the bug I linked to is better as it's saying "give us a proper API" rather than yours which says "keep the flaky API working".Glassco
@ChrisLacy You wished for a subset of the current functionality (get a single activity/task that is on the foreground). I wanted to have the previous one, which gave you more than this (gave you all of the recent tasks). For me the larger functionality is more important, as it ruins one of my app's functionality. Sorry. Anyway, I starred yours too.Trochlear
@ChrisLacy Also, BTW, I think in one of Google's chats (which Dianne Hackborn answered herself) , they said they don't wish apps to be able to monitor the launching of other apps. The question that was asked was about logs reading being deprecated, which prevented apps from monitoring launch of apps. I think that's exactly what you wish for. Of course, I think they are wrong with this decision, but still...Trochlear
tbh Google has been taking some really weird steps in the name of privacy in Android LDosimeter
@UmerFarooq true. I don't understand the logic though, as it doesn't really give a lot of privacy.Trochlear
@androiddeveloper I hope someone finds a hack without rooting. Maybe reflections can solve this issue. Who knows, Google itself becomes wise enough in not restricting its platform which is famous/prospering because of customizationDosimeter
@UmerFarooq there is already a lot of people requesting that google won't do it. you can join too: code.google.com/p/android-developer-preview/issues/… code.google.com/p/android-developer-preview/issues/… . I remember another one that was very popular, but can't find it.Trochlear
@androiddeveloper I want to keep the reference of an object/instance even when the service is destroyed, Is there anyway to do that?Dosimeter
@UmerFarooq Do you have a thread here asking about it? If so, put a link to it, and I'll try to help you. I need to understand the whole "story"... In any case, you could use a static reference, but if the process itself is killed, you will of course lose the object. You can also store the object into the internal/external storage to be used later.Trochlear
I'm using Android accessibility service for this.Dedifferentiation
M
40

To get the top (Foreground) package name currently running you need to use the Usage Stats API in Android Lollipop.

But notice user has to approve the access to usage data in the settings for each Application. So you should prompt the user directly to the setting by launching setting action with

Intent intent = new Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS);

To get top packagename:

String topPackageName ;
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { 
    UsageStatsManager mUsageStatsManager = (UsageStatsManager)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<Long,UsageStats>();
        for (UsageStats usageStats : stats) {
            mySortedMap.put(usageStats.getLastTimeUsed(),usageStats);
        }                    
        if(!mySortedMap.isEmpty()) {
            topPackageName =  mySortedMap.get(mySortedMap.lastKey()).getPackageName();                                   
        }                                       
    }
}
Marengo answered 12/11, 2014 at 11:7 Comment(8)
Yes, I've forgot to update the question or add an answer. Sorry. here's a similar question, after I've noticed that's the way to use it : https://mcmap.net/q/89288/-how-to-use-usagestatsmanager/878126 . it is a bit weird though. are you guaranteed to get the top app ? I mean, what if it was opened more than 10 seconds ago?Trochlear
Yes you right, if top is opened more than 10 seconds the stats will return empty list... large time will increase the size of a list therefor the time to sort it.. so it deepens on your implementation and how you want to use the knowledge of a top package. For me 10 sec is enough.Marengo
Maybe, at least it can get the recent ones, starting the last time the device was turned on ? I think that if the query is for a too long time, it takes quite a while to get the result.Trochlear
@Marengo Works nice for most apps but doesn't work for some of the system applications (Google Now Launcher, Downloads, etc). When one of these apps is running, it always returns "com.google.android.googlequicksearchbox"Mn
And how would you do it on Android Wear? It doesn't have the ACTION_USAGE_ACCESS_SETTINGS settings screen where the user can enable this. Thanks in advance.Pius
And it is not supported on most of the Samsung devices.Woodwork
@LiorIluz do you have any update on the issue you mentioned here about com.google.android.googlequicksearchbox ..?Fechter
@SaravanaKumarChinnaraj no, moved on to accessibility service option.Mn
C
10

If you Use UsageStats to get the current foreground package, you will get the wrong information when user opens the notification drawer or on a locked screen. (tested on both Android Lollipop and Marshmallow)

You have to use UsageStatsManager.queryEvents() and look for the latest event with MOVE_TO_FOREGROUND event type for deciding the current foreground package.

Carbuncle answered 29/4, 2016 at 14:53 Comment(2)
This answer just saved me a lot of trouble, it should be the accepted answer.Kenward
Is it also possible to know which of the apps there have a living process?Trochlear
E
2

@user3742392 answer is good, however using a TreeMap to find last used time is a bit overkill (especially if you want to check top running app periodically).

Here is the edited answer without the TreeMap with simple loop instead:

String topPackageName;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
    UsageStatsManager mUsageStatsManager = (UsageStatsManager) getSystemService("usagestats");
    long currentTime = System.currentTimeMillis();
    // get usage stats for the last 10 seconds
    List<UsageStats> stats = mUsageStatsManager.queryUsageStats(UsageStatsManager.INTERVAL_DAILY, currentTime - 1000 * 10, currentTime);
    // search for app with most recent last used time
    if (stats != null) {
        long lastUsedAppTime = 0;
        for (UsageStats usageStats : stats) {
            if (usageStats.getLastTimeUsed() > lastUsedAppTime) {
                topPackageName = usageStats.getPackageName();
                lastUsedAppTime = usageStats.getLastTimeUsed();
            }
        }
    }
}
Eveliaevelin answered 6/11, 2015 at 14:27 Comment(1)
stats size is always zero!Obidiah
R
1

Lollipop deprecated the method; however there is a new API that allows you to view app usage. The method was deprecated because of security issues. :\

UsageStatsManager has some useful methods to see activity between an interval of time. Hope this is sufficient for your needs!

https://developer.android.com/reference/android/app/usage/package-summary.html

Rowley answered 27/10, 2014 at 1:9 Comment(1)
Yes, sorry for not updating this question. I've found it too, but now I don't get how to use it. Can you please check it out: https://mcmap.net/q/89288/-how-to-use-usagestatsmanager and see if you succeed using it? if so, I can mark both the answers.Trochlear

© 2022 - 2024 — McMap. All rights reserved.