ANDROID_APP C++框架

找遍了全網,沒有一個完整的可用的框架。ndk自帶的android_native_app_glue確實不太好用,閉關幾天,寫出了一個框架。完全的消息隊列調用,目前測試的主體框架是沒有什麼問題了,程序入口還是android_main。調用過程:

void android_main(android_app* app)
{
  //APP_LOG("main : 程序啓動");
  //設置消息回調函數,就一個,整體和win32編程差不多了。
  app->onEvent = on_app_event;
 
  //循環等待事情以進行處理。
  while (app->running){//app處於運行狀態
    app->process_message();//處理消息主函數
    if(!app->pause()){
      //draw_frame();//繪製我們的遊戲,相當於MainLoop事件
    }
    else{
      //APP_LOG("PAUSE");
    }
  }
  //APP_LOG("main : 程序結束");
}

消息事件結構:

#pragma pack(push, 1)
struct APP_EVENT
{
    int id;
    union{
        void* data;
        struct{//input motion
            int16_t x, y, z, w;
        };
        struct{//input_keyboard
            int32_t key;
            int32_t flag;
        };
        struct{//ARect
            int16_t left, top, right, bottom;
        };
    };
};
#pragma pack(pop)

主消息處理函數,完全防win32編程設計,當然,事件處理做的還不夠全面。現在只是初期框架,但這個框架已經比glue那個清晰多了。

主消息回調函數: 

void on_app_event(android_app* app, APP_EVENT& event)
{
    switch(event.id)
    {
    case APP_START://activity啓動
        break;
    case APP_STOP://停止
        break;
    case APP_RESUME://返回
        break;
    case APP_PAUSE://暫停
        break;
    case APP_DESTROY://銷燬退出
        break;
    case APP_SAVE://保存狀態
        break;
    case APP_WINDOW_CREATE://窗口創建,app->window有效
        break;
    case APP_WINDOW_CLOSE://窗口銷燬
        break;
    case APP_WINDOW_ACTIVATE://窗口獲得焦點
        break;
    case APP_WINDOW_DEACTIVATE://窗口失去焦點
        break;
    case APP_WINDOW_RESIZE://窗口大小改變
        break;
 
    case APP_TOUCH_DOWN://觸摸按下
        //這三個事件,都使用event.x, event.y作爲座標
        //event.z代表pointerid
        break;
    case APP_TOUCH_MOVE://觸摸滑動
        break;
    case APP_TOUCH_UP:
        break;
 
    default:
        //APP_LOG("unknow msg:%d", cmd);
        break;
    }
}

ndk的activity入口函數其實是:

void ANativeActivity_onCreate(ANativeActivity* activity, void* savedState, size_t savedStateSize);

這個函數由主進程調用,主進程創建一個activity,通知native庫創建環境並處理,如果這個函數不返回,app就會卡死無響應。所以我們native庫的過程要在一個新的線程裏面處理。直接使用主線程的回調也不是不可以,但無法處理MainLoop這個事件,這個事件主線程沒給。如果新建一個線程,如何處理主線程回調的事件,就是一個根本的問題。glue庫用了pipe,並大把大把的mutex lock處理。下面這個庫,把lock基本都去掉了,不再使用ALooper進行消息處理。主線程和線程之間的通信還是用的pipe,因爲簡單易用。

方式很簡單:(設計執行標準)

一:所有ANativeActivity_onCreate裏面指定的回調函數,執行過程都在主線程裏面,這個我們要打包。用APP_EVENT把事件封裝,通過pipe發送到我們線程的事件隊列,主線程不對android_app內部數據進行操作。

二:android_main()過程裏面,循環執行process_message(),進行事件處理。process_message()的執行過程就是,從pipe裏面讀取打包的APP_EVENT,並進行預處理、回調執行、後續處理。

三:所有事件方法,過程儘量保證清晰,可讀性高。

目前庫封裝了部分輸入交互操作,後續會繼續封裝。也歡迎大家評論,有用的着的儘可拿去用,public domain協議!

#ifndef ANDROID_APP_HPP
#define ANDROID_APP_HPP

#include <errno.h>
#include <fcntl.h>
#include <poll.h>
#include <pthread.h>
#include <sched.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/resource.h>

#include<sys/ioctl.h>

#include <jni.h>

#include <android/configuration.h>
#include <android/looper.h>
#include <android/native_activity.h>
#include <android/log.h>

#include "pipefile.hpp"//封裝的pipe操作,之後會發表

#include <cgl/public.h>//#define null NULL
#include <cgl/thread/mutex.hpp>//封裝的鎖操作,之後發表

using namespace cgl;

#define ANDROID_APP_LOG(...) ((void)__android_log_print(ANDROID_LOG_INFO, "android_app", __VA_ARGS__))
#define ANDROID_APP_ERROR(...) ((void)__android_log_print(ANDROID_LOG_ERROR, "android_app", __VA_ARGS__))

#define ANDROID_APP_DEBUG//debug 模式

#ifdef ANDROID_APP_DEBUG
#define ANDROID_APP_LOGV(...) ((void)__android_log_print(ANDROID_LOG_VERBOSE, "android_app", __VA_ARGS__))
#else
#define ANDROID_APP_LOGV(...) ((void)0)
#endif

//android app events
enum ANDROID_APP_EVENT
{
    APP_START,
    APP_STOP,
    APP_RESUME,
    APP_PAUSE,
    APP_DESTROY,
    APP_SAVE,
    APP_CONFIG,
    APP_LOW_MEMORY,

    APP_WINDOW_CREATE,    //set app.window
    APP_WINDOW_CLOSE,    //reset app.window
    APP_WINDOW_ACTIVATE,
    APP_WINDOW_DEACTIVATE,
    APP_WINDOW_RESIZE,
    APP_WINDOW_RECT_CHANGED,
    APP_WINDOW_PAINT,

    APP_INPUT,        //set app.inputQueue
    APP_TOUCH_DOWN,
    APP_TOUCH_UP,
    APP_TOUCH_MOVE,

    APP_KEY_UP,
    APP_KEY_DOWN,
    APP_KEY_PRESS
};

#pragma pack(push, 1)
struct APP_EVENT
{
    int id;
    union{
        void* data;
        struct{//input motion
            int16_t x, y, z, w;
        };
        struct{//input_keyboard
            int32_t key;
            int32_t flag;
        };
        struct{//ARect
            int16_t left, top, right, bottom;
        };
    };
};
#pragma pack(pop)

class android_app;

extern void android_main(android_app* app);

void android_app_post_event(android_app* app, const APP_EVENT& event);
void android_app_post_event(android_app* app, int id);

class android_app
{
public:
    ANativeActivity* activity;
    AConfiguration* config;
    ALooper* looper;
    ANativeWindow* window;

    void* savedState;
    size_t savedStateSize;
    int stateSaved;

    void* userData;

    void (*onEvent)(android_app* app, APP_EVENT& event);

    int activityState;
    bool running;
public:
    pthread_t thread;
    mutex_t mutex;
    cond_t  cond;
public:
    io::pipefile message;
    AInputQueue* inputQueue;
    int destroyed;
public:
    android_app() : activity(null), config(null), looper(null), window(null),
        savedState(null), savedStateSize(0), stateSaved(0),
        userData(null),
        onEvent(null),
        activityState(0),
        thread(), mutex(), cond(),
        message(),
        inputQueue(null),
        destroyed(0)
    {
        running = false;
    }

    void dispose();

    bool pause()const
    {
        return activityState == APP_PAUSE;// || activityState == APP_STOP;
    }

    int process_message()
    {
        APP_EVENT event;
        int bytes;
        ioctl(message.in(), FIONREAD, &bytes);
        while(bytes){
            if(this->read_event(event)){
                //ANDROID_APP_LOGV("process message %d - %p", event.id, event.data);
                this->process_begin(event);
                if(this->onEvent){
                    this->onEvent(this, event);
                }
                this->process_end(event);
            }
            ioctl(message.in(), FIONREAD, &bytes);
        }
        ALooper_pollAll(0, NULL, NULL, NULL);
        //如果傳感器有數據,立即處理。ident == USER
        //ANDROID_APP_LOG("pollAll %d", ident);
        return 0;
    }

public://log
    void print_config();
public:
    void cond_wait()
    {
        cond.wait(mutex);
    }

public:
    static int on_input(int fd, int events, void* data);
    int on_input_event(AInputEvent* event);
private:
    bool read_event(APP_EVENT& event);
    void process_begin(APP_EVENT& event);
    void process_end(APP_EVENT& event);

    int on_input_motion(AInputEvent* event);
    int on_input_keyboard(AInputEvent* event);
};

void free_saved_state(android_app* app)
{
    //auto_lock lock(app->mutex);
    if (app->savedState != NULL) {
        free(app->savedState);
        app->savedState = NULL;
        app->savedStateSize = 0;
    }
}

void android_app::print_config()
{
    char lang[2], country[2];
    AConfiguration_getLanguage(config, lang);
    AConfiguration_getCountry(config, country);

    ANDROID_APP_LOGV("Config: mcc=%d mnc=%d lang=%c%c cnt=%c%c orien=%d touch=%d dens=%d "
            "keys=%d nav=%d keysHid=%d navHid=%d sdk=%d size=%d long=%d "
            "modetype=%d modenight=%d",
            AConfiguration_getMcc(config),
            AConfiguration_getMnc(config),
            lang[0], lang[1], country[0], country[1],
            AConfiguration_getOrientation(config),
            AConfiguration_getTouchscreen(config),
            AConfiguration_getDensity(config),
            AConfiguration_getKeyboard(config),
            AConfiguration_getNavigation(config),
            AConfiguration_getKeysHidden(config),
            AConfiguration_getNavHidden(config),
            AConfiguration_getSdkVersion(config),
            AConfiguration_getScreenSize(config),
            AConfiguration_getScreenLong(config),
            AConfiguration_getUiModeType(config),
            AConfiguration_getUiModeNight(config));
}

#ifdef ANDROID_APP_DEBUG
const char* input_motion_name(int action)
{
    switch(action){
    case AMOTION_EVENT_ACTION_DOWN://觸摸按下
        return "MOTION_DOWN";
    case AMOTION_EVENT_ACTION_UP://觸摸彈起
        return "MOTION_UP";
    case AMOTION_EVENT_ACTION_MOVE://觸摸移動
        return "MOTION_MOVE";
    case AMOTION_EVENT_ACTION_CANCEL:
        return "MOTION_CACEL";
    case AMOTION_EVENT_ACTION_OUTSIDE:
        return "MOTION_OUTSIDE";
    default:
        break;
    }
    return null;
}
#endif

int android_app::on_input_motion(AInputEvent* inputEvent)
{
    APP_EVENT event;

    //motion source
    switch(AInputEvent_getSource(inputEvent))
    {
    case AINPUT_SOURCE_TOUCHSCREEN:
        //消息來源於觸摸屏
        break;
    case AINPUT_SOURCE_TRACKBALL:
        //消息來源於trackball,軌跡球 or 鼠標?
        break;
    default:
        break;
    }

    switch(AMotionEvent_getAction(inputEvent))
    {
    case AMOTION_EVENT_ACTION_DOWN://觸摸按下
        event.id = APP_TOUCH_DOWN;
        break;
    case AMOTION_EVENT_ACTION_UP://觸摸彈起
        event.id = APP_TOUCH_UP;
        break;
    case AMOTION_EVENT_ACTION_MOVE://觸摸移動
        event.id = APP_TOUCH_MOVE;
        break;
    case AMOTION_EVENT_ACTION_CANCEL:
        break;
    case AMOTION_EVENT_ACTION_OUTSIDE:
        break;
    default:
        break;
    }

    //getX()    是表示view相對於自身左上角的x座標,
    //getRawX()    是表示相對於物理屏幕左上角的x座標值
    //AMotionEvent_getXPrecision

    size_t count = AMotionEvent_getPointerCount(inputEvent);
    for(int i=0; i < count; ++i){
        event.x = AMotionEvent_getX(inputEvent, i);
        event.y = AMotionEvent_getY(inputEvent, i);
        event.z = i;

        if(this->onEvent){
            this->onEvent(this, event);
        }

        #ifdef ANDROID_APP_DEBUG
        ANDROID_APP_LOGV("%s : index=%d, pointer=%d, flag=%d state=%d x=%d, y=%d\n", 
            input_motion_name(AMotionEvent_getAction(inputEvent)),
            i,
            AMotionEvent_getPointerId(inputEvent, i),
            AMotionEvent_getFlags(inputEvent), 
            AMotionEvent_getMetaState(inputEvent),
            event.x, event.y);
        #endif
    }
    return this->onEvent ? 1 : 0;
}

int android_app::on_input_keyboard(AInputEvent* inputEvent)
{
    //鍵盤控制鍵管用,字符鍵不管用
    ANDROID_APP_LOGV("keyinput : action=%d flag=%d keycode=%d",
        AKeyEvent_getAction(inputEvent),
        AKeyEvent_getFlags(inputEvent),
        AKeyEvent_getKeyCode(inputEvent));

    APP_EVENT event;
    switch(AKeyEvent_getAction(inputEvent)){
    case AKEY_STATE_UNKNOWN:
        break;
    case AKEY_STATE_UP:
        event.id = APP_KEY_UP;
        break;
    case AKEY_STATE_DOWN:
        event.id = APP_KEY_DOWN;
        break;
    case AKEY_STATE_VIRTUAL:
        event.id = APP_KEY_PRESS;
        break;
    default:
        break;
    }

    event.key = AKeyEvent_getKeyCode(inputEvent);
    event.flag = AKeyEvent_getFlags(inputEvent);
    if(this->onEvent){//if processed, reutrn 1
        this->onEvent(this, event);
        return 1;
    }

    return 0;
}

// input event callback
int android_app::on_input_event(AInputEvent* inputEvent)
{
    if(AInputEvent_getType(inputEvent) == AINPUT_EVENT_TYPE_MOTION){
        return this->on_input_motion(inputEvent);
    }
    else if(AInputEvent_getType(inputEvent) == AINPUT_EVENT_TYPE_KEY){
        return this->on_input_keyboard(inputEvent);        
    }
    return 0;
}

// inputQueue callback
int android_app::on_input(int fd, int events, void* data)
{
    ANDROID_APP_LOGV("on_input %p", data);
    android_app* app = (android_app*)data;
    AInputEvent* event = NULL;
    while (AInputQueue_getEvent(app->inputQueue, &event) >= 0) {
        //ANDROID_APP_LOGV("New input event: type=%d\n", AInputEvent_getType(event));
        if (AInputQueue_preDispatchEvent(app->inputQueue, event)) {
            continue;
        }
        AInputQueue_finishEvent(app->inputQueue, event, app->on_input_event(event));
    }
    return 1;
}

//讀取事件
bool android_app::read_event(APP_EVENT& event)
{
    return message.read(&event, sizeof(event)) == sizeof(event);
}

#ifdef ANDROID_APP_DEBUG
const char* app_event_name(int id)
{
    switch (id)
    {
        case APP_START:                return "APP_START";
        case APP_STOP:                return "APP_STOP";
        case APP_RESUME:            return "APP_RESUME";
        case APP_PAUSE:                return "APP_PAUSE";
        case APP_DESTROY:            return "APP_DESTROY";
        case APP_SAVE:                return "APP_SAVE";
        case APP_CONFIG:            return "APP_CONFIG";
        case APP_WINDOW_CREATE:        return "APP_WINDOW_CREATE";
        case APP_WINDOW_CLOSE:        return "APP_WINDOW_CLOSE";
        case APP_WINDOW_ACTIVATE:    return "APP_WINDOW_ACTIVATE";
        case APP_WINDOW_DEACTIVATE: return "APP_WINDOW_DEACTIVATE";
        case APP_WINDOW_RESIZE:        return "APP_WINDOW_RESIZE";
        case APP_INPUT:                return "APP_INPUT";
        default:
            break;
    }
    return null;
}
#endif

//預處理事件
void android_app::process_begin(APP_EVENT& event)
{
    switch (event.id){
    case APP_START:
    case APP_STOP:
    case APP_RESUME:
    case APP_PAUSE:
        ANDROID_APP_LOGV("APP_STATE = %s\n", app_event_name(event.id));
        this->activityState = event.id;
        break;
    case APP_DESTROY:
        ANDROID_APP_LOGV("APP_DESTROY\n");
        this->running = false;
        break;
    case APP_SAVE:
        //free_saved_state(this);
        break;
    case APP_CONFIG:
        ANDROID_APP_LOGV("APP_CONFIG\n");
        AConfiguration_fromAssetManager(this->config, this->activity->assetManager);
        this->print_config();
        break;

    case APP_WINDOW_CREATE:
        ANDROID_APP_LOGV("APP_WINDOW_CREATE : %p\n", event.data);
        this->window = (ANativeWindow*)event.data;
        break;
    case APP_INPUT:{
        ANDROID_APP_LOGV("APP_INPUT : %p\n", event.data);
        if(this->inputQueue){
            AInputQueue_detachLooper(this->inputQueue);
        }
        this->inputQueue = (AInputQueue*)event.data;
        if(this->inputQueue){
            AInputQueue_attachLooper(this->inputQueue, this->looper, 0, android_app::on_input, this);
        }
        break;
    }
    default:
        ANDROID_APP_LOGV("APP_EVENT : %s", app_event_name(event.id));
        break;
    }
}

//後續處理事件
void android_app::process_end(APP_EVENT& event)
{
    switch (event.id) {
    case APP_WINDOW_CLOSE:
        ANDROID_APP_LOGV("APP_WINDOW_CLOSE\n");
        this->window = NULL;
        break;
    case APP_SAVE:
        ANDROID_APP_LOGV("APP_SAVE\n");
        this->stateSaved = 1;
        break;
    case APP_RESUME:
        //free_saved_state(this);
        break;
    default:
        break;
    }
}

void android_app::dispose()
{
    ANDROID_APP_LOGV("android_app::dispose!");
    free_saved_state(this);
    //auto_lock lock(app->mutex);
    if(this->inputQueue){
        AInputQueue_detachLooper(this->inputQueue);
    }
    AConfiguration_delete(this->config);
    this->destroyed = 1;
    this->cond.broadcast();
    // Can't touch android_app object after this.
}

// app main thread
void* android_app_main(void* param)
{
    android_app* app = (android_app*)param;

    app->config = AConfiguration_new();
    AConfiguration_fromAssetManager(app->config, app->activity->assetManager);
    app->print_config();

    app->looper = ALooper_prepare(0);
    app->running = true;

    android_main(app);    //android_main

    app->dispose();

    return NULL;
}

// --------------------------------------------------------------------
//
// Native activity interaction (主線程調用的函數)
//
// --------------------------------------------------------------------

android_app* android_app_create(ANativeActivity* activity, void* savedState, size_t savedStateSize)
{
    android_app* app = new android_app;
    app->activity = activity;

    if (savedState != NULL) {
        /*
        app->savedState = malloc(savedStateSize);
        app->savedStateSize = savedStateSize;
        memcpy(app->savedState, savedState, savedStateSize);
        */
    }

    if(app->message.create()){
        ANDROID_APP_ERROR("could not create pipe: %s", strerror(errno));
        return NULL;
    }

    //int flag = fcntl(app->message.in(), F_GETFL, 0 );
    //fcntl(app->message.in(), F_SETFL, flag | O_NONBLOCK);

    pthread_attr_t attr;
    pthread_attr_init(&attr);
    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
    pthread_create(&app->thread, &attr, android_app_main, app);

    return app;
}

void android_app_post_event(android_app* app, const APP_EVENT& event)
{
    //ANDROID_APP_LOGV("write event %d", event.id);
    if(app->message.write(&event, sizeof(event)) != sizeof(event)) {
        ANDROID_APP_ERROR("Failure writing android_app event: %s\n", strerror(errno));
    }
}

void android_app_post_event(android_app* app, int id)
{
    APP_EVENT event = {id};
    android_app_post_event(app, event);
}

//
// 主線程回調函數
//

//
// app
//

void onStart(ANativeActivity* activity)
{
    ANDROID_APP_LOGV("Activity Start: %p\n", activity);
    android_app_post_event((android_app*)activity->instance, APP_START);
}

void onStop(ANativeActivity* activity)
{
    ANDROID_APP_LOGV("Activity Stop: %p\n", activity);
    android_app_post_event((android_app*)activity->instance, APP_STOP);
}

void onResume(ANativeActivity* activity)
{
    ANDROID_APP_LOGV("Activity Resume: %p\n", activity);
    android_app_post_event((android_app*)activity->instance, APP_RESUME);
}

void onPause(ANativeActivity* activity)
{
    ANDROID_APP_LOGV("Activity Pause: %p\n", activity);
    android_app_post_event((android_app*)activity->instance, APP_PAUSE);
}

void onDestroy(ANativeActivity* activity)
{
    ANDROID_APP_LOGV("Activity Destroy: %p\n", activity);
    android_app* app = (android_app*)activity->instance;
    //auto_lock lock(app->mutex);
    android_app_post_event(app, APP_DESTROY);
    while (!app->destroyed) {
        //app->cond_wait();
    }

    app->message.close();
    delete app;
}

void* onSaveInstanceState(ANativeActivity* activity, size_t* outLen)
{
    android_app* app = (android_app*)activity->instance;
    void* savedState = NULL;

    ANDROID_APP_LOGV("Activity SaveInstanceState: %p\n", activity);
    /*
    auto_lock lock(app->mutex);
    app->stateSaved = 0;
    android_app_post_event(app, APP_SAVE);
    while (!app->stateSaved) {
        app->cond_wait();
    }

    if (app->savedState != NULL) {
        savedState = app->savedState;
        *outLen = app->savedStateSize;
        app->savedState = NULL;
        app->savedStateSize = 0;
    }
    */
    return savedState;
}

void onConfigurationChanged(ANativeActivity* activity) {
    ANDROID_APP_LOGV("Activity ConfigurationChanged: %p\n", activity);
    android_app_post_event((android_app*)activity->instance, APP_CONFIG);
}

void onLowMemory(ANativeActivity* activity)
{
    ANDROID_APP_LOGV("Activity LowMemory: %p\n", activity);
    android_app_post_event((android_app*)activity->instance, APP_LOW_MEMORY);
}

//
// window
//

void onNativeWindowCreated(ANativeActivity* activity, ANativeWindow* window)
{
    ANDROID_APP_LOGV("NativeWindowCreated: %p -- %p\n", activity, window);
    APP_EVENT event;
    event.id = APP_WINDOW_CREATE;
    event.data = window;
    android_app_post_event((android_app*)activity->instance, event);
}

void onNativeWindowDestroyed(ANativeActivity* activity, ANativeWindow* window)
{
    ANDROID_APP_LOGV("NativeWindowDestroyed: %p -- %p\n", activity, window);
    android_app_post_event((android_app*)activity->instance, APP_WINDOW_CLOSE);
}

void onWindowFocusChanged(ANativeActivity* activity, int focused)
{
    ANDROID_APP_LOGV("WindowFocusChanged: %p -- %d\n", activity, focused);
    android_app_post_event((android_app*)activity->instance, focused ? APP_WINDOW_ACTIVATE : APP_WINDOW_DEACTIVATE);
}

void onNativeWindowResized(ANativeActivity* activity, ANativeWindow* window)
{
    ANDROID_APP_LOGV("NativeWindowResized: %p -- %p\n", activity, window);
    android_app_post_event((android_app*)activity->instance, APP_WINDOW_RESIZE);
}

void onContentRectChanged(ANativeActivity* activity, const ARect* rect)
{
    ANDROID_APP_LOGV("ContentRectChanged: [%d, %d - %d, %d]\n", rect->left, rect->top, rect->right, rect->bottom);
    /*
    APP_EVENT event;
    event.id     = APP_WINDOW_RECT_CHANGED;
    event.left   = rect->left;
    event.top    = rect->top;
    event.right  = rect->right;
    event.bottom = rect->bottom;
    android_app_post_event((android_app*)activity->instance, event);
    */
}

void onNativeWindowRedrawNeeded(ANativeActivity* activity, ANativeWindow* window)
{
    ANDROID_APP_LOGV("NativeWindowRedrawNeeded: %p -- %p\n", activity, window);
    android_app_post_event((android_app*)activity->instance, APP_WINDOW_PAINT);
}

//
// input
//

void android_app_set_input(android_app* app, AInputQueue* inputQueue)
{
    APP_EVENT event;
    event.id = APP_INPUT;
    event.data = inputQueue;
    android_app_post_event(app, event);
}

void onInputQueueCreated(ANativeActivity* activity, AInputQueue* queue)
{
    ANDROID_APP_LOGV("InputQueueCreated: %p -- %p\n", activity, queue);
    android_app_set_input((android_app*)activity->instance, queue);
}

void onInputQueueDestroyed(ANativeActivity* activity, AInputQueue* queue)
{
    ANDROID_APP_LOGV("InputQueueDestroyed: %p -- %p\n", activity, queue);
    android_app_set_input((android_app*)activity->instance, NULL);
}

//
// native activity entry
//

JNIEXPORT
void ANativeActivity_onCreate(ANativeActivity* activity, void* savedState, size_t savedStateSize)
{
    ANDROID_APP_LOGV("NativeActivity create: %p\n", activity);

    //app
    activity->callbacks->onStart   = onStart;
    activity->callbacks->onStop    = onStop;
    activity->callbacks->onResume  = onResume;
    activity->callbacks->onPause   = onPause;
    activity->callbacks->onDestroy = onDestroy;
    activity->callbacks->onSaveInstanceState    = onSaveInstanceState;
    activity->callbacks->onConfigurationChanged = onConfigurationChanged;
    activity->callbacks->onLowMemory = onLowMemory;

    //window
    activity->callbacks->onNativeWindowCreated      = onNativeWindowCreated;
    activity->callbacks->onNativeWindowDestroyed    = onNativeWindowDestroyed;
    activity->callbacks->onWindowFocusChanged       = onWindowFocusChanged;
    activity->callbacks->onNativeWindowResized      = onNativeWindowResized;
    activity->callbacks->onContentRectChanged       = onContentRectChanged;
    activity->callbacks->onNativeWindowRedrawNeeded = onNativeWindowRedrawNeeded;

    //input
    activity->callbacks->onInputQueueCreated   = onInputQueueCreated;
    activity->callbacks->onInputQueueDestroyed = onInputQueueDestroyed;

    //create android app
    activity->instance = android_app_create(activity, savedState, savedStateSize);

    //ANDROID_APP_LOGV("NativeActivity create successed.");
}

#endif /* ANDROID_APP_HPP  */

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章