CMakeLists.txt:
cmake_minimum_required(VERSION 3.10.2)

project(native-activity)

add_library(native_app_glue STATIC ${ANDROID_NDK}/sources/android/native_app_glue/android_native_app_glue.c)

set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -u ANativeActivity_onCreate")

file(GLOB_RECURSE native-activity_SRC "*.hpp" "*.cpp")
add_library(native-activity SHARED ${native-activity_SRC})

target_include_directories (native-activity PRIVATE ${ANDROID_NDK}/sources/android/native_app_glue PRIVATE ${native-activity_SRC})
target_link_libraries(native-activity android native_app_glue log jnigraphics)

Я хочу увидеть какое то UI.  OpenGL ES мне больше не нужен. Но я хочу обойтись без Java и XML layout : 
#include <android/native_activity.h>
#include <android_native_app_glue.h>
#include <GLES/gl.h>
#include <EGL/egl.h>
#include <android/log.h>
#include <iostream>
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, "NativeActivity", __VA_ARGS__)

struct Engine {
    android_app* app;
    EGLDisplay display = EGL_NO_DISPLAY;
    EGLSurface surface = EGL_NO_SURFACE;
    EGLContext context = EGL_NO_CONTEXT;
    bool initialized = false;
    float color = 0.0f;
    float targetColor = 1.0f;
    float fadeSpeed = 0.01f;
};

void update_fade(Engine* engine) {
    engine->color = std::clamp(engine->color + (engine->color < engine->targetColor ? engine->fadeSpeed : -engine->fadeSpeed), 0.0f, 1.0f);
    if (engine->color <= 0.0f || engine->color >= 1.0f) engine->targetColor = 1.0f - engine->targetColor;
}

// Инициализация OpenGL ES
void engine_init(Engine* engine) {
    static const EGLint configAttribs[] = {
            EGL_RENDERABLE_TYPE, EGL_OPENGL_ES_BIT,
            EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
            EGL_RED_SIZE, 5,
            EGL_GREEN_SIZE, 6,
            EGL_BLUE_SIZE, 5,
            EGL_DEPTH_SIZE, 16,
            EGL_NONE
    };
    static const EGLint contextAttribs[] = {
            EGL_CONTEXT_CLIENT_VERSION, 1,
            EGL_NONE
    };

    engine->display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
    if (engine->display != EGL_NO_DISPLAY && eglInitialize(engine->display, nullptr, nullptr)) {
        EGLConfig config;
        EGLint numConfigs;
        if (eglChooseConfig(engine->display, configAttribs, &config, 1, &numConfigs)) {
            engine->context = eglCreateContext(engine->display, config, EGL_NO_CONTEXT, contextAttribs);
            engine->surface = eglCreateWindowSurface(engine->display, config, engine->app->window, nullptr);
            if (engine->context != EGL_NO_CONTEXT && engine->surface != EGL_NO_SURFACE &&
                eglMakeCurrent(engine->display, engine->surface, engine->surface, engine->context)) {
                engine->initialized = true;
                glClearColor(1.0f, 0.0f, 0.0f, 1.0f);  // Инициализация OpenGL ES
                return;
            }
        }
    }
    LOGE("EGL initialization failed");
}

void engine_draw_frame(Engine* engine) {
    if (!engine->initialized) return;

    update_fade(engine);

    glClearColor(engine->color, engine->color, engine->color, 1);  // Цвет фона с прозрачностью
    glClear(GL_COLOR_BUFFER_BIT);

    if (!eglSwapBuffers(engine->display, engine->surface)) {
        if (EGLint error = eglGetError(); error != EGL_BAD_SURFACE && error != EGL_NOT_INITIALIZED) {
            LOGE("EGL: eglSwapBuffers failed with error 0x%x", error);
        }
    }
}


// Обработка команд
void handle_cmd(android_app* app, int32_t cmd) {
    auto* engine = static_cast<Engine*>(app->userData);
    if (cmd == APP_CMD_INIT_WINDOW && app->window) {
        engine_init(engine);
    } else if (cmd == APP_CMD_TERM_WINDOW && engine->initialized) {
        eglDestroySurface(engine->display, engine->surface);
        eglDestroyContext(engine->display, engine->context);
        eglTerminate(engine->display);
        engine->initialized = false;
    }
}

// Главная функция
void android_main(android_app* state) {
    Engine engine{state};

    state->userData = &engine;
    state->onAppCmd = handle_cmd;

    while (true) {
        int events;
        android_poll_source* source;

        if (ALooper_pollAll(0, nullptr, &events, reinterpret_cast<void**>(&source)) >= 0) {
            if (source) source->process(state, source);
            if (state->destroyRequested) {
                if (engine.initialized) {
                    eglDestroySurface(engine.display, engine.surface);
                    eglDestroyContext(engine.display, engine.context);
                    eglTerminate(engine.display);
                }
                return;
            }
        }
        engine_draw_frame(&engine);
    }
}