AdaptiveIconUtil.kt 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960
  1. package ch.threema.app.utils
  2. import android.content.Context
  3. import android.graphics.Bitmap
  4. import android.graphics.BitmapFactory
  5. import android.graphics.Color
  6. import android.graphics.Paint
  7. import android.os.Build
  8. import androidx.core.graphics.applyCanvas
  9. import androidx.core.graphics.createBitmap
  10. import androidx.core.graphics.drawable.IconCompat
  11. import androidx.core.graphics.scale
  12. object AdaptiveIconUtil {
  13. /**
  14. * Creates an adaptive icon from the given [bitmap].
  15. * The icon includes appropriate amounts of padding, such that on most systems it appears to fill the available
  16. * space of the used shape, by accepting small amounts of cropping.
  17. * Returns a regular (i.e. non-adaptive) icon, scaled down to an appropriate size, if adaptive icons are not supported by the system.
  18. */
  19. @JvmStatic
  20. fun create(context: Context, bitmap: Bitmap): IconCompat {
  21. val density = context.resources.displayMetrics.density
  22. val outerSize = (OUTER_SIZE * density).toInt()
  23. val innerSize = (INNER_SIZE * density).toInt()
  24. val offset = (outerSize - innerSize) / 2f
  25. if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
  26. return IconCompat.createWithBitmap(bitmap.scale(outerSize, outerSize))
  27. }
  28. val options = BitmapFactory.Options()
  29. options.inPreferredConfig = Bitmap.Config.ARGB_8888
  30. val scaledBitmap = bitmap.scale(innerSize, innerSize, false)
  31. val paddedBitmap = createBitmap(outerSize, outerSize)
  32. try {
  33. paddedBitmap.applyCanvas {
  34. drawColor(Color.TRANSPARENT)
  35. val paint = Paint(Paint.ANTI_ALIAS_FLAG)
  36. drawBitmap(scaledBitmap, offset, offset, paint)
  37. }
  38. return IconCompat.createWithAdaptiveBitmap(paddedBitmap)
  39. } finally {
  40. scaledBitmap.recycle()
  41. }
  42. }
  43. /**
  44. * The width and height in dp of the resulting bitmap, as per the adaptive icon specifications.
  45. */
  46. private const val OUTER_SIZE = 108
  47. /**
  48. * The width and height in dp of the avatar itself centered within the resulting bitmap. Intentionally set to be slightly larger
  49. * than the 72 dp of the adaptive icon specifications, which can lead to slight cropping of the image when displayed but reduces
  50. * the likelihood that the edges of the image will be visible, leading to a nicer appearance on most systems.
  51. */
  52. private const val INNER_SIZE = 76
  53. }