5

I've seen articles and articles on hiding the navigation bar for android application through java. However, what I would like to know, is how do I remove the navigation bar through a pure android c++ native-activity application for a full-screen application(game)(NO JAVA AT ALL!). Full-screen from the android manifest works at hiding the top bar, but the navigation bar stays visible.

This is the Navigation Bar that I wish to remove.

I've searched through books with no luck, there's is no actual documentation for native-activity and google searches result in nothing. There is only the comments inside some of the header files which are tiny comments that don't even help. It seems the topic regarding pure c++ android applications is a black spot yet a lot of games that are coming out on the market are written in c++.

I've also tried setting:

AConfiguration_setNavHidden(m_app->config, ACONFIGURATION_NAVHIDDEN_YES);

But it seems to do nothing, in fact all the AConfiguratin_setXXX seem to do nothing. Perhaps I'm calling it in the wrong place? I've been calling it during APP_CMD_INIT_WINDOW after creating the window. Where should I be calling this function?

MightyMoo
  • 101
  • 6
  • AFAIK, you can not do it without calling Java APIs. You may have to call java methods via JNI from pure C++ code using `GetMethodID` and [related functions](https://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/functions.html). AConfiguration is probably not what you need — based on quick glance over docs, it is for editing Java `Configuration` object. You need to get `jobject` for your `Activity`, obtain `JNIEnv` and use it to call Java methods required for your task. – user1643723 Dec 09 '16 at 12:12
  • I just had a job interview today and I mentioned this problem, and apparently they had the same problem but solved it with pure c++. I forgot to ask them how they did it before I left, but it sounds like it is possible. My last resort, if I can't find an answer, is to partially use Java, like a normal human being. Thanks for your input though! – MightyMoo Dec 09 '16 at 12:29
  • Using C++ to call Java methods with JNI *is* "pure C++" because you are not writing any Java code — just using JVM C++ API to call Java methods. – user1643723 Dec 09 '16 at 12:35
  • Yes I understand that "pure c++" is still using java calls. I just need the secret ingredient to hide the navigation. I know there is one, there has to be! What I meant by partially using java as a last resort, was hiding the navigation on the java. – MightyMoo Dec 09 '16 at 12:39

2 Answers2

6

I found this piece of code which works (requiring API level > 19). Just call the function at the beginning of main().

void AutoHideNavBar(struct android_app* state)
{
    JNIEnv* env{};
    state->activity->vm->AttachCurrentThread(&env, NULL);

    jclass activityClass = env->FindClass("android/app/NativeActivity");
    jmethodID getWindow = env->GetMethodID(activityClass, "getWindow", "()Landroid/view/Window;");

    jclass windowClass = env->FindClass("android/view/Window");
    jmethodID getDecorView = env->GetMethodID(windowClass, "getDecorView", "()Landroid/view/View;");

    jclass viewClass = env->FindClass("android/view/View");
    jmethodID setSystemUiVisibility = env->GetMethodID(viewClass, "setSystemUiVisibility", "(I)V");

    jobject window = env->CallObjectMethod(state->activity->clazz, getWindow);

    jobject decorView = env->CallObjectMethod(window, getDecorView);

    jfieldID flagFullscreenID = env->GetStaticFieldID(viewClass, "SYSTEM_UI_FLAG_FULLSCREEN", "I");
    jfieldID flagHideNavigationID = env->GetStaticFieldID(viewClass, "SYSTEM_UI_FLAG_HIDE_NAVIGATION", "I");
    jfieldID flagImmersiveStickyID = env->GetStaticFieldID(viewClass, "SYSTEM_UI_FLAG_IMMERSIVE_STICKY", "I");

    const int flagFullscreen = env->GetStaticIntField(viewClass, flagFullscreenID);
    const int flagHideNavigation = env->GetStaticIntField(viewClass, flagHideNavigationID);
    const int flagImmersiveSticky = env->GetStaticIntField(viewClass, flagImmersiveStickyID);
    const int flag = flagFullscreen | flagHideNavigation | flagImmersiveSticky;

    env->CallVoidMethod(decorView, setSystemUiVisibility, flag);

    state->activity->vm->DetachCurrentThread();
}
Viktor Sehr
  • 12,825
  • 5
  • 58
  • 90
5

So! If anyone is curious, I did come up with an answer from rummaging through one of Microsoft's teapot examples. And this is what I came up with:

public class NameOfActivity extends NativeActivity {

void setImmersiveSticky() {
    View decorView = getWindow().getDecorView();
    decorView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_FULLSCREEN
            | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
            | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
            | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
            | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
            | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
}

@Override
protected void onCreate(Bundle savedInstanceState) {
    setContentView(R.layout.activity_main);

    int SDK_INT = android.os.Build.VERSION.SDK_INT;
    if (SDK_INT >= 19) {
        setImmersiveSticky();

        View decorView = getWindow().getDecorView();
        decorView.setOnSystemUiVisibilityChangeListener
                (new View.OnSystemUiVisibilityChangeListener() {
                    @Override
                    public void onSystemUiVisibilityChange(int visibility) {
                        setImmersiveSticky();
                    }
                });
    }
    super.onCreate(savedInstanceState);
}

@Override
protected void onResume() {
    //Hide toolbar
    int SDK_INT = android.os.Build.VERSION.SDK_INT;
    if (SDK_INT >= 11 && SDK_INT < 14) {
        getWindow().getDecorView().setSystemUiVisibility(View.STATUS_BAR_HIDDEN);
    } else if (SDK_INT >= 14 && SDK_INT < 19) {
        getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_LOW_PROFILE);
    } else if (SDK_INT >= 19) {
        setImmersiveSticky();
    }
    super.onResume();
}

}

The pure c++ android development still uses java, it gets it from the source inside the android SDK directory. What you can do is extend the NativeActivity with a few additional tweaks. Inside the manifest all you have to do is:

    android:hasCode="true"

and then the most importan part is to change the activity name from

        android:name="android.app.NativeActivity"

to

        android:name="com.example.package.NameOfActivity"

It will still call the android main and set it up just like a regular native activity, but now it gives you a completely full-screen. I hope this helps someone out there. It took me a days of searching for answers, and this is what I could come up with!

GOOD LUCK!

MightyMoo
  • 101
  • 6
  • I've found this from sfml, its full c++ and takes account of older api versions : https://github.com/SFML/SFML/blob/fae3b65f0567f87fa9925cd42d28df15eb69e79c/src/SFML/Main/MainAndroid.cpp#L139 – user2591935 Jan 03 '17 at 18:29
  • Thank you very much, I really hopes this works for me too :) – Viktor Sehr Jun 09 '18 at 21:36
  • Yes, extending the NativeActivity is the way to go about this. That's what Google are doing there too: https://github.com/googlesamples/android-ndk/tree/master/teapots/classic-teapot – Slion Jul 31 '18 at 11:12
  • How is this the accepted answer? It uses Java, when the request was to not use Java! – Jon Watte Nov 03 '20 at 21:40