Wrapper of the Android native_app_glue framework to implement app.nit

The framework provides 3 different structures for a single C application under Android. We use all 3 structures in this API to implement app.nit on Android. Each structure is wrapped in a Nit extern class:

  • NativeAppGlue is the lowest level class, it is implemented by the C structure android_app. It offers features on the main Android thread (not on the same thread as Nit). For this reason, prefer to use NdkNativeActivity.

  • NdkNativeActivity is implemented by the C structure ANativeActivity. It is on the same thread as Nit and manages the synchronization with the main Android thread.

  • NativeNativeActivity is implemented in Java by android.app.NativeActivity, which is a subclass of Activity and Context (in Java). It represent main activity of the running application. Use it to get anything related to the Context and as anchor to execute Java UI code.

Introduced classes

extern class AConfiguration

android :: AConfiguration

Android NDK's struture holding configurations of the native app
extern class AInputQueue

android :: AInputQueue

Android NDK's struture to handle input events synchronously
extern class ALooper

android :: ALooper

Android NDK's structure to handle events synchronously
extern class ANativeWindow

android :: ANativeWindow

Android NDK's structure to control the native window for drawing
extern class NativeAppGlue

android :: NativeAppGlue

This is the interface for the standard glue code of a threaded
extern class NativeNativeActivity

android :: NativeNativeActivity

Android SDK's android.app.NativeActivity.
extern class NdkNativeActivity

android :: NdkNativeActivity

An Android activity implemented in C. This is the C part of NativeActivity

Redefined classes

redef class App

android :: native_app_glue $ App

App subclasses are cross-platform applications
redef class Sys

android :: native_app_glue $ Sys

The main class of the program.

All class definitions

extern class AConfiguration

android $ AConfiguration

Android NDK's struture holding configurations of the native app
extern class AInputQueue

android $ AInputQueue

Android NDK's struture to handle input events synchronously
extern class ALooper

android $ ALooper

Android NDK's structure to handle events synchronously
extern class ANativeWindow

android $ ANativeWindow

Android NDK's structure to control the native window for drawing
redef class App

android :: native_app_glue $ App

App subclasses are cross-platform applications
extern class NativeAppGlue

android $ NativeAppGlue

This is the interface for the standard glue code of a threaded
extern class NativeNativeActivity

android $ NativeNativeActivity

Android SDK's android.app.NativeActivity.
extern class NdkNativeActivity

android $ NdkNativeActivity

An Android activity implemented in C. This is the C part of NativeActivity
redef class Sys

android :: native_app_glue $ Sys

The main class of the program.
package_diagram android::native_app_glue native_app_glue android::log log android::native_app_glue->android::log android::dalvik dalvik android::native_app_glue->android::dalvik android::platform platform android::log->android::platform android::activities activities android::dalvik->android::activities ...android::platform ... ...android::platform->android::platform ...android::activities ... ...android::activities->android::activities android::cardboard cardboard android::cardboard->android::native_app_glue android::game game android::game->android::native_app_glue gamnit::cardboard cardboard gamnit::cardboard->android::cardboard gamnit::cardboard... ... gamnit::cardboard...->gamnit::cardboard android::input_events input_events android::input_events->android::game gamnit::display_android display_android gamnit::display_android->android::game android::input_events... ... android::input_events...->android::input_events gamnit::display_android... ... gamnit::display_android...->gamnit::display_android

Ancestors

module abstract_collection

core :: abstract_collection

Abstract collection classes and services.
module abstract_text

core :: abstract_text

Abstract class for manipulation of sequences of characters
module activities

android :: activities

Android Activities wrapper
module app

app :: app

app.nit is a framework to create cross-platform applications
module app_base

app :: app_base

Base of the app.nit framework, defines App
module array

core :: array

This module introduces the standard array structure.
module assets

app :: assets

Portable services to load resources from the assets folder
module aware

android :: aware

Android compatibility module
module bitset

core :: bitset

Services to handle BitSet
module bytes

core :: bytes

Services for byte streams and arrays
module circular_array

core :: circular_array

Efficient data structure to access both end of the sequence.
module codec_base

core :: codec_base

Base for codecs to use with streams
module codecs

core :: codecs

Group module for all codec-related manipulations
module collection

core :: collection

This module define several collection classes.
module collections

java :: collections

Basic Java collections
module core

core :: core

Standard classes and methods used by default by Nit programs and libraries.
module environ

core :: environ

Access to the environment variables of the process
module error

core :: error

Standard error-management infrastructure.
module exec

core :: exec

Invocation and management of operating system sub-processes.
module ffi_support

java :: ffi_support

Core supporting services for the FFI with Java
module file

core :: file

File manipulations (create, read, write, etc.)
module fixed_ints

core :: fixed_ints

Basic integers of fixed-precision
module fixed_ints_text

core :: fixed_ints_text

Text services to complement fixed_ints
module flat

core :: flat

All the array-based text representations
module gc

core :: gc

Access to the Nit internal garbage collection mechanism
module hash_collection

core :: hash_collection

Introduce HashMap and HashSet.
module iso8859_1

core :: iso8859_1

Codec for ISO8859-1 I/O
module java

java :: java

Supporting services for the FFI with Java and to access Java libraries
module jvm

jvm :: jvm

Java Virtual Machine invocation API and others services from the JNI C API
module kernel

core :: kernel

Most basic classes and methods.
module list

core :: list

This module handle double linked lists
module math

core :: math

Mathematical operations
module native

core :: native

Native structures for text and bytes
module numeric

core :: numeric

Advanced services for Numeric types
module platform

android :: platform

Triggers compilation for the android platform
module protocol

core :: protocol

module queue

core :: queue

Queuing data structures and wrappers
module range

core :: range

Module for range of discrete objects.
module re

core :: re

Regular expression support for all services based on Pattern
module ropes

core :: ropes

Tree-based representation of a String.
module sorter

core :: sorter

This module contains classes used to compare things and sorts arrays.
module stream

core :: stream

Input and output streams of characters
module text

core :: text

All the classes and methods related to the manipulation of text entities
module time

core :: time

Management of time and dates
module union_find

core :: union_find

union–find algorithm using an efficient disjoint-set data structure
module utf8

core :: utf8

Codec for UTF-8 I/O

Parents

module dalvik

android :: dalvik

Java related services specific to Android and its Dalvik VM
module log

android :: log

Advanced Android logging services

Children

module cardboard

android :: cardboard

Services from the Google Cardboard SDK for virtual reality on Android
module game

android :: game

Android services and implementation of app.nit for gamnit and mnit

Descendants

module a_star-m

a_star-m

module android19

gamnit :: android19

Variation using features from Android API 19
module camera_control_android

gamnit :: camera_control_android

Two fingers camera manipulation, pinch to zoom and slide to scroll
module cardboard

gamnit :: cardboard

Update the orientation of world_camera at each frame using the head position given by android::cardboard
module display_android

gamnit :: display_android

Gamnit display implementation for Android
module gamepad

android :: gamepad

Support for gamepad events (over Bluetooth or USB)
module gamnit_android

gamnit :: gamnit_android

Support services for Gamnit on Android
module input_events

android :: input_events

Pointer and hardware key events
module sensors

android :: sensors

Access Android sensors
module vr

gamnit :: vr

VR support for gamnit depth, for Android only
# Wrapper of the Android native_app_glue framework to implement app.nit
#
# The framework provides 3 different structures for a single C application
# under Android. We use all 3 structures in this API to implement app.nit
# on Android. Each structure is wrapped in a Nit extern class:
#
# * `NativeAppGlue` is the lowest level class, it is implemented by the C
#   structure `android_app`. It offers features on the main Android thread
#   (not on the same thread as Nit). For this reason, prefer to use
#   `NdkNativeActivity`.
#
# * `NdkNativeActivity` is implemented by the C structure `ANativeActivity`. It
#   is on the same thread as Nit and manages the synchronization with the
#   main Android thread.
#
# * `NativeNativeActivity` is implemented in Java by `android.app.NativeActivity`,
#   which is a subclass of `Activity` and `Context` (in Java). It represent
#   main activity of the running application. Use it to get anything related
#   to the `Context` and as anchor to execute Java UI code.
module native_app_glue is
	ldflags("-landroid", "-lnative_app_glue")
	android_activity "android.app.NativeActivity"
end

import platform
import log
import dalvik

in "C header" `{
	#include <android_native_app_glue.h>
`}

in "C body" `{
	struct android_app* native_app_glue_data;

	// Was `android_main` called?
	int android_main_launched = 0;

	// Entry point called by the native_app_glue_framework framework
	// We relay the call to the Nit application.
	void android_main(struct android_app* app) {
		native_app_glue_data = app;

		if (android_main_launched) {
			// Second call to `android_main`, may happen if `exit 0` was not
			// called previously to force unloading the Nit app state.
			// This happens sometimes when the `destroy` lifecycle command
			// was not correctly received.
			// We `exit 0` here hoping the system restarts the app nicely
			// without an error popup.
			exit(0);
		} else {
			android_main_launched = 1;
			int main(int argc, char ** argv);
			main(0, NULL);
		}
	}

	// Main callback on the native_app_glue framework
	//
	// We relay everything to our App.
	static void app_cmd_handler(struct android_app* app, int32_t cmd) {
		App nit_app = app->userData;
		switch (cmd) {
			case APP_CMD_SAVE_STATE:
				App_save_state(nit_app);
				break;
			case APP_CMD_INIT_WINDOW:
				App_init_window(nit_app);
				break;
			case APP_CMD_TERM_WINDOW:
				App_term_window(nit_app);
				break;
			case APP_CMD_GAINED_FOCUS:
				App_gained_focus(nit_app);
				break;
			case APP_CMD_LOST_FOCUS:
				App_lost_focus(nit_app);
				break;
			case APP_CMD_PAUSE:
				App_pause(nit_app);
				break;
			case APP_CMD_STOP:
				App_stop(nit_app);
				break;
			case APP_CMD_DESTROY:
				App_destroy(nit_app);
				break;
			case APP_CMD_START:
				App_start(nit_app);
				break;
			case APP_CMD_RESUME:
				App_resume(nit_app);
				break;
			case APP_CMD_LOW_MEMORY:
				App_low_memory(nit_app);
				break;
			case APP_CMD_CONFIG_CHANGED:
				App_config_changed(nit_app);
				break;
			case APP_CMD_INPUT_CHANGED:
				App_input_changed(nit_app);
				break;
			case APP_CMD_WINDOW_RESIZED:
				App_window_resized(nit_app);
				break;
			case APP_CMD_WINDOW_REDRAW_NEEDED:
				App_window_redraw_needed(nit_app);
				break;
			case APP_CMD_CONTENT_RECT_CHANGED:
				App_content_rect_changed(nit_app);
				break;
		}
	}
`}

# Android SDK's `android.app.NativeActivity`.
#
# Can be used to get anything related to the `Context` of the activity in Java
# and as anchor to execute Java UI code.
extern class NativeNativeActivity in "Java" `{ android.app.NativeActivity `}
	super NativeActivity
end

redef class Sys
	redef fun jvm do return app.native_app_glue.ndk_native_activity.vm
end

redef class App
	redef fun setup
	do
		var native_app_glue = native_app_glue
		native_app_glue.user_data = self

		set_as_cmd_handler(native_app_glue)
	end

	# The underlying implementation using the Android native_app_glue framework
	fun native_app_glue: NativeAppGlue `{ return native_app_glue_data; `}

	redef fun native_activity do return native_app_glue.ndk_native_activity.java_native_activity

	# Set `native_app_glue` command handler to our C implementation which
	# will callback self.
	private fun set_as_cmd_handler(native_app_glue: NativeAppGlue) import save_state,
		init_window, term_window, gained_focus, lost_focus, pause, stop, destroy,
		start, resume, low_memory, config_changed, input_changed, window_resized,
		window_redraw_needed, content_rect_changed `{
		native_app_glue->onAppCmd = &app_cmd_handler;
	`}

	# Notification from the Android framework to generate a new saved state
	#
	# You can use the `shared_preferences` module or `NativeAppGlue::saved_state`.
	fun save_state do end

	# Notification from the native_app glue framework, a new ANativeWindow is ready
	#
	# When called, `NativeAppGlue::window` returns a poiter to the new window surface.
	fun init_window do end

	# Notification from the native_app glue framework, the existing window needs to be terminated
	#
	# Upon receiving this command, `native_app_glue.window` still contains the existing window.
	fun term_window do end

	# Notification from the Android framework, `native_activity` has gained focus
	fun gained_focus do end

	# Notification from the Android framework, `native_activity` has lost focus
	fun lost_focus do end

	# Notification from the Android framework, your app has been paused
	fun pause do end

	# Notification from the Android framework, your app has been stopped
	fun stop do end

	# Notification from the Android framework, `native_activity` is being destroyed
	#
	# Clean up and exit.
	fun destroy do end

	# Notification from the Android framework, `native_activity` has been started
	fun start do end

	# Notification from the Android framework, `native_activity` has been resumed
	fun resume do end

	# Notification from the Android framework, the system is running low on memory
	#
	# Try to reduce your memory use.
	fun low_memory do force_garbage_collection

	# Notification from the Android framework, the current device configuration has changed
	fun config_changed do end

	# Notification from the Android framework, `native_app_glue.input_queue` has changed
	fun input_changed do end

	# Notification from the Android framework, the window has been resized.
	#
	# Please redraw with its new size.
	fun window_resized do end

	# Notification from the Android framework, the current ANativeWindow must be redrawn
	fun window_redraw_needed do end

	# Notification from the Android framework, the content area of the window has changed
	#
	# Raised when the soft input window being shown or hidden, and similar events.
	fun content_rect_changed do end

	# Call the `ALooper_pollAll` to retrieve events and callback the application
	fun poll_looper(timeout_ms: Int) import handle_looper_event `{
		int ident;
		int event;
		void* source;
		while ((ident=ALooper_pollAll(timeout_ms, NULL, &event, &source)) >= 0) {
			App_handle_looper_event(self, ident, event, source);
		}
	`}

	# Call the `ALooper_pollOnce` to retrieve at most one event and callback the application
	fun poll_looper_pause(timeout_ms: Int) import handle_looper_event `{
		int event;
		void* source;
		int ident = ALooper_pollOnce(timeout_ms, NULL, &event, &source);
		if (ident >= 0) {
			App_handle_looper_event(self, ident, event, source);
		}
	`}

	# Handle an event retrieved by the `ALooper` and `poll_looper` without a callback
	protected fun handle_looper_event(ident, event: Int, data: Pointer) import native_app_glue,
		save_state, init_window, term_window, gained_focus, lost_focus, pause, stop,
		destroy, start, resume, low_memory, config_changed, input_changed,
		window_resized, window_redraw_needed, content_rect_changed `{

		struct android_app *app_glue = App_native_app_glue(self);
		struct android_poll_source* source = (struct android_poll_source*)data;

		// Process this event.
		if (source != NULL) source->process(app_glue, source);
	`}
end

# An Android activity implemented in C. This is the C part of `NativeActivity`
# which is the Java part.
#
# The callbacks at this level are synchronous on the UI thread. Thus app.nit
# do not use them, and instead rely on `NativeAppGlue`.
extern class NdkNativeActivity `{ ANativeActivity * `}

	# Callbacks on the main thread
	# FIXME This would not yet be usable, to implement when Nit has threads
	#fun set_callbacks_handler(handler: App) or callbacks= ...

	# Java VM associated to `self`
	fun vm: JavaVM `{ return self->vm; `}

	# JNI environmnet associated to `self`
	fun env: JniEnv `{ return self->env; `}

	# The `NativeActivity`, as in the Java object, associated to `self`
	fun java_native_activity: NativeActivity `{ return self->clazz; `}

	# Path to this application's internal data directory.
	fun internal_data_path: CString `{ return (char*)self->internalDataPath; `}

	# Path to this application's external (removable/mountable) data directory.
	fun external_data_path: CString `{ return (char*)self->externalDataPath; `}

	# The platform's SDK version code.
	fun sdk_version: Int `{ return self->sdkVersion; `}

	# This is the native instance of the application.  It is not used by
	# the framework, but can be set by the application to its own instance
	# state.
	fun instance: Pointer `{ return self->instance; `}

	# Pointer to the Asset Manager instance for the application.  The application
	# uses this to access binary assets bundled inside its own .apk file.
	#
	# TODO activate in a future `asset_manager` module if it cannot be done in Java
	#fun asset_manager: AssetManager `{ return self->assetManager; `}

	# Available starting with Honeycomb: path to the directory containing
	# the application's OBB files (if any).  If the app doesn't have any
	# OBB files, this directory may not exist.
	# api?
	#
	# TODO activate in a future module at API 11
	#fun obb_path: CString `{ return (char*)self->obbPath; `}
end

# This is the interface for the standard glue code of a threaded
# application.  In this model, the application's code is running
# in its own thread separate from the main thread of the process.
# It is not required that this thread be associated with the Java
# VM, although it will need to be in order to make JNI calls any
# Java objects.
extern class NativeAppGlue `{ struct android_app* `}
	# We use the `userData` field of the C structure to store an handle to
	# the associated App
	private fun user_data: App `{ return self->userData; `}
	private fun user_data=(val: App) `{
		App_incr_ref(val);
		self->userData = val;
	`}

	# Fill this in with the function to process input events.  At this point
	# the event has already been pre-dispatched, and it will be finished upon
	# return.  Return 1 if you have handled the event, 0 for any default
	# dispatching.
	#int32_t (*onInputEvent)(struct android_app* app, AInputEvent* event);
	#fun set_input_event_handler(handler: App) `{  `}

	# The ANativeActivity object instance that this app is running in.
	fun ndk_native_activity: NdkNativeActivity `{ return self->activity; `}

	# The current configuration the app is running in.
	fun config: AConfiguration `{ return self->config; `}

	# This is the last instance's saved state, as provided at creation time.
	# It is NULL if there was no state.  You can use this as you need; the
	# memory will remain around until you call android_app_exec_cmd() for
	# APP_CMD_RESUME, at which point it will be freed and savedState set to NULL.
	# These variables should only be changed when processing a APP_CMD_SAVE_STATE,
	# at which point they will be initialized to NULL and you can malloc your
	# state and place the information here.  In that case the memory will be
	# freed for you later.
	fun saved_state: Pointer `{ return self->savedState; `}
	fun saved_state_size: Int `{ return self->savedStateSize; `}

	# The ALooper associated with the app's thread.
	fun looper: ALooper `{ return self->looper; `}

	# When non-NULL, this is the input queue from which the app will
	# receive user input events.
	fun input_queue: AInputQueue `{ return self->inputQueue; `}

	# When non-NULL, this is the window surface that the app can draw in.
	fun window: ANativeWindow `{ return self->window; `}

	# Current content rectangle of the window; this is the area where the
	# window's content should be placed to be seen by the user.
	#
	# TODO activate when we know what to return (returns a struct not a pointer)
	#fun content_self: ARect `{ return self->contentRect; `}

	# Current state of the app's activity.  May be either APP_CMD_START,
	# APP_CMD_RESUME, APP_CMD_PAUSE, or APP_CMD_STOP; see below.
	fun activity_state: Int `{ return self->activityState; `}

	# This is non-zero when the application's NativeActivity is being
	# destroyed and waiting for the app thread to complete.
	fun destroy_requested: Bool `{ return self->destroyRequested; `}
end

# Android NDK's struture holding configurations of the native app
extern class AConfiguration `{ AConfiguration* `}
end

# Android NDK's structure to handle events synchronously
extern class ALooper `{ ALooper* `}
	# Returns the looper associated with the calling thread, or NULL if there is not one
	new for_thread `{ return ALooper_forThread(); `}
end

# Android NDK's struture to handle input events synchronously
extern class AInputQueue `{ AInputQueue* `}
end

# Android NDK's structure to control the native window for drawing
extern class ANativeWindow `{ ANativeWindow* `}
	# Change the format and size of the window buffers
	#
	# All arguments can be set to 0 to use the default devices values.
	# `width` and `height` must both be set to 0 or have significant values.
	#
	# `format` is a value specified by EGL.
	fun set_buffers_geometry(width, height, format: Int): Bool `{
		return ANativeWindow_setBuffersGeometry(self, (int32_t)width, (int32_t)height, (int32_t)format);
	`}
end
lib/android/native_app_glue.nit:20,1--405,3