androidadaptive-icon

How to use IconCompat.createWithAdaptiveBitmap


I want to apply adaptive icons to shortcuts generated by following code (code is only for reference, it does not compile):

ShortcutInfoCompat shortcut = new ShortcutInfoCompat.Builder(context, "com.myapp.mainactivity")
                    .setShortLabel(context.getResources().getString("short label"))
                    .setLongLabel(context.getResources().getString("long label"))
                    .setIcon(IconCompat.createWithAdaptiveBitmap(bitmap)
                    .setIntent(targetActivityIntent)
                    .build();

public Bitmap getLauncherIcon(final Context context) {
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
        return null;
    } else {
        Drawable backgroundDrawable = context.getDrawable(R.mipmap.ic_launcher_background);
        Drawable vectorDrawable = context.getDrawable(R.drawable.ic_launcher_main_foreground);
        AdaptiveIconDrawable adaptiveIconDrawable = new AdaptiveIconDrawable(backgroundDrawable, vectorDrawable);
        Bitmap bitmap = drawableToBitmap(adaptiveIconDrawable);
        return bitmap;
    }
}

private static Bitmap drawableToBitmap(Drawable drawable) {
    Bitmap bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
    Canvas canvas = new Canvas(bitmap);
    drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
    drawable.draw(canvas);
    return bitmap;
}

This here is my icon (ic_main_white.xml)

<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
        android:width="45dp"
        android:height="45dp"
        android:viewportHeight="1024"
        android:viewportWidth="1024">
    <path
        android:fillColor="#FFFFFF"
        android:pathData="M511.5 74C269.87847 74 74 269.87847 74 511.5 74 753.13368 269.87847 949 511.5 949 753.12153 949 949 753.13368 949 511.5 949 269.87847 753.12153 74 511.5 74l0 0 0 0 0 0zm30.10243 764.20312l0 -140.08506 -57.72569 0 0 140.27951C325.65972 825.12674 199.05208 699.1875 184.78472 541.25l142.21181 0 0 -57.72569 -142.34549 0C198.12847 324.77257 325.07639 197.95833 483.87674 184.63889l0 142.00521 57.72569 0 0 -141.81077c157.64583 14.40104 283.32986 140.76563 296.74653 298.69098l-139.87847 0 0 57.72569 139.74479 0C824.02083 698.34896 698.66493 823.85069 541.60243 838.20312l0 0z"/>
</vector>

Using the Android Asset Generator I created an Image Asset where I get all the needed files generated. This is the same process you would go through when creating an adaptive icon for your app's launcher icon.

But the result is only a part of the icon being shown, it looks like the generated icon is to big for what it's expected or I'm missing something somewhere.

Also there is this documentation where following is stated:

For dynamic shortcuts, call the createWithAdaptiveBitmap() method when you create them.

The icons are generated by Android Studio itself and this also works with my launcher's icon, but why is it not working right using createWithAdaptiveBitmap? Am I missing some java code or do you know of an example using adaptive icons with shortcuts, I could not find anything that worked on GitHub or somewhere else.


Solution

  • For the solution you need:

    1. When you generate the icon with the asset manager in Android Studio make sure the icon resides inside the "secure area", it is really important the assets have the correct size (see https://developer.android.com/guide/practices/ui_guidelines/icon_design_adaptive)

    2. The convertion to bitmap is key:

      private static Bitmap drawableToBitmap(final Drawable drawable, final Context context) {
      
        final float screenDensity = context.getResources().getDisplayMetrics().density;
        final int adaptiveIconSize = Math.round(ADAPTIVE_ICON_SIZE_DP * screenDensity);
        final int adaptiveIconOuterSides = Math.round(ADAPTIVE_ICON_OUTER_SIDES_DP * screenDensity);
      
        final Bitmap bitmap = Bitmap.createBitmap(adaptiveIconSize, adaptiveIconSize, Bitmap.Config.ARGB_8888);
        final Canvas canvas = new Canvas(bitmap);
        drawable.setBounds(adaptiveIconOuterSides, adaptiveIconOuterSides, adaptiveIconSize - adaptiveIconOuterSides,
              adaptiveIconSize - adaptiveIconOuterSides);
        drawable.draw(canvas);
        return bitmap;
      }