Safe Area Insets not returned correctly for Android

Hi Folks,

I am trying to get safe area insets for android phones, so that I can prevent drawing my app under those blocked areas like notches and all. I am using this code which is working fine for iOS devices.

auto safeAreaInsets = juce::Desktop::getInstance().getDisplays().getPrimaryDisplay()->safeAreaInsets;

For android, its not giving correct safe area insets. I tried making a native application in Android Studio and its respecting the safe area insets. Here is the following code generated by Android Studio.

import androidx.activity.EdgeToEdge;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        EdgeToEdge.enable(this);
        setContentView(R.layout.activity_main);
        ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> {
            Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());
            v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);
            return insets;
        });
    }
}

How to implement this things in juce so that it will return correct safe area insets, so that I will draw only in safe area by subtracting this insets from local bounds.

This is very basic functionality which one would expect the framework to handle perfectly. There have been numerous threads since at least 2019 pointing these problems out but there has not been a response from anyone from the JUCE team on any of those threads.

This is on my radar. At the moment I’m focusing on MIDI 2.0, but I’m planning to investigate Android safe display areas after that.

That’s great, thank you!

Some updates:

We now do a better job of respecting safe screen areas in demo projects generated from PIPs. Such projects should now avoid placing demo content beneath notches and other screen decorations:

We’ve also updated our Android safe-area handling:

On all Android versions, we’ve switched to displaying content “edge-to-edge”, which in practice means that JUCE apps will always draw behind the status and navigation bars. On Android 15 and above, this behaviour is enforced, and we back-ported it to keep the behaviour as consistent as possible between Android versions. As a result of this change, it’s now extremely important to handle the safeAreaInsets correctly, as it’s now much more likely that content will render behind the system UI if these insets are ignored.

Finally, we’ve updated the SidePanel component to avoid areas of the screen that might be obscured. This makes the DemoRunner more usable on iPhones and Androids with screen notches:

2 Likes

I have tested this today and everything works as expected. Thank you very much!

1 Like

That’s wonderful to hear!

Weirdly, when I just tried evaluating this when looking at the JUCE 8 develop tip, it worked fine for my test when using an SDK 36 emulator, but displayed my app with a tiny window when using an emulator for SDK 35 or SDK 34 (the oldest I went back to). If anybody else spots this behaviour, do please let me know!

I decided to look again at this, and found the “tiny window” problem was due to my not calling setKioskModeComponent for the main window component. No such issue for SDK 36 emulators!

Screen Recording 2026-05-05 at 4.12.40 PM

I am encountering a critical issue specifically on devices running Android 11. After launching the app, the UI becomes completely unresponsive—no interactions are possible, and the app cannot even be closed using standard system controls. The only way to terminate the app is by restarting the device.

This issue does not occur on other Android versions. For example, the app functions correctly on a device running Android 16. I have reproduced the problem both on an Android 11 emulator and a physical device running the same version.

Notably, this behavior was not present in previous JUCE versions, which suggests a possible regression or compatibility issue introduced in newer updates.

This is a severe problem, as it effectively locks the user’s device and creates a denial-of-service–like experience. I would appreciate guidance on potential causes or solutions to resolve this issue.