// // Android Native Application interface // for the Fast Light Tool Kit (FLTK). // // Copyright 2018 by Bill Spitzak and others. // // This library is free software. Distribution and use rights are outlined in // the file "COPYING" which should have been included with this file. If this // file is missing or damaged, see the license at: // // https://www.fltk.org/COPYING.php // // Please see the following page on how to report bugs and issues: // // https://www.fltk.org/bugs.php // /** \file Fl_Android_Application.H \brief Definition of Android Native Application interface */ #ifndef FL_ANDROID_APPLICATION_H #define FL_ANDROID_APPLICATION_H #include extern void (*fl_unlock_function)(); extern void (*fl_lock_function)(); #include #include #include #include #include #include /** A class to make Java calls from C++ easier. */ class Fl_Android_Java { JavaVM *pJavaVM = nullptr; JNIEnv *pJNIEnv = nullptr; jobject pNativeActivity; jclass pNativeActivityClass; bool pAttached = false; public: Fl_Android_Java(); ~Fl_Android_Java(); bool is_attached() { return pAttached; } JavaVM *VM() { return pJavaVM; } JNIEnv *env() { return pJNIEnv; } jobject native_ativity() { return pNativeActivity; } jclass native_activity_class() { return pNativeActivityClass; } }; /** Static class that manages all interaction between the Android Native Activity and the FLTK library. It also keeps often used data for global access. On launch, it creates a main thread and communication pipe to the Activity. All FLTK code will run in that thread. Activity events will be polled by the Screen driver using the provided Android Looper, and will also be routed back to this class as needed. This code is based on the native activity interface provided by . It is based on a set of application-provided callbacks that will be called by the Activity's main thread when certain events occur. 1/ The application must provide a function named "int main(argc, argv)" that will be called when the activity is created, in a new thread that is distinct from the activity's main thread. 2/ The application has access to a static "Fl_Android_Application" class that contains references to other important objects, e.g. the ANativeActivity object instance the application is running in. 3/ the "Fl_Android_Application" class holds an ALooper instance that already listens to two important things: - activity lifecycle events (e.g. "pause", "resume"). See APP_CMD_XXX declarations below. - input events coming from the AInputQueue attached to the activity. Each of these correspond to an ALooper identifier returned by ALooper_pollOnce with values of LOOPER_ID_MAIN and LOOPER_ID_INPUT, respectively. FLTK will add more items to the looper for timers and file and socket communication. (fl_add_timeout, Fl::add_fd(), ... */ class Fl_Android_Application { public: enum { /** * Looper data ID of commands coming from the app's main thread, which * is returned as an identifier from ALooper_pollOnce(). The data for this * identifier is a pointer to an android_poll_source structure. * These can be retrieved and processed with android_app_read_cmd() * and android_app_exec_cmd(). */ LOOPER_ID_MAIN = 1, /** * Looper data ID of events coming from the AInputQueue of the * application's window, which is returned as an identifier from * ALooper_pollOnce(). The data for this identifier is a pointer to an * android_poll_source structure. These can be read via the inputQueue * object of android_app. */ LOOPER_ID_INPUT, /** * Timer data ID of all timer events coming from the Unix timer_create() * and friends, used in fl_add_timeout() and colleagues. */ LOOPER_ID_TIMER, /** * Start of user-defined ALooper identifiers. */ LOOPER_ID_USER, }; /** * @see android.H Fl_Android_Platform_Event */ enum { APP_CMD_INPUT_CHANGED, APP_CMD_INIT_WINDOW, APP_CMD_TERM_WINDOW, APP_CMD_WINDOW_RESIZED, APP_CMD_WINDOW_REDRAW_NEEDED, APP_CMD_CONTENT_RECT_CHANGED, APP_CMD_GAINED_FOCUS, APP_CMD_LOST_FOCUS, APP_CMD_CONFIG_CHANGED, APP_CMD_LOW_MEMORY, APP_CMD_START, APP_CMD_RESUME, APP_CMD_SAVE_STATE, APP_CMD_PAUSE, APP_CMD_STOP, APP_CMD_DESTROY, }; public: // --- logging static void log_e(const char *text, ...); static void log_w(const char *text, ...); static void log_i(const char *text, ...); static void log_v(const char *text, ...); // --- application state stuff static int8_t read_cmd(); static void pre_exec_cmd(int8_t cmd); static void post_exec_cmd(int8_t cmd); static int destroy_requested() { return pDestroyRequested; } static const char *get_internal_data_path() { return pActivity->internalDataPath; } static const char *get_external_data_path() { return pActivity->externalDataPath; } static AAssetManager *get_asset_manager() { return pActivity->assetManager; } static ANativeActivity *get_activity() { return pActivity; } // --- event handling static AInputQueue *input_event_queue() { return pInputQueue; } // --- screen stuff static bool copy_screen(); static inline ANativeWindow *native_window() { return pNativeWindow; } static inline ANativeWindow_Buffer &graphics_buffer() { return pApplicationWindowBuffer; } // --- timer stuff static void send_timer_index(uint8_t ix); static uint8_t receive_timer_index(); protected: static void free_saved_state(); static void print_cur_config(); static void destroy(); static void* thread_entry(void* param); // --- screen handling stuff static void allocate_screen(); static bool lock_screen(); static void unlock_and_post_screen(); static bool screen_is_locked(); // --- timer stuff static void create_timer_handler(); static void destroy_timer_handler(); static ANativeActivity *pActivity; static AConfiguration *pConfig; static void *pSavedState; static size_t pSavedStateSize; static ALooper *pAppLooper; static AInputQueue *pInputQueue; static ANativeWindow *pNativeWindow; static ANativeWindow_Buffer pNativeWindowBuffer; static ANativeWindow_Buffer pApplicationWindowBuffer; static int pActivityState; static int pDestroyRequested; // ---- no need to make these visible to the outside ---- static pthread_mutex_t pMutex; static pthread_cond_t pCond; static int pMsgReadPipe; static int pMsgWritePipe; static pthread_t pThread; static int pRunning; static int pStateSaved; static int pDestroyed; static AInputQueue* pPendingInputQueue; static ANativeWindow* pPendingWindow; // --- timer variables static int pTimerReadPipe; static int pTimerWritePipe; }; class Fl_Android_Activity : public Fl_Android_Application { public: static void create(ANativeActivity* activity, void* savedState, size_t savedStateSize); private: static void set_activity(ANativeActivity *a) { pActivity = a; } static void set_callbacks(); // ---- Android Native Activity interface static void write_cmd(int8_t cmd); static void set_input(AInputQueue* inputQueue); static void set_window(ANativeWindow* window); static void set_activity_state(int8_t cmd); static void close_activity(); // ---- Android Native Activity callbacks ---- static void onContentRectChanged(ANativeActivity *activity, const ARect *rect); static void onNativeWindowRedrawNeeded(ANativeActivity *activity, ANativeWindow *window); static void onNativeWindowResized(ANativeActivity *activity, ANativeWindow *window); static void onDestroy(ANativeActivity* activity); static void onStart(ANativeActivity* activity); static void onResume(ANativeActivity* activity); static void* onSaveInstanceState(ANativeActivity* activity, size_t* outLen); static void onPause(ANativeActivity* activity); static void onStop(ANativeActivity* activity); static void onConfigurationChanged(ANativeActivity* activity); static void onLowMemory(ANativeActivity* activity); static void onWindowFocusChanged(ANativeActivity* activity, int focused); static void onNativeWindowCreated(ANativeActivity* activity, ANativeWindow* window); static void onNativeWindowDestroyed(ANativeActivity* activity, ANativeWindow* window); static void onInputQueueCreated(ANativeActivity* activity, AInputQueue* queue); static void onInputQueueDestroyed(ANativeActivity* activity, AInputQueue* queue); }; #endif // FL_ANDROID_APPLICATION_H