260 lines
8.4 KiB
Plaintext
260 lines
8.4 KiB
Plaintext
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>
|