Category: android

Dark Mode Musings: Beware of the Context 🌗

Dark Mode Musings: Beware of the Context 🌗

I’ve been working on getting Dark Mode in our app fully supported and I stumbled upon an interesting finding:

The Application#applicationContext does not keep information about the theme that you have set via AppCompatDelegate.setDefaultNightMode(), only a View or Activity context has this information stored. 

After reading through Chris Banes’ articles and watching some great talks about Styles, Themes & Dark Mode, I felt pretty comfortable that I knew quite a bit about the Theming system on Android. However, this particular issue was something that I was not expecting, which is why I decided to document this particular problem I faced. 

The Problem

I have the “Dark theme” set on in my system settings, but inside my app I am explicitly setting the theme to light mode (even though my device theme is set to Dark):


I have two bitmap resources: one located in drawable and one located in drawable-night

Despite my app theme overriding the mode to “light”, the resource from drawable-night was loaded instead of the one from thedrawable folder. 

Why was this happening? 🧐

I was using the Application#applicationContext to load up the Bitmap: 

class BitmapLoader(val context: Context) {

override fun loadBitmap(@RawRes resourceId: Int, bitmapConfig: Bitmap.Config): Bitmap? {
val options =
BitmapFactory.Options().apply { inPreferredConfig = bitmapConfig }
return BitmapFactory.decodeResource(
context.resources, resourceId, options
// This class was used in a similar way to the following usage:
val bitmapLoader = BitmapLoader(application.applicationContext)

The Solution

The fix in this case was to use the Activity#context method or View#context, instead of Application#applicationContext

The lesson here is that the Application#applicationContext should not be used for retrieving UI resources. The Application object will only have system-level information and not information that is set by AppCompatDelegate. AppCompatDelegate only works on the activity-level.

You need to be very careful of the context you use when obtaining resources that could change based on the theme. 

Thanks for reading, if you have any questions or comments — feel free to reach out on Twitter @riggaroo

Thanks to Chris Banes and Alan Viverette for confirming what I was experiencing is intentional.

Lessons Learnt with Kotlin: Extension Functions

Lessons Learnt with Kotlin: Extension Functions

At Over, we’ve been using Kotlin since we started the new Android version of the app in November 2018. From day one, we’ve been excited to try the language features and leverage them to build our mobile design app.

One of the features we were most excited about was extension functions.

What is an Extension Function?

An extension function allows you to extend a classes functionality without needing to edit (or have access to) the class itself. They are great for libraries whose classes you can’t access. 

This is an example of an extension function in Kotlin: 

fun Point = Point(width / 2f, height / 2f)

You can then use it wherever required, as if that function formed part of the Canvas class itself, although it is not explicitly part of the API: 

val centerPoint =

How we overused them:

When we first started writing Kotlin, we were eager to use the new functionality of the language. We wanted to use extension functions and we didn’t realise the consequences of over-using them. We ended up with a code base that used them everywhere

The main functionality of the app (i.e. the rendering of projects), was written with extension functions. Want to render an image to the screen? Extension function. Want to render some text to the screen? Extension function. Want to do anything that doesn’t quite fit into the MVVM/MVP/MVI model? Extension function. 

This got tricky when we needed to start doing background loading and caching. Where should that logic and state be kept if everything is just an extension function? 🤨

It was at this point that we realised we had overused extension functions. Instead of creating new classes and concepts, we had created extension functions. 

This meant we needed to do a large refactor of the rendering to remove extension functions and rather create a new class to perform this related functionality.  


This is not a blog post stating that “extension functions are terrible! don’t use them!”. They are an extremely useful feature of the language and we still use them at Over. We are just a bit more careful about what we use them for and where

We don’t do this ❌

We don’t use extension functions for non-related methods. For instance, this example below should not form part of the String API. It is unrelated functionality to the String class and shouldn’t be provided as an extension on that class since its specific to our business logic.  

fun String.toUserProperties() : UserProperties {
return UserProperties(this.toUppercase())

In this case, we would rather not make the extension function at all and just use the constructor of the UserProperties class to get this functionality. 

One thing to remember is that this function will be made available to your entire project (if you don’t make it private), which is also a great reason not to make an extension function. 

We do this ✅

We add extension functions onto classes when it makes sense to do so and the function relates to the class that we are extending.

For example, this method can totally be a part of the String API since it is related to String manipulation and it is commonly used throughout our app:

fun String.toGraphemeCharsList(): List<String> {
// do something to get list of grapheme characters

Side note: For those who are unfamiliar with the word grapheme . A grapheme is the smallest unit of a writing system. In Java/Kotlin, calling the loved String.toCharArray() method, will return characters in their unicode form. So if you are working with emoji or special characters, they are generally made up of more than one unicode character. For instance, the following emoji: 👩‍👩‍👧 is actually a combination of multiple emojis (as well as multiple unicode characters), so String.toCharArray() returns the “incorrect” number of visible characters on screen, it returns the number of unicode characters. Read more about this here.

However, we favor creating new classes for new behaviour, instead of adding extension functions onto existing classes.

We use extension functions on classes that aren’t extendable (i.e. classes that are part of the framework or primitives). We also create private extensions and use them only in the file they were created.

Summary 📃

Extension functions are a powerful feature in Kotlin that can be overused if you are not careful about when and where you use them. We made that mistake early on and now we are a lot more aware of our usages of them. 

Hopefully this article helps you reason about extension functions, when you are considering using them in your code. 

Have any thoughts or questions? Find me on Twitter.

Over ❤️ Kotlin – How we’ve used Kotlin to build our design app

Over ❤️ Kotlin – How we’ve used Kotlin to build our design app

I recently presented this talk at Kotlin Everywhere South Africa as the keynote for the event. I really enjoyed preparing this talk as it spoke about how we use Kotlin, mistakes we’ve made along the way and our opinion on how we decide to use certain features. 

Talk Description:

Over the past year and a half, I’ve worked primarily on a Kotlin codebase. We at Over, were lucky enough to get a chance to start a project from scratch and we chose Kotlin for many reasons. Our app has been featured multiple times on the Google Play Store and we have found ourselves facing some unique challenges with the product.

In this talk, I’ll cover what my experience has been like working on a Kotlin codebase. I will cover some of the features in Kotlin we use the most, some features we eagerly over used and some of the mistakes we’ve made along the way.

The video recording can be found here: 

The slides for the talk can be found here:

Android Canvas Drawing: Useful Graphics Classes & Operations 🧪

Android Canvas Drawing: Useful Graphics Classes & Operations 🧪

Drawing on an Android Canvas is quite overwhelming, there are many different classes and concepts to understand when drawing something. If you haven’t already read part one of this series make sure to read it here.

In this post, we will be covering some classes that you will find available within the Android Framework which can make your life a bit easier when working with a canvas.

Rect / RectF ◼️

A rectangle class that stores four values: topleftright and bottom. These can be used for drawing directly on canvas or just for storing sizes of objects that you want to draw.

The difference between the Rect and RectF class is that the RectF stores float values, where as the Rect class stores integers.

val rect = RectF(100.0f, 200.0f, 300.0f, 400.0f)

With KTX there are many graphics extension functions that you should take advantage of. For instance, there are some for Rect and RectF. One such extension is the destructuring declaration which gets components out of a Rect object:

val rect = RectF(100.0f, 200.0f, 300.0f, 400.0f)
val (left, top, right, bottom) = rect
// left = 100.0f, top = 200.0f, right = 300.0f, bottom = 400.0f

You can do other operations with a Rect class, for instance, you can union two Rects together. This basically just includes the points from both Rectsand returns a bigger Rect that contains both Rects inside it. There are also extension functions for this operation, but it is also possible without the extension:

val rect = RectF(100.0f, 200.0f, 300.0f, 400.0f)
val otherRect = RectF(50.0f, 400.0f, 150.0f, 500.0f)
// rect = RectF(50.0, 200.0, 300.0, 500.0)
// alternatively:
val combinedRect = rect + otherRect
// or alternatively:
val combinedRect = rect or otherRect
// combinedRect = RectF(50.0, 200.0, 300.0, 500.0)

There are other operations you can perform on a Rect, such as : andxoror.

Point / PointF 👉🏽

Stores an x and y coordinate which represents a “point” on a canvas. Point stores integer values, whereas PointF stores floating point values.

val point = PointF(200.0f, 300.0f)

If you are using KTX, there are some extension functions built onto the Point and PointF classes that make working with points much easier. For instance, operator overloads which add the ability to plus and minus two points from each other.

val start = PointF(100.0f, 30.0f)
val end = PointF(20.0f, 10.0f)
val difference = start - end
val together = start + end
// together = Point(120.0f, 40.0f)

There also exists destructuring declarations for these classes, so we can easily get out x and y coordinates out easily from the Point class:

val start = PointF(100.0f, 30.0f)
val end = PointF(20.0f, 10.0f)
val (x, y) = start - end
// x = 80.0f y = 20.0f

Matrix 🔢

A 3 by 3 Matrix that stores information which can be used to transform a canvas. A Matrix can store the following kind of transformation information: scale, skew, rotation, translation.

Below is an example of using a Matrix to transform a Bitmap that is drawn on a Canvas.

Examples of Matrix transformations

To use a Matrix when drawing, you can do the following:

val customMatrix = Matrix()
// in onDraw()
canvas.withMatrix(customMatrix) {
    drawBitmap(bitmap, null, rect, paint)

The above code will draw a bitmap on a canvas that is rotated at 20 degrees. There are a few other functions on a Matrix that we can use such as scaling, rotating and skewing. The great part about using a Matrix over doing everything yourself manually with Canvas transformations, is that the Matrix holds cumulative information about the transformations that are applied to it.

If you translate the Matrix, rotate, scale and translate again, the end values of the translation would be a bit different than the original values. If you were to do this yourself, you would need to calculate that manually if you were performing normal Canvas translate, scale functions.

preRotate vs proRotate vs setRotate

You might be wondering what postRotate means, considering the fact that there are other methods such as setRotate and preRotate on a Matrix. These three methods all do slightly different things:

setRotate — Completely resets the current Matrix and applies the rotation, thus losing any information that you may already have stored in your Matrix.

preRotate — The rotation will be applied before whatever the currentMatrix contains.

postRotate — The rotation will be applied after whatever the currentMatrix contains.

Perspective Drawing with Matrix

Matrix object can also provide us with the ability to perform perspective drawing, which is not possible to achieve with just standard Canvas transformation APIs. The function that allows perspective drawing or skewing of a canvas is Matrix#setPolyToPoly() . This method does sound a bit confusing at first, but once you wrap your head around how it works, it is not so bad!

Here is an example bitmap that has been “skewed” using the setPolyToPolymethod.

Bitmap drawn with setPolyToPoly

The setPolyToPoly method takes input (src) “points”, and maps them to the specified output (dst) “points”. I say “points” because they aren’t real point objects as we’ve just explored earlier in this post, but they are rather just values in a float array, which can be quite confusing.

You can see in the src array below, the first two values are representing the top left point of the image, the second two values represent the top right point and so on. These points can be in any order, but they must match with the corresponding point that you want it to map to, in the dstarray.

val src = floatArrayOf(
    0f, 0f, // top left point
    width, 0f, // top right point
    width, height, // bottom right point
    0f, height // bottom left point
val dst = floatArrayOf(
    50f, -200f, // top left point
    width, -200f, // top right point
    width, height +200f, // bottom right point
    0f, height // bottom left point
val pointCount = 4 // number of points

// the second and fourth arguments represent the index in the src and dest arrays from which the points should start being mapped from
newMatrix.setPolyToPoly(src, 0, dst, 0, pointCount)

canvas.withMatrix(newMatrix) {
   drawBitmap(bitmap, null, rect, paint)

In this example, the bottom right point, will be mapped from the point [width, height] to the point [width, height +200f].

So you can see from the above example that a Matrix can do some pretty powerful and interesting stuff.

Tip: Use the Matrix class to work between different coordinate systems

If you have two different coordinate systems that you are dealing with on a single view, then leveraging a Matrix class can help you map between the two.

For instance, if you get a touch event from Android that is measured in the height and width of the size of the screen, but you would like to know what that point would be inside the image you are drawing on screen, within that coordinate system (ie the coordinate system of the image), you can use a Matrix to map between these two systems.

Example of two different coordinate systems

In order to get the point mapped inside the image drawn on screen, we can use the Matrix#mapPoints() method:

fun mapPoint(point: PointF): PointF {
computeMatrix.reset() // apply the same transformations on the matrix that are applied to the Image
computeMatrix.postTranslate(20f, 20f)
computeMatrix.postRotate(20f, x, y) // create float array with the points we want to map
val arrayPoint = floatArrayOf(point.x, point.y) // use the map points function to apply the same transformations that the matrix has, onto the input array of coordinates
computeMatrix.mapPoints(arrayPoint) // get the points out from the array, these will now be transformed by the matrix.
return PointF(arrayPoint[0], arrayPoint[1])

In the above example, the input point would be the touch event from Android, and the translation and rotation that we apply on the computeMatrix is the same translation and rotation we applied on the image when it was drawn. Then we create a float array which contains the original x and y point. We then call the mapPoints method with this array. It’ll then transform the values in place and when we query the array for the first and second values it’ll be the mapped coordinate, which is the point inside the image view.

Summary 👨🏾‍🎨

You can see that the Android Graphics APIs contain loads of useful classes that you can leverage to do a lot of the calculations and mathematics for you. From Points to Rects to more complex calculation classes like Matrixclasses, we can see that there are many things we can use to help us draw graphics on the screen! Make sure to include KTX to have an even smoother experience when working with Android Graphics classes.

Have any questions or comments? Feel free to reach out and say hi to me on Twitter.

Getting Started with Android Canvas Drawing 🖼

Getting Started with Android Canvas Drawing 🖼

Learn the basics of drawing with the Android Canvas Class

Diving into using the Android Canvas class can unlock magical super powers you never knew you had 🤯. Imagine being able to draw anything* your heart desires just with some basic shapes, paths and bitmaps? Well, the Android Canvas gives you just that ability. 

What is a Canvas?

Canvas is a class in Android that performs 2D drawing of different objects onto the screen. The saying “a blank canvas” is very similar to what a Canvas object is on Android. It is basically, an empty space to draw onto. 

The Canvas class is not a new concept, this class is actually wrapping a SKCanvas under the hood. The SKCanvas comes from SKIA, which is a 2D Graphics Library that is used on many different platforms. SKIA is used on platforms such as Google Chrome, Firefox OS, Flutter, Fuschia etc. Once you understand how the Canvas works on Android, the same drawing concepts apply to many other different platforms. 

Tip: Check out the SKIA source code for a deeper understanding of the Canvas implementation.

It is useful to know that SKIA is used in the underlying code for Android, so when you get stuck trying to understand how a certain API works, you can look at the source for SKIA to gain a deeper understanding.

Canvas Coordinate System

The Android Canvas coordinate system.
The Android Canvas Coordinate System

The coordinate system of the Android canvas starts in the top left corner, where [0,0] represents that point. The y axis is positive downwards, and x axis positive towards the right.

All elements drawn on a canvas are placed relative to the [0,0] point. 

When working with the Canvas, you are working with px and not dp, so any methods such as translating, or resizing will be done in pixel sizes. This means you need to translate any dp values into px before calling any canvas operations. This will ensure that your drawing looks consistent across devices with different pixel densities. 

Canvas draw commands will draw over previously drawn items. The last draw command will be the topmost item drawn onto your canvas. It is up to you to ensure that your items are laid out correctly (Alternatively, you might want to use some of the built-in layout mechanisms for this — such as LinearLayout). 

How do I use a Canvas?

To draw onto a canvas in Android, you will need four things:

  1. A bitmap or a view — to hold the pixels where the canvas will be drawn.
  2. Canvas — to run the drawing commands on.
  3. Drawing commands — to indicate to the canvas what to draw.
  4. Paint — to describe how to draw the commands.

Get access to a Canvas instance

In order to get access to a Canvas instance, you will need to create a class that extends from View. This will then allow you to override the onDraw method, which has a Canvas as a parameter. 

class CustomView @JvmOverloads constructor(context: Context,
attrs: AttributeSet? = null, defStyleAttr: Int = 0)
: View(context, attrs, defStyleAttr) {

// Called when the view should render its content.
override fun onDraw(canvas: Canvas?) {

You can then include this view inside your layout XML and this will then automatically invoke the onDraw method of the Custom View. 


You can also get access to a Canvas object by programatically creating one in code, like this:

val bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888) 
val canvas = Canvas(bitmap)

It’s worth noting at this point that any Canvas created programmatically without using a View, will be software rendered and not hardware rendered. This can affect the appearance of some of the drawing commands. For instance, some commands are just not supported with hardware rendering, or only supported from a certain API level. For more information about the differences between hardware rendering and software rendering, read this post

What can I draw on a Canvas? ✏️

There are many different things you can draw onto a Canvas. One of the most common drawing operations is to draw a bitmap (image) onto the canvas. The method for doing this is just called drawBitmap and it takes in the bitmap object that is loaded up either with Android’s built-in mechanisms, or with Glide.

canvas.drawBitmap(bitmap, null, rect, paint)

The second parameter here allows us to pass in the portion of the bitmap that you want to render, when passing in null the whole bitmap will be rendered. The third parameter is a RectF object which represents the scale and translation of the bitmap that you want to draw on screen. 

Tip: Make sure your RectF object that you pass into the drawBitmap function is scaled with the correct aspect ratio otherwise your output may be stretched

You need to be careful with this, since it can quite easily stretch the bitmap, as the Canvas calls don’t take into account the aspect ratio of the provided image. You need to ensure the rect that is passed in is properly scaled. The fourth parameter is the paint object, we will cover the purpose of this parameter soon.

There are many other Canvas drawing methods that can give you some great looking views. We won’t be covering them all here, but here are two other examples of drawing methods on the Canvas class:

To draw a circle onto the view, give it a center point x,y , its size and apaint object:

canvas.drawCircle(x, y, size, paint)

Another one is the drawRect() method. This draws a rectangle on screen:

canvas.drawRect(rect, paint)

This is not the full list of drawing methods but just a small highlight of some of them to get you more comfortable with the concepts, feel free to browse the Canvas documentation for a comprehensive list of all of them. 

Paint 🎨

In my opinion, the Paint class is possibly the most interesting graphics class and it is also my favourite, for that very reason. There is so much that a Paint object can do that can really make your drawing operations shine. ✨

The Paint class typically holds colour and style information. The Paint object is then used for drawing objects (i.e. bitmap, text, paths etc) onto a Canvas

To create a Paint object: 

private val textPaint =
Paint().apply {
isAntiAlias = true
color = Color.RED
style = Paint.Style.STROKE

This object should be created before using it in Canvas#onDraw(). It is not recommended to create it in onDraw() since you shouldn’t be doing object allocations in that method. 

isAntiAlias Flag

Tip: Use the isAntiAlias flag to ensure your drawing has smooth edges.

The isAntiAlias flag is quite an important one. If you are drawing objects to your canvas and you notice that the edges of your objects have jagged edges, it is likely that you haven’t set this flag to true. This flag indicates to the paint to smooth out the edges of the object you are drawing to the canvas. 

The Paint class has more than just those three properties, there are many more things you can do with it. For instance, you can also set properties related to text rendering, such as the typeface, letterSpacing(kerning) and textSize.

private val textPaint =
Paint().apply {
isAntiAlias = true
textSize = fontSize
letterSpacing = letterSpace
typeface = newTypeface
setShadowLayer(blurValue, x, y, Color.BLACK)

Unsupported Operations

Tip: Check that the Canvas/Paint APIs you are using work across different API versions. See this site for more information.

It is worth noting that the Paint#setShadowlayer() method doesn’t work consistently across API levels and drawing commands. It works when drawing text on a Canvas, but applying the shadow to other commands such as drawBitmap doesn’t yield the same results across API levels. 

The reason for the inconsistency between API levels is because the Canvas APIs are bundled with the Android Platform and therefore are not updated until the OS is updated. See the list on this page for more information about which APIs work on which Android versions. 

Once you’ve created the Paint object, pass that object into your Canvas#draw*() calls and the drawing will then take on the properties you’ve specified in the paint. 

Next up…

In the next few articles, we will be diving into other parts of working with Canvas and drawing on Android. Be sure to subscribe to updates and follow me on Twitter for more tips. 

If you prefer watching this content — be sure to check out my talk from Mobile Matters London for a summary of this content.