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<uses-sdk android:minSdkVersion="9" /> 36</pre> 37 38<p>The following line declares {@code android:hasCode} as {@code false}, as this app has only 39native code–no Java. 40</p> 41 42<pre class="no-pretty-print"> 43<application android:label="@string/app_name" 44android:hasCode="false"> 45</pre> 46 47<p>The next line declares the {@code NativeActivity} class.</p> 48 49<pre class="no-pretty-print"> 50<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<meta-data android:name="android.app.lib_name" 59 android:value="native-activity" /> 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 <EGL/egl.h> 144#include <GLES/gl.h> 145 146 147#include <android/sensor.h> 148#include <android/log.h> 149#include <android_native_app_glue> 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(&engine, 0, sizeof(engine)); 174state->userData = &engine; 175state->onAppCmd = engine_handle_cmd; 176state->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->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 &events, 212 (void**)&source)) >= 0) { 213 214 215 // Process this event. 216 if (source != NULL) { 217 source->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 &event, 1) > 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->destroyRequested != 0) { 237 engine_term_display(&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 > 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(&engine); 257 } 258} 259</pre> 260