diff options
Diffstat (limited to 'docs/html-ndk/ndk/samples/sample_na.jd')
-rw-r--r-- | docs/html-ndk/ndk/samples/sample_na.jd | 259 |
1 files changed, 259 insertions, 0 deletions
diff --git a/docs/html-ndk/ndk/samples/sample_na.jd b/docs/html-ndk/ndk/samples/sample_na.jd new file mode 100644 index 0000000..a677de5 --- /dev/null +++ b/docs/html-ndk/ndk/samples/sample_na.jd @@ -0,0 +1,259 @@ +page.title=Sample: native-activity +@jd:body + +<div id="qv-wrapper"> + <div id="qv"> + <h2>On this page</h2> + + <ol> + <li><a href="#am">AndroidManifest.xml</a></li> + <li><a href="#anm">Android.mk</a></li> + <li><a href="#apm">Application.mk</a></li> + <li><a href="#mac">main.c</a></li> + </ol> + </li> + </ol> + </div> + </div> + +<p>The native-activity sample resides under the NDK installation root, in +{@code samples/native-activity}. It is a very simple example of a purely native +application, with no Java source code. In the absence of any Java source, the +Java compiler still creates an executable stub for the virtual machine to run. +The stub serves as a wrapper for the actual, native program, which is located in the {@code .so} +file.</p> + +<p>The app itself simply renders a color onto the entire screen, and +then changes the color partly in response to movement that it detects.</p> + +<h2 id="am">AndroidManifest.xml</h2> + +<p>An app with only native code must not specify an Android API level lower than 9, which introduced +the <a href="{@docRoot}ndk/guides/concepts.html#naa">{@code NativeActivity}</a> framework class.</p> + +<pre class="no-pretty-print"> +<uses-sdk android:minSdkVersion="9" /> +</pre> + +<p>The following line declares {@code android:hasCode} as {@code false}, as this app has only +native code–no Java. +</p> + +<pre class="no-pretty-print"> +<application android:label="@string/app_name" +android:hasCode="false"> +</pre> + +<p>The next line declares the {@code NativeActivity} class.</p> + +<pre class="no-pretty-print"> +<activity android:name="android.app.NativeActivity" +</pre> + +<p>Finally, the manifest specifies {@code android:value} as the name of the shared library to be +built, minus the initial {@code lib} and the {@code .so} extension. This value must be the same as +the name of {@code LOCAL_MODULE} in {@code Android.mk}.</p> + +<pre class="no-pretty-print"> +<meta-data android:name="android.app.lib_name" + android:value="native-activity" /> +</pre> + +<h2 id="anm">Android.mk</h2> +<p>This file begins by providing the name of the shared library to generate.</p> + +<pre class="no-pretty-print"> +LOCAL_MODULE := native-activity +</pre> + +<p>Next, it declares the name of the native source-code file.</p> + +<pre class="no-pretty-print"> +LOCAL_SRC_FILES := main.c +</pre> + +<p>Next, it lists the external libraries for the build system to use in building the binary. The +{@code -l} (link-against) option precedes each library name.</p> + +<ul> +<li>{@code log} is a logging library.</li> +<li>{@code android} encompasses the standard Android support APIs for NDK. For more information about +the APIs that Android and the NDK support, see <a href="stable_apis.html">Android NDK Native +APIs</a>.</li> +<li>{@code EGL} corresponds to the platform-specific portion of the graphics API.</li> +<li>{@code GLESv1_CM} corresponds to OpenGL ES, the version of OpenGL for Android. This library +depends on EGL.</li> +</ul> + +<p>For each library:</p> + +<ul> +<li>The actual file name starts with {@code lib}, and ends with the +{@code .so} extension. For example, the actual file name for the +{@code log} library is {@code liblog.so}.</li> +<li>The library resides in the following directory, NDK root: +{@code <ndk>/platforms/android-<sdk_version>/arch-<abi>/usr/lib/}.</li> +</ul> + +<pre class="no-pretty-print"> +LOCAL_LDLIBS := -llog -landroid -lEGL -lGLESv1_CM +</pre> + +<p>The next line provides the name of the static library, {@code android_native_app_glue}, which the +application uses to manage {@code NativeActivity} lifecycle events and touch input.</p> + +<pre class="no-pretty-print"> +LOCAL_STATIC_LIBRARIES := android_native_app_glue +</pre> + +<p>The final line tells the build system to build this static library. +The {@code ndk-build} script places the built library +({@code libandroid_native_app_glue.a}) into the {@code obj} directory +generated during the build process. For more information about the {@code android_native_app_glue} +library, see its {@code android_native_app_glue.h} header and corresponding {@code .c}source file. +</p> + + +<pre class="no-pretty-print"> +$(call import-module,android/native_app_glue) +</pre> + +<p>For more information about the {@code Android.mk} file, see +<a href="{@docRoot}ndk/guides/android_mk.html">Android.mk</a>.</p> + + +<h2 id="apm">Application.mk</h2> + +<p>This line defines the minimum level of Android API Level support.</p> + +<pre class="no-pretty-print"> +APP_PLATFORM := android-10 +</pre> + +<p>Because there is no ABI definition, the build system defaults to building only for +{@code armeabi}.</p> + +<h2 id="mac">main.c</h2> +<p>This file essentially contains the entire progam.</p> + +<p>The following includes correspond to the libraries, both shared and static, +enumerated in {@code Android.mk}.</p> + +<pre class="no-pretty-print"> +#include <EGL/egl.h> +#include <GLES/gl.h> + + +#include <android/sensor.h> +#include <android/log.h> +#include <android_native_app_glue> +</pre> + +<p>The {@code android_native_app_glue} library calls the following function, +passing it a predefined state structure. It also serves as a wrapper that +simplifies handling of {@code NativeActivity} callbacks.</p> + +<pre class="no-pretty-print"> +void android_main(struct android_app* state) { +</pre> + +<p>Next, the program handles events queued by the glue library. The event +handler follows the state structure.</p> + +<pre class="no-pretty-print"> +struct engine engine; + + + +// Suppress link-time optimization that removes unreferenced code +// to make sure glue isn't stripped. +app_dummy(); + + +memset(&engine, 0, sizeof(engine)); +state->userData = &engine; +state->onAppCmd = engine_handle_cmd; +state->onInputEvent = engine_handle_input; +engine.app = state; +</pre> + +<p>The application prepares to start monitoring the sensors, using the +APIs in {@code sensor.h}.</p> + +<pre class="no-pretty-print"> + engine.sensorManager = ASensorManager_getInstance(); + engine.accelerometerSensor = + ASensorManager_getDefaultSensor(engine.sensorManager, + ASENSOR_TYPE_ACCELEROMETER); + engine.sensorEventQueue = + ASensorManager_createEventQueue(engine.sensorManager, + state->looper, LOOPER_ID_USER, NULL, NULL); +</pre> + +<p>Next, a loop begins, in which the application polls the system for +messages (sensor events). It sends messages to +{@code android_native_app_glue}, which checks to see whether they match +any {@code onAppCmd} events defined in {@code android_main}. When a +match occurs, the message is sent to the handler for execution.</p> + +<pre class="no-pretty-print"> +while (1) { + // Read all pending events. + int ident; + int events; + struct android_poll_source* source; + + + // If not animating, we will block forever waiting for events. + // If animating, we loop until all events are read, then continue + // to draw the next frame of animation. + while ((ident=ALooper_pollAll(engine.animating ? 0 : -1, NULL, + &events, + (void**)&source)) >= 0) { + + + // Process this event. + if (source != NULL) { + source->process(state, source); + } + + + // If a sensor has data, process it now. + if (ident == LOOPER_ID_USER) { + if (engine.accelerometerSensor != NULL) { + ASensorEvent event; + while (ASensorEventQueue_getEvents(engine.sensorEventQueue, + &event, 1) > 0) { + LOGI("accelerometer: x=%f y=%f z=%f", + event.acceleration.x, event.acceleration.y, + event.acceleration.z); + } + } + } + + + // Check if we are exiting. + if (state->destroyRequested != 0) { + engine_term_display(&engine); + return; + } + } +</pre> + +<p>Once the queue is empty, and the program exits the polling loop, the +program calls OpenGL to draw the screen.</p> +<pre class="no-pretty-print"> + if (engine.animating) { + // Done with events; draw next animation frame. + engine.state.angle += .01f; + if (engine.state.angle > 1) { + engine.state.angle = 0; + } + + + // Drawing is throttled to the screen update rate, so there + // is no need to do timing here. + engine_draw_frame(&engine); + } +} +</pre> |