How do I enable full screen immersive mode for a Native Activity NDK app?

拥有回忆 提交于 2019-12-22 17:06:07

问题


Reading the documentation at https://developer.android.com/training/system-ui/immersive.html I can't seem to find any information on how to set full screen immersive mode in a Native Activity NDK app (without using JNI) as it seems full screen immersive mode can only be toggled from Java.

As it cannot be set from the manifest (Set Android immersive full screen mode in manifest), is there any way to request it via EGL?

Seems the only way to enable full screen immersive mode is to call setSystemUiVisibility via JNI ahead of requesting a surface via EGL?


回答1:


Answering my own question, you can set immersive mode via C++/JNI without add java to your project. Here is my snippet, large parts are copied from somewhere on the internet.

auto portis::android_util::SetImmersiveMode(JNIEnv* env, android_app* iandroid_app) -> bool {
    PORTIS_ASSERT(iandroid_app && env);

    jclass activityClass = env->FindClass("android/app/NativeActivity");
    jclass windowClass = env->FindClass("android/view/Window");
    jclass viewClass = env->FindClass("android/view/View");
    jmethodID getWindow = env->GetMethodID(activityClass, "getWindow", "()Landroid/view/Window;");
    jmethodID getDecorView = env->GetMethodID(windowClass, "getDecorView", "()Landroid/view/View;");
    jmethodID setSystemUiVisibility = env->GetMethodID(viewClass, "setSystemUiVisibility", "(I)V");
    jmethodID getSystemUiVisibility = env->GetMethodID(viewClass, "getSystemUiVisibility", "()I");

    jobject windowObj = env->CallObjectMethod(iandroid_app->activity->clazz, getWindow);
    jobject decorViewObj = env->CallObjectMethod(windowObj, getDecorView);

    // Get flag ids
    jfieldID id_SYSTEM_UI_FLAG_LAYOUT_STABLE = env->GetStaticFieldID(viewClass, "SYSTEM_UI_FLAG_LAYOUT_STABLE", "I");
    jfieldID id_SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION = env->GetStaticFieldID(viewClass, "SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION", "I");
    jfieldID id_SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN = env->GetStaticFieldID(viewClass, "SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN", "I");
    jfieldID id_SYSTEM_UI_FLAG_HIDE_NAVIGATION = env->GetStaticFieldID(viewClass, "SYSTEM_UI_FLAG_HIDE_NAVIGATION", "I");
    jfieldID id_SYSTEM_UI_FLAG_FULLSCREEN = env->GetStaticFieldID(viewClass, "SYSTEM_UI_FLAG_FULLSCREEN", "I");
    jfieldID id_SYSTEM_UI_FLAG_IMMERSIVE_STICKY = env->GetStaticFieldID(viewClass, "SYSTEM_UI_FLAG_IMMERSIVE_STICKY", "I");

    // Get flags
    const int flag_SYSTEM_UI_FLAG_LAYOUT_STABLE = env->GetStaticIntField(viewClass, id_SYSTEM_UI_FLAG_LAYOUT_STABLE);
    const int flag_SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION = env->GetStaticIntField(viewClass, id_SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
    const int flag_SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN = env->GetStaticIntField(viewClass, id_SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
    const int flag_SYSTEM_UI_FLAG_HIDE_NAVIGATION = env->GetStaticIntField(viewClass, id_SYSTEM_UI_FLAG_HIDE_NAVIGATION);
    const int flag_SYSTEM_UI_FLAG_FULLSCREEN = env->GetStaticIntField(viewClass, id_SYSTEM_UI_FLAG_FULLSCREEN);
    const int flag_SYSTEM_UI_FLAG_IMMERSIVE_STICKY = env->GetStaticIntField(viewClass, id_SYSTEM_UI_FLAG_IMMERSIVE_STICKY);

    // Get current immersiveness
    const int currentVisibility = env->CallIntMethod(decorViewObj, getSystemUiVisibility);
    const bool is_SYSTEM_UI_FLAG_LAYOUT_STABLE = (currentVisibility & flag_SYSTEM_UI_FLAG_LAYOUT_STABLE) != 0;
    const bool is_SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION = (currentVisibility & flag_SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) != 0;
    const bool is_SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN = (currentVisibility & flag_SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN) != 0;
    const bool is_SYSTEM_UI_FLAG_HIDE_NAVIGATION = (currentVisibility & flag_SYSTEM_UI_FLAG_HIDE_NAVIGATION) != 0;
    const bool is_SYSTEM_UI_FLAG_FULLSCREEN = (currentVisibility & flag_SYSTEM_UI_FLAG_FULLSCREEN) != 0;
    const bool is_SYSTEM_UI_FLAG_IMMERSIVE_STICKY = (currentVisibility & flag_SYSTEM_UI_FLAG_IMMERSIVE_STICKY) != 0;

    const auto isAlreadyImmersive =
        is_SYSTEM_UI_FLAG_LAYOUT_STABLE &&
        is_SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION &&
        is_SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN &&
        is_SYSTEM_UI_FLAG_HIDE_NAVIGATION &&
        is_SYSTEM_UI_FLAG_FULLSCREEN &&
        is_SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
    PORTIS_LOGD()
        << "set_immersive data"
        << is_SYSTEM_UI_FLAG_LAYOUT_STABLE
        << is_SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
        << is_SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
        << is_SYSTEM_UI_FLAG_HIDE_NAVIGATION
        << is_SYSTEM_UI_FLAG_FULLSCREEN
        << is_SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
    auto success = true;
    if (true) {
        const int flag =
            flag_SYSTEM_UI_FLAG_LAYOUT_STABLE |
            flag_SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION |
            flag_SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN |
            flag_SYSTEM_UI_FLAG_HIDE_NAVIGATION |
            flag_SYSTEM_UI_FLAG_FULLSCREEN |
            flag_SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
        env->CallVoidMethod(decorViewObj, setSystemUiVisibility, flag);
        if(env->ExceptionCheck()) {
            // Read exception msg
            jthrowable e = env->ExceptionOccurred();
            env->ExceptionClear(); // clears the exception; e seems to remain valid
            jclass clazz = env->GetObjectClass(e);
            jmethodID getMessage = env->GetMethodID(clazz, "getMessage", "()Ljava/lang/String;");
            jstring message = (jstring)env->CallObjectMethod(e, getMessage);
            const char *mstr = env->GetStringUTFChars(message, NULL);
            const auto exception_msg = std::string{mstr};
            env->ReleaseStringUTFChars(message, mstr);
            env->DeleteLocalRef(message);
            env->DeleteLocalRef(clazz);
            env->DeleteLocalRef(e);
            PORTIS_LOGW() << "set_immersive exception [" << exception_msg << "]";
            success = false;
        }
        else {
            PORTIS_LOGI() << "set_immersive success";
        }
    }
    env->DeleteLocalRef(windowObj);
    env->DeleteLocalRef(decorViewObj);
    return success;
}


来源:https://stackoverflow.com/questions/47507714/how-do-i-enable-full-screen-immersive-mode-for-a-native-activity-ndk-app

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!