The previous recipes in this chapter provided simple examples with the logcat output only. This recipe will discuss how to manage the native window at Android NDK.
Readers are recommended to read the following recipes before going through this one:
Also recall that native window management has been introduced briefly in the Displaying graphics with EGL recipe in Chapter 4, Android NDK OpenGL ES API.
The following steps create the sample application:
NativeWindowManagement
. Set the package name as cookbook.chapter5.nativewindowmanagement
. Please refer to the Loading native libraries and registering native methods recipe of Chapter 2, Java Native Interface, if you want more detailed instructions.NativeWindowManagement
project, select Android Tools | Add Native Support.AndroidManifest.xml
. Please refer to previous recipe or the downloaded code for details. Note that the metadata android.app.lib_name
must have its value as NativeWindowManagement
.NativeWindowManagement.cpp
and mylog.h
under the jni
folder. NativeWindowManagement.cpp
is modified based on previous recipe. The following code snippet shows the updated part:void drawSomething(struct android_app* app) { ANativeWindow_Buffer lWindowBuffer; ANativeWindow* lWindow = app->window; ANativeWindow_setBuffersGeometry(lWindow, 0, 0, WINDOW_FORMAT_RGBA_8888); if (ANativeWindow_lock(lWindow, &lWindowBuffer, NULL) < 0) { return; } memset(lWindowBuffer.bits, 0, lWindowBuffer.stride*lWindowBuffer.height*sizeof(uint32_t)); int sqh = 150, sqw = 100; int wst = lWindowBuffer.stride/2 - sqw/2; int wed = wst + sqw; int hst = lWindowBuffer.height/2 - sqh/2; int hed = hst + sqh; for (int i = hst; i < hed; ++i) { for (int j = wst; j < wed; ++j) { ((char*)(lWindowBuffer.bits))[(i*lWindowBuffer.stride + j)*sizeof(uint32_t)] = (char)255; //R ((char*)(lWindowBuffer.bits))[(i*lWindowBuffer.stride + j)*sizeof(uint32_t) + 1] = (char)0; //G ((char*)(lWindowBuffer.bits))[(i*lWindowBuffer.stride + j)*sizeof(uint32_t) + 2] = (char)0; //B ((char*)(lWindowBuffer.bits))[(i*lWindowBuffer.stride + j)*sizeof(uint32_t) + 3] = (char)255; //A } } ANativeWindow_unlockAndPost(lWindow); } void handle_activity_lifecycle_events(struct android_app* app, int32_t cmd) { LOGI(2, "%d: dummy data %d", cmd, *((int*)(app->userData))); switch (cmd) { case APP_CMD_INIT_WINDOW: drawSomething(app); break; } }
Android.mk
file under the jni
folder, which is similar to the one used in the previous recipe. You just need to replace the module name as NativeWindowManagement
and the source file as NativeWindowManagement.cpp
.$ adb logcat -v time NativeWindowManagement:I *:S
When the application starts, we will see the following logcat:
The device screen will display a red rectangle at the center of the screen, as follows:
The NDK interface for native window management is defined in the window.h
, rect.h
, native_window_jni.h
, and native_window.h
header files. The first two simply define some constants and data structures. native_window_jni.h
defines a single function named
ANativeWindow_fromSurface
, which helps us to obtain a native window from a Java surface object. We have illustrated this function in the Displaying graphics with EGL recipe in Chapter 4, Android NDK OpenGL ES API. Here, we focus on the functions provided in native_window.h
.
Perform the following steps to draw a square on the phone screen:
ANativeWindow_setBuffersGeometry
function:
int32_t ANativeWindow_setBuffersGeometry(ANativeWindow* window, int32_t width, int32_t height, int32_t format);
This function updates the native window buffer associated with the native window referred by the window input argument. The window size and format are changed according to the rest of the input arguments. Three formats are defined in native_window.h
, including WINDOW_FORMAT_RGBA_8888
, WINDOW_FORMAT_RGBX_8888
, and WINDOW_FORMAT_RGB_565
. If the size or the format is set to 0
, then the native window's base value will be used.
ANativeWindow_lock
function:int32_t ANativeWindow_lock(ANativeWindow* window, ANativeWindow_Buffer* outBuffer, ARect* inOutDirtyBounds);
After this call is returned, the input argument outBuffer
will refer to the window buffer for drawing.
memset
to set all the data to 0
.255
. This will show us a red rectangle.ANativeWindow_unlockAndPost
function:int32_t ANativeWindow_unlockAndPost(ANativeWindow* window);