Android SetSystemUiVisibility
#1
Hi,

I have written a JNI method call to call the above. It hides the nav bar on my nexus 7. It of course pops back up on touch input. I am looking for a pointer on where to look to make this call when media is playing. I find the bar annoying during media playback and would like to auto hide it.

My first go at JNI too, so if any one wants to critique my code here it is, will do a pull request when I have done, if I can get up to scratch):

void CXBMCApp::SetSystemUiVisibility(int visibility)
{
if (m_activity == NULL)
return;

JNIEnv *env = NULL;
AttachCurrentThread(&env);
jobject oActivity = m_activity->clazz;
jclass cActivity = env->GetObjectClass(oActivity);

android_printf("CXBMCApp::HideAndroidNavigationBar Looking for: setSystemUiVisibility");
jmethodID MethodGetWindow = env->GetMethodID(cActivity, "getWindow", "()Landroid/view/Window;");
jobject lWindow = env->CallObjectMethod(oActivity, MethodGetWindow);
jclass cWindow = env->FindClass("android/view/Window");
jclass cView = env->FindClass("android/view/View");
jmethodID MethodGetDecorView = env->GetMethodID(cWindow, "getDecorView", "()Landroid/view/View;");
jobject lDecorView = env->CallObjectMethod(lWindow, MethodGetDecorView);
jmethodID MethodSetSystemUiVisibility = env->GetMethodID(cView, "setSystemUiVisibility", "(I)V");
jint jVisibility = visibility;
env->CallVoidMethod(lDecorView, MethodSetSystemUiVisibility, jVisibility);

//cleanup
env->DeleteLocalRef(oActivity);
env->DeleteLocalRef(cActivity);
env->DeleteLocalRef(lWindow);
env->DeleteLocalRef(cWindow);
env->DeleteLocalRef(cView);
env->DeleteLocalRef(lDecorView);

DetachCurrentThread();
}
Reply
#2
(2012-07-31, 15:14)jamiejones85 Wrote: Hi,

I have written a JNI method call to call the above. It hides the nav bar on my nexus 7. It of course pops back up on touch input. I am looking for a pointer on where to look to make this call when media is playing. I find the bar annoying during media playback and would like to auto hide it.

The nav bar are the buttons like MENU, HOME etc? If so the problem is that we target the API version 9 and the SYSTEM_UI_FLAG_HIDE_NAVIGATION flag has been introduced with the API version 14 so it is not available in our builds.

Concerning your code:

There's no real standard or convention here but I use "mid" in front of every jmethodID variable so in case of "getWindow()" it would be midWindowGetWindow. jobject variables have a leading "o" and "jint" variables a leading "i".

(2012-07-31, 15:14)jamiejones85 Wrote: My first go at JNI too, so if any one wants to critique my code here it is, will do a pull request when I have done, if I can get up to scratch):

void CXBMCApp::SetSystemUiVisibility(int visibility)
{
if (m_activity == NULL)
return;

JNIEnv *env = NULL;
AttachCurrentThread(&env);
jobject oActivity = m_activity->clazz;
jclass cActivity = env->GetObjectClass(oActivity);

android_printf("CXBMCApp::HideAndroidNavigationBar Looking for: setSystemUiVisibility");
jmethodID MethodGetWindow = env->GetMethodID(cActivity, "getWindow", "()Landroid/view/Window;");
jobject lWindow = env->CallObjectMethod(oActivity, MethodGetWindow);
jclass cWindow = env->FindClass("android/view/Window");
You can use env->GetObjectClass(lWindow) to get a reference to the proper jclass object. That's safer than FindClass().

(2012-07-31, 15:14)jamiejones85 Wrote: jclass cView = env->FindClass("android/view/View");
Again you can use GetObjectClass() after retrieving lDecorView 2 lines further down.

(2012-07-31, 15:14)jamiejones85 Wrote: jmethodID MethodGetDecorView = env->GetMethodID(cWindow, "getDecorView", "()Landroid/view/View;");
jobject lDecorView = env->CallObjectMethod(lWindow, MethodGetDecorView);
jmethodID MethodSetSystemUiVisibility = env->GetMethodID(cView, "setSystemUiVisibility", "(I)V");
jint jVisibility = visibility;
env->CallVoidMethod(lDecorView, MethodSetSystemUiVisibility, jVisibility);
No need for the extra jint variable. Just pass the "visibility" variable to CallVoidMethod (and add an explicit cast in front of it to be sure).

(2012-07-31, 15:14)jamiejones85 Wrote: //cleanup
env->DeleteLocalRef(oActivity);
No need to delete this reference as it is a global reference always available in the ANativeActivite struct.

(2012-07-31, 15:14)jamiejones85 Wrote: env->DeleteLocalRef(cActivity);
env->DeleteLocalRef(lWindow);
env->DeleteLocalRef(cWindow);
env->DeleteLocalRef(cView);
env->DeleteLocalRef(lDecorView);

DetachCurrentThread();
}

What I'm unsure is what values can be passed to your method. My guess is one of the android.view.View.SYSTEM_UI_FLAG_*** constants but there's no documentation on it in your code. Wouldn't a boolean parameter be better suited as all we want to do is toggle show/hide of the navigation bar?
Always read the online manual (wiki), FAQ (wiki) and search the forum before posting.
Do not e-mail Team Kodi members directly asking for support. Read/follow the forum rules (wiki).
Please read the pages on troubleshooting (wiki) and bug reporting (wiki) before reporting issues.
Reply
#3
Thanks for the reply.

SYSTEM_UI_FLAG_HIDE_NAVIGATION is equal to 2, so just for my testing I was passing in a value of 2 to make it hide. Which works.
SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION = 512 is also another option to make xbmc interface sit behind the navigation bar.

I am still experimenting at this stage.

It is the bar at the bottom, http://static.trustedreviews.com/94%7C00...nexus7.jpg, I want it hidden when a video is playing.
Reply
#4
/**
* http://developer.android.com/reference/a...FULLSCREEN
* Possible param values can be found above.
* SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION = 512 (0x00000200)
* SYSTEM_UI_FLAG_HIDE_NAVIGATION = 2 (0x00000002)
* are the most interesting for me
*/
void CXBMCApp::SetSystemUiVisibility(int visibility)
{
if (m_activity == NULL)
return;

//setSystemUiVisibility has been in since api 11 http://developer.android.com/reference/a...ility(int)
if (CAndroidFeatures::GetVersion() < 11)
return;

JNIEnv *env = NULL;
AttachCurrentThread(&env);
jobject oActivity = m_activity->clazz;
jclass cActivity = env->GetObjectClass(oActivity);

android_printf("CXBMCApp::HideAndroidNavigationBar Looking for: setSystemUiVisibility");
jmethodID midWindowGetWindow = env->GetMethodID(cActivity, "getWindow", "()Landroid/view/Window;");
jobject lWindow = env->CallObjectMethod(oActivity, midWindowGetWindow);

jclass cWindow = env->GetObjectClass(lWindow);
jmethodID midViewGetDecorView = env->GetMethodID(cWindow, "getDecorView", "()Landroid/view/View;");

jobject lDecorView = env->CallObjectMethod(lWindow, midViewGetDecorView);
jclass cView = env->GetObjectClass(lDecorView);
//get the setSystemUiVisibilityMethod
jmethodID midViewSetSystemUiVisibility = env->GetMethodID(cView, "setSystemUiVisibility", "(I)V");
//call the setSystemUiVisibility method
env->CallVoidMethod(lDecorView, midViewSetSystemUiVisibility, (jint)visibility);

//cleanup
env->DeleteLocalRef(cActivity);
env->DeleteLocalRef(lWindow);
env->DeleteLocalRef(cWindow);
env->DeleteLocalRef(cView);
env->DeleteLocalRef(lDecorView);

DetachCurrentThread();
}
Any better?

Reply
#5
Yup looks better know but the initial problem with setSystemUiVisibility only being available for android 3.0+ (api level 11) and the two flags even only for api level 14/16+ and XBMC currently targeting api level 9 still exists.
Always read the online manual (wiki), FAQ (wiki) and search the forum before posting.
Do not e-mail Team Kodi members directly asking for support. Read/follow the forum rules (wiki).
Please read the pages on troubleshooting (wiki) and bug reporting (wiki) before reporting issues.
Reply
#6
(2012-07-31, 21:25)Montellese Wrote: Yup looks better know but the initial problem with setSystemUiVisibility only being available for android 3.0+ (api level 11) and the two flags even only for api level 14/16+ and XBMC currently targeting api level 9 still exists.

Forgive my ignorance, does that mean I cant use the AndroidFeatures that was recently added to check the build number and use my own constant with a value of 2? I'm new to android and open source.
Reply
#7
It doesn't really matter what version of android you are running. What matters is which API version XBMC is built against (which has to be equal or lower to what you are running on your device). AFAIK if you build against API version 9 you will not be able to access any features introduced afterwards. But if you can prove me wrong I won't object Wink
Always read the online manual (wiki), FAQ (wiki) and search the forum before posting.
Do not e-mail Team Kodi members directly asking for support. Read/follow the forum rules (wiki).
Please read the pages on troubleshooting (wiki) and bug reporting (wiki) before reporting issues.
Reply
#8
It seems that you can. I am building against version 9 but I am able to hide the navigation bar on the home screen.
Reply
#9
Maybe it's because of the dynamic nature of JNI i.e. you get a reference/ID of a class/method at runtime so there's no compiler or anything else that stops you from accessing features of a newer API version.
Always read the online manual (wiki), FAQ (wiki) and search the forum before posting.
Do not e-mail Team Kodi members directly asking for support. Read/follow the forum rules (wiki).
Please read the pages on troubleshooting (wiki) and bug reporting (wiki) before reporting issues.
Reply
#10
Montellese - same is possible with iOS (thank god). We can call objectiveC selectors of iOS 5.1 runtime even if we are building against iOS 4.3 SDK. (we have to check that the object responds to the selector before calling it - guess something like that will be done when getting the reference from jni).
AppleTV4/iPhone/iPod/iPad: HowTo find debug logs and everything else which the devs like so much: click here
HowTo setup NFS for Kodi: NFS (wiki)
HowTo configure avahi (zeroconf): Avahi_Zeroconf (wiki)
READ THE IOS FAQ!: iOS FAQ (wiki)
Reply
#11
Been new to this I am having a bit of an issue.

android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.

Thus so far haven't found where the android view is created and by which thread. Any one able to point me to where it is created? I thought it was in WinEGPlatformAndroid.cpp

Is there some documentation about the general architecture and sub systems?

Thanks
Reply
#12
We never explicitely create a view. We get a reference to a native window object from the native activity and use that to create the necessary EGL context.
Always read the online manual (wiki), FAQ (wiki) and search the forum before posting.
Do not e-mail Team Kodi members directly asking for support. Read/follow the forum rules (wiki).
Please read the pages on troubleshooting (wiki) and bug reporting (wiki) before reporting issues.
Reply
#13
I think my answer my lie in android_native_app_glue.c
Reply
#14
I have now managed to get this working, been quite busy. I have had to make use of a small java class that implements Runnable to override the run method to get it to work.

Would a solution that requires a small amount of java be excepted in to mainline? I know there is an empty class in there (class xbmc{}) atm.
Reply
#15
The code to do this is in my git if anyone wants to have a look, I'll do a pull request when it is polished. When the navigation bar is hidden the playing video needs to be resized to reclaim the space that was used. Any pointers on this?
Reply

Logout Mark Read Team Forum Stats Members Help
SetSystemUiVisibility0