Keeping cool in Android Q with the Thermal API

We’ve all been there are some point – using our Android device and things start to feel like they’re getting a bit warm in our hands. Whether we’re playing a game or using an application that is performing an intensive operation, these things can often require a lot of resources which makes our device work harder.

In these kind of situations, applications should attempt to reduce the amount of resources that they are consuming in an attempt to bring the device out of that high temperature zone. If we’re playing a game then maybe it could reduce the frame rate being used, or the streaming app that we’re using could reduce the resolution being used for the media content. Even smaller things such as disabling / reducing specific hardware usage (camera flash, speaker volume, location services) can be change to reduce the resource usage.



With Android Q we see a new addition added to the Power Manager API that allows us to both retrieve and listen to the state of a device thermal status. Whilst we could previously achieve some data around the battery temperature from the BatteryManager API, this addition to the PowerManager gives us an overall status of the device condition and does not just focus on a specific temperature value, making it both simpler to understand and use.

Note: In order to make use of this API, devices require a new HAL layer to provide this functionality. This is currently supported on Pixel devices and is looking to expand to other device vendors in the near future.


Using this new Thermal API from the Power Manager we are able to both retrieve and listen to the Thermal Status of the device. Either of these routes will provide us with 1 of the 8 available status values.

When it comes to retrieving the current thermal status of the device, we can do this by making use of the getCurrentThermalStatus() function from the Power Manager. When we call this, we’re going to get back one of the thermal status values stated within the power manager.

  • THERMAL_STATUS_NONE
  • THERMAL_STATUS_LIGHT
  • THERMAL_STATUS_MODERATE
  • THERMAL_STATUS_SEVERE
  • THERMAL_STATUS_SHUTDOWN
  • THERMAL_STATUS_CRITICAL
  • THERMAL_STATUS_EMERGENCY

As we go down this list of status values we can see that they get progressively worse. When we receive the THERMAL_STATUS_NONE value back from the Thermal API this indicates that the device is not currently undergoing any thermal throttling. However, any other values indicate that there is some throttling taking place and the operations you are performing within your application may need to be reconsidered. Whilst there is no clear indication of the temperatures in question here, the names of these values give us some indication on how serious the current temperature state of the device is.


To get started with the Thermal API we need to begin by retrieving an instance of the PowerManager. Once we have this we can then use it to access the current thermal status:

val powerManager = getSystemService(Context.POWER_SERVICE) 
        as PowerManager
val currentStatus = powerManager.currentThermalStatus

When we retrieve this thermal status for the device we will be returned one of the thermal status values that we previously looked at. Each of these values is actually just an integer that is used to represent the current status of the device:

public static final int THERMAL_STATUS_NONE = 0;
public static final int THERMAL_STATUS_LIGHT = 1;
public static final int THERMAL_STATUS_MODERATE = 2;
public static final int THERMAL_STATUS_SEVERE = 3;
public static final int THERMAL_STATUS_CRITICAL = 4;
public static final int THERMAL_STATUS_EMERGENCY = 5;
public static final int THERMAL_STATUS_SHUTDOWN = 6;

It would make sense for us to retrieve this status when we are trying to start some operation that could be quite intensive on the device. For example, if the device is already in a state of THERMAL_STATUS_SEVERE, then it might not make sense to start an operation with the full resource requirements. Not only may the user have been doing something intensive before opening your application, but they could be multi-tasking and have multiple applications open at the same time.


As well as being able to retrieve the current thermal status we can also listen for any changes by making use of addThermalStatusListener(). This function takes an instance of the OnThermalStatusChangedListener interface, this provides a single function called onThermalStatusChanged() to provide us with the changed thermal status of the device.

powerManager.addThermalStatusListener {
    // do something with status
}

If you wish to subscribe to thermal status updates on a separate thread it is also possible to provide an Executor instance, as per this method. This instance is used to dispatch the callback and listener events which are provided from this observation of the thermal status.

Using this listener allows us to monitor the thermal status of the device and adjust the resources that we are using within our application. So for example, as the thermal status increases we may reduce certain aspects of the experience we are providing (e.g. reduce the frame rate, resolution or hardware feature usage) to bring the thermal status down. And then, once the device is at a more stable state, the listener can again be used to bring the resources back up to more acceptable levels.


Whilst it’s understandable that the Thermal API might not be useful for all applications, it proves to be invaluable for those which it is applicable for. If your application is one that may be sending a users device into a THERMAL_STATUS_SHUTDOWN at an extreme, or if your application is constantly over consuming a devices resources without being mindful that it is doing so, then that user may look elsewhere for an application that takes these things into consideration.

If you do work on an application that may benefit from utilising the Thermal API then I’d love to hear your thoughts about it. Either way, please feel free to reach out if you have any questions!

[twitter-follow screen_name=’hitherejoe’ show_count=’yes’]