web-dev-qa-db-fra.com

Android: comment obtenir une liste des activités installées, telles qu'elles apparaissent dans le lanceur, sans doublons

J'écris une application qui permet à l'utilisateur d'afficher la liste des applications installées, de sélectionner l'une d'entre elles, puis de la démarrer à temps. À l'aide de didacticiels de stackoverflow, j'ai réussi à comprendre comment obtenir une liste des activités installées, leurs noms de package et leurs icônes (c'est-à-dire ici - plusieurs façons de le faire). Juste au cas où, c'est comme ça que je commence mes activités, ça fonctionne parfaitement, pas de problème ici:

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

Le problème est de récupérer une liste des applications installées. J'ai trouvé deux façons d'obtenir une liste des applications installées:

1) utiliser

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

et à partir de chaque élément de apps, vous pouvez obtenir son nom de package et son étiquette (noms d'application).

2) utiliser

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    
}

Il y a un problème avec la première méthode : elle renvoie tous les packages installés, y compris les services système, qui peuvent ne contenir aucune activité et ne sont donc pas lancables. Voici une capture d'écran avec un exemple: app list with packages

Tous les éléments ci-dessus qui n'ont pas d'icônes ne peuvent pas être lancés.

Il y a aussi un problème avec la seconde approche : plusieurs éléments de la liste ont des doublons: app list with duplicates

Lorsque je configure un point d'arrêt dans le débogueur, je vois que ces éléments "Maps" ont des noms d'activité différents ("com.google.Android.maps.MapsActivity", "com.google.Android.maps.LatitudeActivity", "com.google .Android.maps.PlacesActivity "etc.).

J'ai décidé d'utiliser la deuxième approche, car elle donne une liste qui convient mieux à mes besoins, mais je ne trouve pas de moyen de filtrer les doublons et de n'afficher que l'activité par défaut de l'application, telle qu'elle apparaît dans le lanceur. (vous ne voyez qu'une seule carte dans la liste des applications de votre téléphone, pas quatre). J'ai essayé de filtrer les applications système via ApplicationInfo.FLAG_SYSTEM, mais cela supprime de nombreuses applications que je souhaite avoir, y compris Maps et d'autres applications préinstallées. J'ai essayé d'utiliser PackageManager.MATCH_DEFAULT_ONLY flag lors de l'exécution de queryIntentActivities, mais cela filtre également de nombreuses applications, en laissant seulement quelques-unes.

Je suis un peu perdu ici et je ne sais pas quoi faire. J'ai lu toutes les questions sur stackoverflow concernant la récupération d'une liste des applications installées, mais ce problème n'a jamais été soulevé. S'il vous plaît, aidez quelqu'un? Comment récupérer une liste des applications lancables installées qui n'a pas de doublons?

29
Anton Cherkashyn
Intent localIntent2 = new Intent("Android.intent.action.PICK_ACTIVITY");
Intent localIntent3 = new Intent("Android.intent.action.MAIN",null);
localIntent3.addCategory("Android.intent.category.LAUNCHER");   
localIntent2.putExtra("Android.intent.extra.INTENT",localIntent3);
startActivityForResult(localIntent2, 1);

Essayez ce code. Il répertorie uniquement les applications qui sont toutes installées sur votre appareil.

14
Satheeshkumar

Je suis peut-être en retard, mais je viens de trouver un moyen parfait d'obtenir toutes les applications avec un lanceur et aucune application en double (y compris les applications système comme les contacts, les cartes, etc.). Bien que la réponse de Satheesh puisse fonctionner (je ne me suis pas vérifié), mais je voulais choisir plusieurs activités, j'ai donc utilisé le code ci-dessous pour obtenir les applications installées.

J'ai utilisé votre deuxième approche et jeté les paquets en double à l'aide de HashSet. Voici le code final:

    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));
14
Ashish Tanna

Essayez le code ci-dessous et faites-moi savoir ce qui s'est passé.

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    
}
6
Yugandhar Babu

J'avais la même exigence. Finalement, j'ai ajouté une autre condition pour filtrer la liste des applications. Je viens de vérifier si l'application a une "intention de lancement".

Ainsi, le code résultant ressemble à ...

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);
    }

}
3
joecizac

@Ashish Tanna et jozze ont raison, mais les performances peuvent être un petit problème.

C'est la meilleure performance.

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) Ajouter un HashSet
(2) Juger si l'application est activée
(3) Juger si a l'intérieur du hachage

3
Trinea