1page.title=Sample: native-activity
2@jd:body
3
4<div id="qv-wrapper">
5    <div id="qv">
6      <h2>On this page</h2>
7
8      <ol>
9        <li><a href="#am">AndroidManifest.xml</a></li>
10        <li><a href="#anm">Android.mk</a></li>
11        <li><a href="#apm">Application.mk</a></li>
12        <li><a href="#mac">main.c</a></li>
13          </ol>
14        </li>
15      </ol>
16    </div>
17  </div>
18
19<p>The native-activity sample resides under the NDK installation root, in
20{@code samples/native-activity}. It is a very simple example of a purely native
21application, with no Java source code. In the absence of any Java source, the
22Java compiler still creates an executable stub for the virtual machine to run.
23The stub serves as a wrapper for the actual, native program, which is located in the {@code .so}
24file.</p>
25
26<p>The app itself simply renders a color onto the entire screen, and
27then changes the color partly in response to movement that it detects.</p>
28
29<h2 id="am">AndroidManifest.xml</h2>
30
31<p>An app with only native code must not specify an Android API level lower than 9, which introduced
32the <a href="{@docRoot}ndk/guides/concepts.html#naa">{@code NativeActivity}</a> framework class.</p>
33
34<pre class="no-pretty-print">
35&lt;uses-sdk android:minSdkVersion="9" /&gt;
36</pre>
37
38<p>The following line declares {@code android:hasCode} as {@code false}, as this app has only
39native code&ndash;no Java.
40</p>
41
42<pre class="no-pretty-print">
43&lt;application android:label="@string/app_name"
44android:hasCode="false"&gt;
45</pre>
46
47<p>The next line declares the {@code NativeActivity} class.</p>
48
49<pre class="no-pretty-print">
50&lt;activity android:name="android.app.NativeActivity"
51</pre>
52
53<p>Finally, the manifest specifies {@code android:value} as the name of the shared library to be
54built, minus the initial {@code lib} and the {@code .so} extension. This value must be the same as
55the name of {@code LOCAL_MODULE} in {@code Android.mk}.</p>
56
57<pre class="no-pretty-print">
58&lt;meta-data android:name="android.app.lib_name"
59        android:value="native-activity" /&gt;
60</pre>
61
62<h2 id="anm">Android.mk</h2>
63<p>This file begins by providing the name of the shared library to generate.</p>
64
65<pre class="no-pretty-print">
66LOCAL_MODULE    := native-activity
67</pre>
68
69<p>Next, it declares the name of the native source-code file.</p>
70
71<pre class="no-pretty-print">
72LOCAL_SRC_FILES := main.c
73</pre>
74
75<p>Next, it lists the external libraries for the build system to use in building the binary. The
76{@code -l} (link-against) option precedes each library name.</p>
77
78<ul>
79<li>{@code log} is a logging library.</li>
80<li>{@code android} encompasses the standard Android support APIs for NDK. For more information about
81the APIs that Android and the NDK support, see  <a href="stable_apis.html">Android NDK Native
82APIs</a>.</li>
83<li>{@code EGL} corresponds to the platform-specific portion of the graphics API.</li>
84<li>{@code GLESv1_CM} corresponds to OpenGL ES, the version of OpenGL for Android. This library
85depends on EGL.</li>
86</ul>
87
88<p>For each library:</p>
89
90<ul>
91<li>The actual file name starts with {@code lib}, and ends with the
92{@code .so} extension. For example, the actual file name for the
93{@code log} library is {@code liblog.so}.</li>
94<li>The library resides in the following directory, NDK root:
95{@code <ndk>/platforms/android-<sdk_version>/arch-<abi>/usr/lib/}.</li>
96</ul>
97
98<pre class="no-pretty-print">
99LOCAL_LDLIBS    := -llog -landroid -lEGL -lGLESv1_CM
100</pre>
101
102<p>The next line provides the name of the static library, {@code android_native_app_glue}, which the
103application uses to manage {@code NativeActivity} lifecycle events and touch input.</p>
104
105<pre class="no-pretty-print">
106LOCAL_STATIC_LIBRARIES := android_native_app_glue
107</pre>
108
109<p>The final line tells the build system to build this static library.
110The {@code ndk-build} script places the built library
111({@code libandroid_native_app_glue.a}) into the {@code obj} directory
112generated during the build process. For more information about the {@code android_native_app_glue}
113library, see its {@code android_native_app_glue.h} header and corresponding {@code .c}source file.
114</p>
115
116
117<pre class="no-pretty-print">
118$(call import-module,android/native_app_glue)
119</pre>
120
121<p>For more information about the {@code Android.mk} file, see
122<a href="{@docRoot}ndk/guides/android_mk.html">Android.mk</a>.</p>
123
124
125<h2 id="apm">Application.mk</h2>
126
127<p>This line defines the minimum level of Android API Level support.</p>
128
129<pre class="no-pretty-print">
130APP_PLATFORM := android-10
131</pre>
132
133<p>Because there is no ABI definition, the build system defaults to building only for
134{@code armeabi}.</p>
135
136<h2 id="mac">main.c</h2>
137<p>This file essentially contains the entire progam.</p>
138
139<p>The following includes correspond to the libraries, both shared and static,
140enumerated in {@code Android.mk}.</p>
141
142<pre class="no-pretty-print">
143#include &lt;EGL/egl.h&gt;
144#include &lt;GLES/gl.h&gt;
145
146
147#include &lt;android/sensor.h&gt;
148#include &lt;android/log.h&gt;
149#include &lt;android_native_app_glue&gt;
150</pre>
151
152<p>The {@code android_native_app_glue} library calls the following function,
153passing it a predefined state structure. It also serves as a wrapper that
154simplifies handling of {@code NativeActivity} callbacks.</p>
155
156<pre class="no-pretty-print">
157void android_main(struct android_app* state) {
158</pre>
159
160<p>Next, the program handles events queued by the glue library. The event
161handler follows the state structure.</p>
162
163<pre class="no-pretty-print">
164struct engine engine;
165
166
167
168// Suppress link-time optimization that removes unreferenced code
169// to make sure glue isn't stripped.
170app_dummy();
171
172
173memset(&amp;engine, 0, sizeof(engine));
174state-&gt;userData = &amp;engine;
175state-&gt;onAppCmd = engine_handle_cmd;
176state-&gt;onInputEvent = engine_handle_input;
177engine.app = state;
178</pre>
179
180<p>The application prepares to start monitoring the sensors, using the
181APIs in {@code sensor.h}.</p>
182
183<pre class="no-pretty-print">
184    engine.sensorManager = ASensorManager_getInstance();
185    engine.accelerometerSensor =
186                    ASensorManager_getDefaultSensor(engine.sensorManager,
187                        ASENSOR_TYPE_ACCELEROMETER);
188    engine.sensorEventQueue =
189                    ASensorManager_createEventQueue(engine.sensorManager,
190                        state-&gt;looper, LOOPER_ID_USER, NULL, NULL);
191</pre>
192
193<p>Next, a loop begins, in which the application polls the system for
194messages (sensor events). It sends messages to
195{@code android_native_app_glue}, which checks to see whether they match
196any {@code onAppCmd} events defined in {@code android_main}. When a
197match occurs, the message is sent to the handler for execution.</p>
198
199<pre class="no-pretty-print">
200while (1) {
201        // Read all pending events.
202        int ident;
203        int events;
204        struct android_poll_source* source;
205
206
207        // If not animating, we will block forever waiting for events.
208        // If animating, we loop until all events are read, then continue
209        // to draw the next frame of animation.
210        while ((ident=ALooper_pollAll(engine.animating ? 0 : -1, NULL,
211                &amp;events,
212                (void**)&amp;source)) &gt;= 0) {
213
214
215            // Process this event.
216            if (source != NULL) {
217                source-&gt;process(state, source);
218            }
219
220
221            // If a sensor has data, process it now.
222            if (ident == LOOPER_ID_USER) {
223                if (engine.accelerometerSensor != NULL) {
224                    ASensorEvent event;
225                    while (ASensorEventQueue_getEvents(engine.sensorEventQueue,
226                            &amp;event, 1) &gt; 0) {
227                        LOGI("accelerometer: x=%f y=%f z=%f",
228                                event.acceleration.x, event.acceleration.y,
229                                event.acceleration.z);
230                    }
231                }
232            }
233
234
235        // Check if we are exiting.
236        if (state-&gt;destroyRequested != 0) {
237            engine_term_display(&amp;engine);
238            return;
239        }
240    }
241</pre>
242
243<p>Once the queue is empty, and the program exits the polling loop, the
244program calls OpenGL to draw the screen.</p>
245<pre class="no-pretty-print">
246    if (engine.animating) {
247        // Done with events; draw next animation frame.
248        engine.state.angle += .01f;
249        if (engine.state.angle &gt; 1) {
250            engine.state.angle = 0;
251        }
252
253
254        // Drawing is throttled to the screen update rate, so there
255        // is no need to do timing here.
256        engine_draw_frame(&amp;engine);
257    }
258}
259</pre>
260