Android: How to get a list of installed activities, as they appear in launcher, without duplicates

31,723

Solution 1

Intent localIntent2 = new Intent(Intent.ACTION_PICK_ACTIVITY);
Intent localIntent3 = new Intent(Intent.ACTION_MAIN, null);
localIntent3.addCategory(Intent.CATEGORY_LAUNCHER); 
localIntent2.putExtra(Intent.EXTRA_INTENT, localIntent3);
startActivityForResult(localIntent2, 1);

Try this code. It will list out only the applications which are all installed in your device.

Solution 2

I might be late, but i just found a perfect way of getting all apps having launcher & no duplicate apps (including system apps like contacts, maps, etc.). Although, Satheesh's answer might be working (haven't checked myself), but I wanted to pick multiple activities so I used below code to get installed apps.

I used your second approach and discarded duplicate packages using HashSet. Here's the final code :

    final PackageManager packageManager = getPackageManager();
    Intent intent = new Intent(Intent.ACTION_MAIN, null);
    intent.addCategory(Intent.CATEGORY_LAUNCHER);
    List<ResolveInfo> resInfos = packageManager.queryIntentActivities(intent, 0);
    //using hashset so that there will be no duplicate packages, 
    //if no duplicate packages then there will be no duplicate apps
    HashSet<String> packageNames = new HashSet<String>(0);
    List<ApplicationInfo> appInfos = new ArrayList<ApplicationInfo>(0);

    //getting package names and adding them to the hashset
    for(ResolveInfo resolveInfo : resInfos) {
        packageNames.add(resolveInfo.activityInfo.packageName);
    }

    //now we have unique packages in the hashset, so get their application infos
    //and add them to the arraylist
    for(String packageName : packageNames) {
        try {
            appInfos.add(packageManager.getApplicationInfo(packageName, PackageManager.GET_META_DATA));
        } catch (NameNotFoundException e) {
            //Do Nothing
        }
    }

    //to sort the list of apps by their names
    Collections.sort(appInfos, new ApplicationInfo.DisplayNameComparator(packageManager));

Solution 3

Try below code and let me know what happened.

PackageManager manager = getPackageManager();
Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);

List<ResolveInfo> resolveInfos= manager.queryIntentActivities(mainIntent, 0);
// Below line is new code i added to your code
Collections.sort(resolveInfos, new ResolveInfo.DisplayNameComparator(manager));

for(ResolveInfo info : resolveInfos) {
     ApplicationInfo applicationInfo = info.activityInfo.applicationInfo;
     //...
     //get package name, icon and label from applicationInfo object    
}

Solution 4

Both @Ashish Tanna and jozze are right, but the performance maybe a little problem.

This is the best performance one.

Set<String> packageNameSet = new HashSet<>();
PackageManager pm = context.getPackageManager();
Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);
List<ResolveInfo> resolveInfos = packageManager.queryIntentActivities(mainIntent, 0);
for(ResolveInfo info : resolveInfos) {
    // be added
    ApplicationInfo applicationInfo;
    if (info == null || (applicationInfo = info.activityInfo.applicationInfo) == null
            || !applicationInfo.enabled || packageNameSet.contains(applicationInfo.packageName)) {
        continue;
    }
    packageNameSet.add(applicationInfo.packageName);

    //...
    //get package name, icon and label from applicationInfo object
}

(1) Add a HashSet
(2) Judge whether application is enabled
(3) Judge whether has inside the hashset

Solution 5

I had the same requirement. Ultimately I added another condition to filter down the app list. I just checked whether the app has 'launcher intent'.

So, the resultant code looks like...

PackageManager pm = getPackageManager();
List<ApplicationInfo> apps = pm.getInstalledApplications(PackageManager.GET_GIDS);

for (ApplicationInfo app : apps) {
    if(pm.getLaunchIntentForPackage(app.packageName) != null) {
        // apps with launcher intent
        if((app.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) == 1) {
            // updated system apps
        } else if ((app.flags & ApplicationInfo.FLAG_SYSTEM) == 1) {
            // system apps
        } else {
            // user installed apps
        }
        appsList.add(app);
    }

}
Share:
31,723
Anton Cherkashyn
Author by

Anton Cherkashyn

My name is Anton Cherkashyn, I'm an Android engineer. SOreadytohelp

Updated on June 04, 2020

Comments

  • Anton Cherkashyn
    Anton Cherkashyn about 4 years

    I am writing an app that allows user to view the list of installed apps, select one of them and then start it on schedule. Using tutorials from stackoverflow i managed to figure out how to get a list of installed activities, their package names and icons(i.e. here - several ways to do it). Just in case, this is how i start activities, it works flawlessly, no problem here:

    Intent launchIntent = packageManager.getLaunchIntentForPackage(packageName);
    launchIntent.setAction(Intent.ACTION_MAIN);
    launchIntent.addCategory(Intent.CATEGORY_LAUNCHER);
    launchIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    startActivity(launchIntent);
    

    The problem is with retrieving a list of installed apps. I've found two ways to get a list of installed applications:

    1) use

    PackageManager pm = getPackageManager();
    List<ApplicationInfo> apps = pm.getInstalledApplication(PackageManager.GET_META_DATA) 
    

    and from each element from apps you can get it's package name and package label(app names).

    2) use

    PackageManager pm = getPackageManager();    
    Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
    mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);
    List<ResolveInfo> resolveInfos = packageManager.queryIntentActivities(mainIntent, 0);
    for(ResolveInfo info : resolveInfos) {
        ApplicationInfo applicationInfo = info.activityInfo.applicationInfo;
        //...
        //get package name, icon and label from applicationInfo object    
    }
    

    There is a problem with first method: it returns all installed packages, including system services, which may not contain any activity and are therefore not launchable. Here's a screenshot with an example: app list with packages

    All the items above that have no icons are not launchable.

    There is a problem with the second approach as well: Several items in the list have duplicates: app list with duplicates

    When i set up a breakpoint in debugger i see, that these "Maps" items have different activity names ("com.google.android.maps.MapsActivity", "com.google.android.maps.LatitudeActivity", "com.google.android.maps.PlacesActivity" etc.).

    I decided to use the second approach, because it gives a list that is more suitable for my needs, but i can't find a way to filter out the duplicates and only show the default activity for the app, as they appear in the Launcher(you only see one 'Maps' in your phone's list of apps, not four). I've tried filtering out system apps through ApplicationInfo.FLAG_SYSTEM, but this removes many apps that i want to have, including Maps and other preinstalled apps. I've tried using PackageManager.MATCH_DEFAULT_ONLY flag when executing queryIntentActivities, but this also filters out many apps, leaving just a few.

    I'm kinda lost here, and i don't know what to do. I've read all the questions on stackoverflow about retrieving a list of installed apps, but this issue has never been brought up. Please, help anyone? How do i retrieve a list of installed launchable apps that has no duplicates?