6

I have an activity in my app wherein a ListView of all installed apps is generated. In addition to the app name, the app icon appears as well. I had created an array of objects containing all the information about the application, among this the icon, and retrieved the icon using:

drawableAppIcon = mPackageManager.getApplicationIcon(apps.applicationInfo);

Where application is a <PackageInfo> object. The problem with this is that while I readily have access to all the drawables, various apps seem to pull various quality drawables; one app icon will be extremely high res while another will be the low res version. I would have thought that the above line of code would have accounted for screen size and found the appropriate icons, but it doesn't. Is there an alternative that accounts for screen size? Or even more preferably is there a way to extract just the highest res icon and then scale it down based on screen size, which would basically guarantee all of them look clean?

EDIT: I've found a solution, but it only works for Android 4.0+

try {
    Context otherAppCtxt = context.createPackageContext(apps.applicationInfo.packageName, Context.CONTEXT_IGNORE_SECURITY);
    info.drawableAppIcon = otherAppCtxt.getResources().getDrawableForDensity(apps.applicationInfo.icon, DisplayMetrics.DENSITY_XHIGH);
} catch (PackageManager.NameNotFoundException e) {
    e.printStackTrace();
}

For others' reference, this works, if someone has a solution for older version of Android that would be really helpful.

mike
  • 1,318
  • 3
  • 21
  • 41
  • Do the application icons look okay elsewhere in Android? Are you resizing them in your app? I'd start my making sure that you're drawing them using their intrinsic width/height. – Dane White Aug 22 '13 at 17:17

3 Answers3

8
ApplicationInfo applicationInfo = 
        packagemanager.getApplicationInfo(packageName(), PackageManager.GET_META_DATA);
Resources res = packagemanager.getResourcesForApplication(applicationInfo);
Drawable appIcon = res.getDrawableForDensity(applicationInfo.icon, 
                                             DisplayMetrics.DENSITY_XXXHIGH, 
                                             null);
sorcererxw
  • 131
  • 2
  • 7
  • Thank You Sorcerer! – ORY Mar 09 '17 at 22:52
  • instead 'Drawable appIcon = res.getDrawableForDensity(applicationInfo.icon, DisplayMetrics.DENSITY_XXXHIGH, null);' use this 'Drawable appIcon = res.getDrawableForDensity(applicationInfo.icon, DisplayMetrics.DENSITY_XXXHIGH);' – ORY Mar 29 '17 at 20:58
7

I suspect there is some other reason why the icons look bad (such as resizing within your app), but if you need to do it for any Android version:

// Get the application's resources
Resources res = mPackageManager.getResourcesForApplication(appInfo);

// Get a copy of the configuration, and set it to the desired resolution
Configuration config = res.getConfiguration();
Configuration originalConfig = new Configuration(config);
config.densityDpi = DisplayMetrics.DENSITY_XHIGH;

// Update the configuration with the desired resolution
DisplayMetrics dm = res.getDisplayMetrics();
res.updateConfiguration(config, dm);

// Grab the app icon
Drawable appIcon = res.getDrawable(appInfo.icon);

// Set our configuration back to what it was
res.updateConfiguration(originalConfig, dm);
Dane White
  • 3,443
  • 18
  • 16
0

Here's a new answer to an old question, just to put everything in one place. You'll need to get the devices default density, and resize the image to ensure that you have a properly conforming size, as just requesting the icon does not always return proper size.

Consider these two methods, one to obtain device size, and the second to resize your drawable:

private int getDeviceDpi(){
        DisplayMetrics dm = new DisplayMetrics();
        getWindowManager().getDefaultDisplay().getMetrics(dm);
        return dm.densityDpi;
}

private Drawable getSizedAppIcon(Context context, String packageName, int Density) throws PackageManager.NameNotFoundException {
    //for @param Density you can use a static from DisplayMetrics.<something>

        PackageManager pm = Objects.requireNonNull(context).getPackageManager();
        ApplicationInfo appInfo = this.getPackageManager().getApplicationInfo(packageName, 0);
        Drawable icon = pm.getApplicationIcon(appInfo);
        Bitmap bitmap = ((BitmapDrawable) icon).getBitmap();
        switch (Density){
            case DisplayMetrics.DENSITY_LOW: //120
                return new BitmapDrawable(getResources(), Bitmap.createScaledBitmap(bitmap,
                        32, 32, true));
            case DisplayMetrics.DENSITY_MEDIUM: //160
                return new BitmapDrawable(getResources(), Bitmap.createScaledBitmap(bitmap,
                        48, 48, true));
            case DisplayMetrics.DENSITY_HIGH: //240
                return new BitmapDrawable(getResources(), Bitmap.createScaledBitmap(bitmap,
                        72, 72, true));
            case DisplayMetrics.DENSITY_XHIGH: //320
                return new BitmapDrawable(getResources(), Bitmap.createScaledBitmap(bitmap,
                        96, 96, true));
            case DisplayMetrics.DENSITY_XXHIGH: //480
                return new BitmapDrawable(getResources(), Bitmap.createScaledBitmap(bitmap,
                        144, 144, true));
            case DisplayMetrics.DENSITY_XXXHIGH: //640
                return new BitmapDrawable(getResources(), Bitmap.createScaledBitmap(bitmap,
                        192, 192, true));
            default:
                return icon;
        }

}

Then call them like in this example:

try{
    getSizedAppIcon(this, "com.example.app",getDeviceDpi());
}catch (Exception ignore) {}
sh7411usa
  • 196
  • 1
  • 13