Transparent adaptive icon background

Easiest Solution ever:

  1. Assuming you have a PNG file with a transparent background (preferably, square ratio), let's call it "app_icon.png", put it in your drawable folder P.S: It doesn't matter how large it is, what matters is the square ratio.

  2. Go to AndroidManifest.xml, in your main application tag, check for the

    android:icon="@mipmap/app_icon"

and change it to

android:icon="@drawable/app_icon"
  1. Delete all your "mipmap" folders now since you don't need them.

Why does this work: This tells android to use a drawable DIRECTLY from the folder as an icon, without going through the hurdle of mipmap XML files.

Congratulations, now you will have a logo with a transparent background.


TL;DR Adaptive Icons cannot have transparent Background

Transparent background will be opaque black.

According to the source code of Android 8.0 framework, the <background> layer is inherently opaque; the framework fills the background with opaque black, as mentioned in the question.

The framework has a class AdaptiveIconDrawable, which draws adaptive launcher icons. https://developer.android.com/reference/android/graphics/drawable/AdaptiveIconDrawable.html
The element <adaptive-icon> creates an instance of it:

This class can also be created via XML inflation using <adaptive-icon> tag in addition to dynamic creation.

The source code of method draw in AdaptiveIconDrawable.java is:

@Override
public void draw(Canvas canvas) {
    if (mLayersBitmap == null) {
        return;
    }
    if (mLayersShader == null) {
        mCanvas.setBitmap(mLayersBitmap);
        mCanvas.drawColor(Color.BLACK);
        for (int i = 0; i < mLayerState.N_CHILDREN; i++) {
            if (mLayerState.mChildren[i] == null) {
                continue;
            }
            final Drawable dr = mLayerState.mChildren[i].mDrawable;
            if (dr != null) {
                dr.draw(mCanvas);
            }
        }
        mLayersShader = new BitmapShader(mLayersBitmap, TileMode.CLAMP, TileMode.CLAMP);
        mPaint.setShader(mLayersShader);
    }
    if (mMaskBitmap != null) {
        Rect bounds = getBounds();
        canvas.drawBitmap(mMaskBitmap, bounds.left, bounds.top, mPaint);
    }
}

In short, a Canvas instance receives a bitmap to draw into, and initially it fills the bitmap with black color. Then the foreground drawable and the background drawable do the job:

mCanvas.setBitmap(mLayersBitmap); // reset
mCanvas.drawColor(Color.BLACK);   // fill
for (int i = 0; i < mLayerState.N_CHILDREN; i++) { // two layers
    ...
    final Drawable dr = mLayerState.mChildren[i].mDrawable;
    ...
        dr.draw(mCanvas); // draw
    ...
}

The Color.BLACK is opaque:

0xff000000

The method drawColor fills the bitmap with it, using SRC_OVER mode:

Fill the entire canvas' bitmap (restricted to the current clip) with the specified color, using srcover porterduff mode.

So, the background will be always opaque, even if you set transparent color to the background, as in the screenshot below (from my answer to a similar question).

NoAdaptive and Adaptive

Tags:

Android