Background
Starting from Android O, apps can have adaptive icons, which are 2 layers of drawables: foreground and a background. The background is a mask that gets to be a shape of the launcher/user's choice, while the OS has a default shape for it too.
Here's an example of what Nova Launcher allows to do:
As you can see, it allows not only to choose which shape to use, but also avoid a shape at all (in "prefer legacy icons").
Here are some links about it:
- https://www.youtube.com/watch?v=5MHFYfXno9c
- https://medium.com/@ianhlake/vectordrawable-adaptive-icons-3fed3d3205b5
The problem
While I know how to create a AdaptiveIconDrawable instance, and I'm aware of the wizard that helps creating one for the current app, I don't get how, given an AdaptiveIconDrawable instance, launchers change the shape.
Not only that, but I remember I saw a launcher or two that allows to not have any shape.
Sadly I can't find any information about this part, maybe because this is a relatively very new feature. There isn't even a keyword for it here on StackOverflow.
What I've tried
I tried reading about adaptive icons, but couldn't find a reference to the receiver side.
I know it has the 2 drawables within it:
- https://developer.android.com/reference/android/graphics/drawable/AdaptiveIconDrawable.html#getBackground()
- https://developer.android.com/reference/android/graphics/drawable/AdaptiveIconDrawable.html#getForeground()
I know, at least, how to get an AdaptiveIconDrawable instance out of a third party app (assuming it has one) :
PackageManager pm = context.getPackageManager();
Intent launchIntentForPackage = pm.getLaunchIntentForPackage(packageName);
String fullPathToActivity = launchIntentForPackage.getComponent().getClassName();
ActivityInfo activityInfo = pm.getActivityInfo(new ComponentName(packageName, fullPathToActivity), 0);
int iconRes = activityInfo.icon;
Drawable drawable = pm.getDrawable(packageName, iconRes, activityInfo.applicationInfo); // will be AdaptiveIconDrawable, if the app has it
The questions
Given a AdaptiveIconDrawable instance, how do you shape it, to be of a circular shape, rectangle, rounded rectangle, tear, and so on?
How do I remove the shape and still have a valid size of the icon (using its foreground drawable in it) ? The official size of an app icon for launchers is 48 dp, while the official ones for AdaptiveIconDrawable inner drawables are 72dp (foreground), 108dp (background). I guess this would mean taking the foreground drawable, resize it somehow, and convert to a bitmap.
In which case exactly is it useful to use
IconCompat.createWithAdaptiveBitmap()? It was written that "If you’re building a dynamic shortcut using a Bitmap, you might find the Support Library 26.0.0-beta2’s IconCompat.createWithAdaptiveBitmap() useful in ensuring that your Bitmap is masked correctly to match other adaptive icons." , but I don't get which cases it's useful for.
EDIT: In order to create a bitmap out of the foreground part of the adaptive icon, while resizing to a proper size, I think this could be a good solution:
val foregroundBitmap = convertDrawableToBitmap(drawable.foreground)
val targetSize = convertDpToPixels(this, ...).toInt()
val scaledBitmap = ThumbnailUtils.extractThumbnail(foregroundBitmap, targetSize, targetSize, ThumbnailUtils.OPTIONS_RECYCLE_INPUT)
fun convertDrawableToBitmap(drawable: Drawable?): Bitmap? {
if (drawable == null)
return null
if (drawable is BitmapDrawable) {
return drawable.bitmap
}
val bounds = drawable.bounds
val width = if (!bounds.isEmpty) bounds.width() else drawable.intrinsicWidth
val height = if (!bounds.isEmpty) bounds.height() else drawable.intrinsicHeight
val bitmap = Bitmap.createBitmap(if (width <= 0) 1 else width, if (height <= 0) 1 else height,
Bitmap.Config.ARGB_8888)
val canvas = Canvas(bitmap)
drawable.setBounds(0, 0, canvas.width, canvas.height)
drawable.draw(canvas)
drawable.bounds = bounds;
return bitmap
}
fun convertDpToPixels(context: Context, dp: Float): Float = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, context.resources.displayMetrics)
Might be able to avoid having 2 bitmaps at the same time, but this is ok I think.
About the creation of a shaped drawable of various types, I'm still not sure how to do it. Only solution I've seen by the answers below is of using a rounded rectangle or a circle, but there are other shapes (for example the tear) that can come to mind.
EDIT: I was told as some point by Google (here) that I should use AdaptiveIconDrawable.getIconMask(), but I wasn't given any further information. However, I've found a nice article about this here.



Since Launcher is just an Activity, you can draw anything. You can draw application icons like ponies that run on beautiful animated clouds. This is your world, which obeys only your rules.
Further ... There is no magic in the programming world. If you are faced with magic, just use decompilers (with Java it very easy), find the code responsible for magic, document it and write a great blog post about how this magic works.
You can use AdaptiveIconDrawable.getBackground() and add any mask to it. Actually, you can do anything what you want with icon, AdaptiveIconDrawable is just way, where you can split foreground and background in easy way, without complicated filters or neural networks. Add parallax, animations and many more effects, now you have 2 layer for it.