void message_dispatcher::reset_queue_locked()
	{
		if (m_iqueue) {
			AInputQueue_detachLooper(m_iqueue);
			LOGI("%s:%d> detaching looper from queue %p\n", __FILE__, __LINE__, m_iqueue);
		}
	}
示例#2
0
static void cui_onInputQueueCreated(ANativeActivity* activity, AInputQueue* queue)
{
	CUI_DEBUG("cui_onInputQueueCreated\n");

	if ((activity == NULL) || (queue == NULL))
	{
		CUI_DEBUG("InputQueueCreated param error\n");
		return;
	}

	struct cui_app * this_app = NULL;
	this_app = (struct cui_app *)activity->instance;

	pthread_mutex_lock(&this_app->mutex_lock);
	if(this_app == NULL)
	{
		CUI_DEBUG("this app is not init\n");
		return;
	}

	if (this_app->input_queue != NULL)
	{
		AInputQueue_detachLooper(this_app->input_queue);
	}
	this_app->input_queue = queue;

	if (this_app->input_queue != NULL) {
		CUI_DEBUG("Attaching input queue to looper");
		AInputQueue_attachLooper(this_app->input_queue,
				this_app->looper, 1, looper_callback, this_app);
	}
	pthread_mutex_unlock(&this_app->mutex_lock);

}
示例#3
0
void *cxAndroid::AndroidEntry(void *data)
{
    cxAndroid *app = (cxAndroid *)data;
    AConfiguration_fromAssetManager(app->config, app->activity->assetManager);
    
    app->cmd.id = LOOPER_ID_MAIN;
    app->cmd.app = app;
    app->cmd.process = cxAndroid::cxAndroidExec;
    
    app->input.id = LOOPER_ID_INPUT;
    app->input.app = app;
    app->input.process = cxAndroid::cxAndroidInputExec;
    
    app->looper = ALooper_prepare(ALOOPER_PREPARE_ALLOW_NON_CALLBACKS);
    ALooper_addFd(app->looper, app->msgread, LOOPER_ID_MAIN, ALOOPER_EVENT_INPUT, NULL,&app->cmd);
    
    pthread_mutex_lock(&app->mutex);
    app->running = true;
    pthread_cond_broadcast(&app->cond);
    pthread_mutex_unlock(&app->mutex);
    
    app->cxAndroidMain();
    
    pthread_mutex_lock(&app->mutex);
    if (app->inputQueue != NULL) {
        AInputQueue_detachLooper(app->inputQueue);
        app->inputQueue = NULL;
    }
    AConfiguration_delete(app->config);
    app->config = NULL;
    app->destroyed = true;
    pthread_cond_broadcast(&app->cond);
    pthread_mutex_unlock(&app->mutex);
    return data;
}
void android_app_pre_exec_cmd(struct android_app* android_app, int8_t cmd) {
    switch (cmd) {
        case APP_CMD_INPUT_CHANGED:
            LOGV("APP_CMD_INPUT_CHANGED\n");
            pthread_mutex_lock(&android_app->mutex);
            if (android_app->inputQueue != NULL) {
                AInputQueue_detachLooper(android_app->inputQueue);
            }
            android_app->inputQueue = android_app->pendingInputQueue;
            if (android_app->inputQueue != NULL) {
                LOGV("Attaching input queue to looper");
                AInputQueue_attachLooper(android_app->inputQueue,
                        android_app->looper, LOOPER_ID_INPUT, NULL,
                        &android_app->inputPollSource);
            }
            pthread_cond_broadcast(&android_app->cond);
            pthread_mutex_unlock(&android_app->mutex);
            break;

        case APP_CMD_INIT_WINDOW:
            LOGV("APP_CMD_INIT_WINDOW\n");
            pthread_mutex_lock(&android_app->mutex);
            android_app->window = android_app->pendingWindow;
            pthread_cond_broadcast(&android_app->cond);
            pthread_mutex_unlock(&android_app->mutex);
            break;

        case APP_CMD_TERM_WINDOW:
            LOGV("APP_CMD_TERM_WINDOW\n");
            pthread_cond_broadcast(&android_app->cond);
            break;

        case APP_CMD_RESUME:
        case APP_CMD_START:
        case APP_CMD_PAUSE:
        case APP_CMD_STOP:
            LOGV("activityState=%d\n", cmd);
            pthread_mutex_lock(&android_app->mutex);
            android_app->activityState = cmd;
            pthread_cond_broadcast(&android_app->cond);
            pthread_mutex_unlock(&android_app->mutex);
            break;

        case APP_CMD_CONFIG_CHANGED:
            LOGV("APP_CMD_CONFIG_CHANGED\n");
            AConfiguration_fromAssetManager(android_app->config,
                    android_app->activity->assetManager);
            print_cur_config(android_app);
            break;

        case APP_CMD_DESTROY:
            LOGV("APP_CMD_DESTROY\n");
            android_app->destroyRequested = 1;
            break;
    }
}
static void android_app_destroy(struct android_app* android_app) {
    free_saved_state(android_app);
    pthread_mutex_lock(&android_app->mutex);
    if (android_app->inputQueue != NULL) {
        AInputQueue_detachLooper(android_app->inputQueue);
    }
    AConfiguration_delete(android_app->config);
    android_app->destroyed = 1;
    pthread_cond_broadcast(&android_app->cond);
    pthread_mutex_unlock(&android_app->mutex);
    // Can't touch android_app object after this.
}
示例#6
0
static void onInputQueueDestroyed(ANativeActivity* activity, AInputQueue* queue)
{
    // Retrieve our activity states from the activity instance
    sf::priv::ActivityStates* states = sf::priv::retrieveStates(activity);

    // Detach the input queue
    {
        sf::Lock lock(states->mutex);

        states->inputQueue = NULL;
        AInputQueue_detachLooper(queue);
    }
}
static void android_app_destroy ( struct android_app* android_app ) {
	LOGV ( "android_app_destroy!" );
	free_saved_state ( android_app );
	pthread_mutex_lock ( &android_app->mutex );
	if ( android_app->inputQueue != NULL ) {
		AInputQueue_detachLooper ( android_app->inputQueue );
	}
	AConfiguration_delete ( android_app->config );
	android_app->destroyed = 1;
	pthread_cond_broadcast ( &android_app->cond );
	pthread_mutex_unlock ( &android_app->mutex );
	// 이후에 android_app 개체를 터치할 수 없습니다.
}
示例#8
0
static void frontend_android_deinit(void *data)
{
   struct android_app* android_app = (struct android_app*)data;

   if (!android_app)
      return;

   RARCH_LOG("Deinitializing RetroArch ...\n");
   android_app->activityState = APP_CMD_DEAD;

   if (android_app->inputQueue)
   {
      RARCH_LOG("Detaching Android input queue looper ...\n");
      AInputQueue_detachLooper(android_app->inputQueue);
   }
}
示例#9
0
void cxAndroid::cxAndroidPreExec(cxAndroid *app, int8_t cmd)
{
    switch (cmd) {
        case APP_CMD_INPUT_CHANGED:{
            pthread_mutex_lock(&app->mutex);
            if (app->inputQueue != NULL) {
                AInputQueue_detachLooper(app->inputQueue);
            }
            app->inputQueue = app->pendingInputQueue;
            if (app->inputQueue != NULL) {
                AInputQueue_attachLooper(app->inputQueue,app->looper, LOOPER_ID_INPUT, NULL,&app->input);
            }
            pthread_cond_broadcast(&app->cond);
            pthread_mutex_unlock(&app->mutex);
            break;
        }
        case APP_CMD_INIT_WINDOW:{
            pthread_mutex_lock(&app->mutex);
            app->window = app->pendingWindow;
            pthread_cond_broadcast(&app->cond);
            pthread_mutex_unlock(&app->mutex);
            break;
        }
        case APP_CMD_TERM_WINDOW:{
            pthread_cond_broadcast(&app->cond);
            break;
        }
        case APP_CMD_RESUME:
        case APP_CMD_START:
        case APP_CMD_PAUSE:
        case APP_CMD_STOP:{
            pthread_mutex_lock(&app->mutex);
            app->activityState = cmd;
            pthread_cond_broadcast(&app->cond);
            pthread_mutex_unlock(&app->mutex);
            break;
        }
        case APP_CMD_CONFIG_CHANGED:{
            AConfiguration_fromAssetManager(app->config,app->activity->assetManager);
            break;
        }
        case APP_CMD_DESTROY:{
            app->destroyReq = true;
            break;
        }
    }
}
示例#10
0
static void frontend_android_deinit(void *data)
{
   struct android_app *android_app = (struct android_app*)data;

   if (!android_app)
      return;

   RARCH_LOG("Deinitializing RetroArch ...\n");
   android_app->activityState = APP_CMD_DEAD;

   JNIEnv *env = jni_thread_getenv();
   if (env && android_app->onRetroArchExit)
      CALL_VOID_METHOD(env, android_app->activity->clazz, android_app->onRetroArchExit);

   if (android_app->inputQueue)
   {
      RARCH_LOG("Detaching Android input queue looper ...\n");
      AInputQueue_detachLooper(android_app->inputQueue);
   }
}
示例#11
0
void engine_handle_cmd(void *data)
{
   struct android_app *android_app = (struct android_app*)g_android;
   int8_t cmd;

   if (read(android_app->msgread, &cmd, sizeof(cmd)) != sizeof(cmd))
      cmd = -1;

   switch (cmd)
   {
      case APP_CMD_INPUT_CHANGED:
         slock_lock(android_app->mutex);

         if (android_app->inputQueue)
            AInputQueue_detachLooper(android_app->inputQueue);

         android_app->inputQueue = android_app->pendingInputQueue;

         if (android_app->inputQueue)
         {
            RARCH_LOG("Attaching input queue to looper");
            AInputQueue_attachLooper(android_app->inputQueue,
                  android_app->looper, LOOPER_ID_INPUT, NULL,
                  NULL);
         }

         scond_broadcast(android_app->cond);
         slock_unlock(android_app->mutex);
         
         break;

      case APP_CMD_INIT_WINDOW:
         slock_lock(android_app->mutex);
         android_app->window = android_app->pendingWindow;
         scond_broadcast(android_app->cond);
         slock_unlock(android_app->mutex);

         if (g_extern.is_paused)
            rarch_reinit_drivers();
         break;

      case APP_CMD_RESUME:
         slock_lock(android_app->mutex);
         android_app->activityState = cmd;
         scond_broadcast(android_app->cond);
         slock_unlock(android_app->mutex);
         break;

      case APP_CMD_START:
         slock_lock(android_app->mutex);
         android_app->activityState = cmd;
         scond_broadcast(android_app->cond);
         slock_unlock(android_app->mutex);
         break;

      case APP_CMD_PAUSE:
         slock_lock(android_app->mutex);
         android_app->activityState = cmd;
         scond_broadcast(android_app->cond);
         slock_unlock(android_app->mutex);

         if (!g_extern.system.shutdown)
         {
            RARCH_LOG("Pausing RetroArch.\n");
            g_extern.is_paused = true;
         }
         break;

      case APP_CMD_STOP:
         slock_lock(android_app->mutex);
         android_app->activityState = cmd;
         scond_broadcast(android_app->cond);
         slock_unlock(android_app->mutex);
         break;

      case APP_CMD_CONFIG_CHANGED:
         break;
      case APP_CMD_TERM_WINDOW:
         slock_lock(android_app->mutex);

         /* The window is being hidden or closed, clean it up. */
         /* terminate display/EGL context here */
         //RARCH_WARN("Window is terminated outside PAUSED state.\n");

         android_app->window = NULL;
         scond_broadcast(android_app->cond);
         slock_unlock(android_app->mutex);
         break;

      case APP_CMD_GAINED_FOCUS:
         g_extern.is_paused = false;

         if ((android_app->sensor_state_mask & (1ULL << RETRO_SENSOR_ACCELEROMETER_ENABLE))
               && android_app->accelerometerSensor == NULL && driver.input_data)
            android_input_set_sensor_state(driver.input_data, 0, RETRO_SENSOR_ACCELEROMETER_ENABLE,
                  android_app->accelerometer_event_rate);
         break;
      case APP_CMD_LOST_FOCUS:
         // Avoid draining battery while app is not being used
         if ((android_app->sensor_state_mask & (1ULL << RETRO_SENSOR_ACCELEROMETER_ENABLE))
               && android_app->accelerometerSensor != NULL && driver.input_data)
            android_input_set_sensor_state(driver.input_data, 0, RETRO_SENSOR_ACCELEROMETER_DISABLE,
                  android_app->accelerometer_event_rate);
         break;

      case APP_CMD_DESTROY:
         g_extern.system.shutdown = true;
         break;
   }
}
static void *android_app_entry(void *data)
{
   struct android_app* android_app = (struct android_app*)data;

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

   print_cur_config(android_app);

   ALooper* looper = ALooper_prepare(ALOOPER_PREPARE_ALLOW_NON_CALLBACKS);
   ALooper_addFd(looper, android_app->msgread, LOOPER_ID_MAIN, ALOOPER_EVENT_INPUT, NULL, NULL);
   android_app->looper = looper;

   pthread_mutex_lock(&android_app->mutex);
   android_app->running = 1;
   pthread_cond_broadcast(&android_app->cond);
   pthread_mutex_unlock(&android_app->mutex);

   memset(&g_android, 0, sizeof(g_android));
   g_android = android_app;

   RARCH_LOG("Native Activity started.\n");
   rarch_main_clear_state();

   while (!android_app->window)
   {
      if (!android_run_events(android_app))
         goto exit;
   }

   rarch_init_msg_queue();

   if (!android_app_start_main(android_app))
   {
      g_settings.input.overlay[0] = 0;
      // threaded video doesn't work right for just displaying one frame
      g_settings.video.threaded = false;
      init_drivers();
      driver.video_poke->set_aspect_ratio(driver.video_data, ASPECT_RATIO_SQUARE);
      rarch_render_cached_frame();
      sleep(2);
      goto exit;
   }

   if (!g_extern.libretro_dummy)
      menu_rom_history_push_current();

   for (;;)
   {
      if (g_extern.system.shutdown)
         break;
      else if (g_extern.lifecycle_mode_state & (1ULL << MODE_LOAD_GAME))
      {
         load_menu_game_prepare();

         // If ROM load fails, we exit RetroArch. On console it might make more sense to go back to menu though ...
         if (load_menu_game())
            g_extern.lifecycle_mode_state |= (1ULL << MODE_GAME);
         else
         {
#ifdef RARCH_CONSOLE
            g_extern.lifecycle_mode_state |= (1ULL << MODE_MENU);
#else
            return NULL;
#endif
         }

         g_extern.lifecycle_mode_state &= ~(1ULL << MODE_LOAD_GAME);
      }
      else if (g_extern.lifecycle_mode_state & (1ULL << MODE_GAME))
      {
         driver.input->poll(NULL);

         if (driver.video_poke->set_aspect_ratio)
            driver.video_poke->set_aspect_ratio(driver.video_data, g_settings.video.aspect_ratio_idx);

         if (g_extern.lifecycle_mode_state & (1ULL << MODE_VIDEO_THROTTLE_ENABLE))
            audio_start_func();

         // Main loop
         while (rarch_main_iterate());

         if (g_extern.lifecycle_mode_state & (1ULL << MODE_VIDEO_THROTTLE_ENABLE))
            audio_stop_func();
         g_extern.lifecycle_mode_state &= ~(1ULL << MODE_GAME);
      }
      else if(g_extern.lifecycle_mode_state & (1ULL << MODE_MENU))
      {
         g_extern.lifecycle_mode_state |= (1ULL << MODE_MENU_PREINIT);
         while((input_key_pressed_func(RARCH_PAUSE_TOGGLE)) ?
               android_run_events(android_app) : menu_iterate());

         g_extern.lifecycle_mode_state &= ~(1ULL << MODE_MENU);
      }
      else
         break;
   }

exit:
   android_app->activityState = APP_CMD_DEAD;
   RARCH_LOG("Deinitializing RetroArch...\n");

   menu_free();

   if (g_extern.config_save_on_exit && *g_extern.config_path)
      config_save_file(g_extern.config_path);

   if (g_extern.main_is_init)
      rarch_main_deinit();

   rarch_deinit_msg_queue();
#ifdef PERF_TEST
   rarch_perf_log();
#endif
   rarch_main_clear_state();

   RARCH_LOG("android_app_destroy!");
   if (android_app->inputQueue != NULL)
      AInputQueue_detachLooper(android_app->inputQueue);
   AConfiguration_delete(android_app->config);

   // exit() here is nasty.
   // pthread_exit(NULL) or return NULL; causes hanging ...
   // Should probably called ANativeActivity_finsih(), but it's bugged, it will hang our app.
   exit(0);
}
示例#13
0
void StAndroidGlue::processCommand() {
    int8_t aCmd = -1;
    if(::read(myMsgRead, &aCmd, sizeof(aCmd)) == sizeof(aCmd)) {
        switch(aCmd) {
            case CommandId_SaveState:
                freeSavedState();
                break;
        }
    } else {
        ST_ERROR_LOG("No data on command pipe!");
        return;
    }

    // preprocessing
    switch(aCmd) {
        case CommandId_InputChanged: {
            pthread_mutex_lock(&myMutex);
            if(myInputQueue != NULL) {
                AInputQueue_detachLooper(myInputQueue);
            }
            myInputQueue = myInputQueuePending;
            if(myInputQueue != NULL) {
                AInputQueue_attachLooper(myInputQueue,
                                         myLooper, LooperId_INPUT, NULL,
                                         &myInputPollSource);
            }
            pthread_cond_broadcast(&myCond);
            pthread_mutex_unlock(&myMutex);
            break;
        }
        case CommandId_WindowChanged:
        case CommandId_WindowInit: {
            pthread_mutex_lock(&myMutex);
            myWindow = myWindowPending;
            pthread_cond_broadcast(&myCond);
            pthread_mutex_unlock(&myMutex);
            break;
        }
        case CommandId_WindowTerm: {
            pthread_cond_broadcast(&myCond);
            break;
        }
        case CommandId_Resume:
        case CommandId_Start:
        case CommandId_Pause:
        case CommandId_Stop: {
            pthread_mutex_lock(&myMutex);
            myActivityState = aCmd;
            pthread_cond_broadcast(&myCond);
            pthread_mutex_unlock(&myMutex);
            break;
        }
        case CommandId_ConfigChanged: {
            AConfiguration_fromAssetManager(myConfig, myActivity->assetManager);
            updateMonitors();
            printConfig();
            break;
        }
        case CommandId_Destroy: {
            myToDestroy = true;
            break;
        }
    }

    signals.onAppCmd(aCmd);

    // post-processing
    switch(aCmd) {
        case CommandId_WindowTerm: {
            pthread_mutex_lock(&myMutex);
            myWindow = NULL;
            pthread_cond_broadcast(&myCond);
            pthread_mutex_unlock(&myMutex);
            break;
        }
        case CommandId_WindowChanged: {
            pthread_mutex_lock(&myMutex);
            myWindowPending = NULL;
            pthread_cond_broadcast(&myCond);
            pthread_mutex_unlock(&myMutex);
            break;
        }
        case CommandId_SaveState: {
            pthread_mutex_lock(&myMutex);
            myIsStateSaved = true;
            pthread_cond_broadcast(&myCond);
            pthread_mutex_unlock(&myMutex);
            break;
        }
        case CommandId_Resume: {
            freeSavedState();
            break;
        }
    }
}
示例#14
0
void StAndroidGlue::threadEntry() {
    if(myJavaVM->AttachCurrentThread(&myThJniEnv, NULL) < 0) {
        ST_ERROR_LOG("Failed to attach working thread to Java VM");
        return;
    }

    THE_ANDROID_GLUE = this;
    StMessageBox::setCallback(msgBoxCallback);

    myConfig = AConfiguration_new();
    AConfiguration_fromAssetManager(myConfig, myActivity->assetManager);
    updateMonitors();
    printConfig();

    ALooper* aLooper = ALooper_prepare(ALOOPER_PREPARE_ALLOW_NON_CALLBACKS);
    ALooper_addFd(aLooper, myMsgRead, LooperId_MAIN, ALOOPER_EVENT_INPUT, NULL, &myCmdPollSource);
    myLooper = aLooper;

    pthread_mutex_lock(&myMutex);
    myIsRunning = true;
    pthread_cond_broadcast(&myCond);
    pthread_mutex_unlock(&myMutex);

    // try to load stereo APIs
    /**jclass aJClass_Real3D = myThJniEnv->FindClass("com/lge/real3d/Real3D");
    if(aJClass_Real3D != NULL) {
        jmethodID aJMet_isStereoDisplayAvailable = myThJniEnv->GetStaticMethodID(aJClass_Real3D, "isStereoDisplayAvailable", "(Landroid/content/Contex;)Z");
        postMessage("com.lge.real3d.Real3D !!!");
    }

    jclass aJClass_HTC = myThJniEnv->FindClass("com/htc/view/DisplaySetting");
    if(aJClass_HTC != NULL) {
        jmethodID aJMet_isStereoDisplayAvailable = myThJniEnv->GetStaticMethodID(aJClass_HTC, "setStereoscopic3DFormat", "(Landroid/view/Surface;I)Z");
        postMessage("com.htc.view.DisplaySetting !!!");
    }

    jclass aJClass_Sharp = myThJniEnv->FindClass("jp/co/sharp/android/stereo3dlcd/SurfaceController");
    if(aJClass_Sharp != NULL) {
        jmethodID aJMet_setStereoView = myThJniEnv->GetMethodID(aJClass_Sharp, "setStereoView", "(Z)V");
        postMessage("jp.co.sharp.android.stereo3dlcd !!!");
    }*/

    createApplication();
    if(!myApp.isNull()) {
        if(!myApp->open()) {
            stError("Error: application can not be executed!");
        }
        myApp->exec();
    } else {
        stError("Error: no application to execute!");
    }
    myApp.nullify();

    // application is done but we are waiting for destroying event...
    bool isFirstWait = true;
    for(; !myToDestroy; ) {
        if(isFirstWait) {
            postExit();
            isFirstWait = false;
        }

        StAndroidPollSource* aSource = NULL;
        int aNbEvents = 0;
        ALooper_pollAll(-1, NULL, &aNbEvents, (void** )&aSource);
        if(aSource != NULL) {
            aSource->process(this, aSource);
        }
    }

    freeSavedState();
    pthread_mutex_lock(&myMutex);
    if(myInputQueue != NULL) {
        AInputQueue_detachLooper(myInputQueue);
    }
    AConfiguration_delete(myConfig);
    pthread_cond_broadcast(&myCond);
    pthread_mutex_unlock(&myMutex);

    myThJniEnv = NULL;
    StMessageBox::setCallback(NULL);
    THE_ANDROID_GLUE = NULL;

    myJavaVM->DetachCurrentThread();
}
void android_app_pre_exec_cmd(struct android_app* android_app, int8_t cmd) {
    switch (cmd) {
        case APP_CMD_INPUT_CHANGED:
            LOGI("APP_CMD_INPUT_CHANGED\n");
            pthread_mutex_lock(&android_app->mutex);
            if (android_app->inputQueue != NULL) {
                AInputQueue_detachLooper(android_app->inputQueue);
            }
            android_app->inputQueue = android_app->pendingInputQueue;
            if (android_app->inputQueue != NULL) {
                LOGI("Attaching input queue to looper");
                AInputQueue_attachLooper(android_app->inputQueue,
                        android_app->looper, LOOPER_ID_INPUT, NULL,
                        &android_app->inputPollSource);
            }
            pthread_cond_broadcast(&android_app->cond);
            pthread_mutex_unlock(&android_app->mutex);
            break;

        case APP_CMD_INIT_WINDOW:
            LOGI("APP_CMD_INIT_WINDOW\n");
            pthread_mutex_lock(&android_app->mutex);
            android_app->window = android_app->pendingWindow;
            if (android_app->window && 
                ANativeWindow_getWidth(android_app->window) &&
                ANativeWindow_getHeight(android_app->window))
            {
                android_app->lifecycleFlags |= NV_APP_STATUS_HAS_REAL_SURFACE;
            }
            else
            {
                android_app->lifecycleFlags &= ~NV_APP_STATUS_HAS_REAL_SURFACE;
            }

            pthread_cond_broadcast(&android_app->cond);
            pthread_mutex_unlock(&android_app->mutex);
            break;

        case APP_CMD_TERM_WINDOW:
            LOGI("APP_CMD_TERM_WINDOW\n");
            android_app->lifecycleFlags &= ~NV_APP_STATUS_HAS_REAL_SURFACE;
            pthread_cond_broadcast(&android_app->cond);
            break;

        case APP_CMD_WINDOW_RESIZED:
            LOGI("APP_CMD_WINDOW_RESIZED\n");
            pthread_mutex_lock(&android_app->mutex);
            if (android_app->window && 
                ANativeWindow_getWidth(android_app->window) &&
                ANativeWindow_getHeight(android_app->window))
            {
                android_app->lifecycleFlags |= NV_APP_STATUS_HAS_REAL_SURFACE;
            }
            else
            {
                android_app->lifecycleFlags &= ~NV_APP_STATUS_HAS_REAL_SURFACE;
            }

            pthread_cond_broadcast(&android_app->cond);
            pthread_mutex_unlock(&android_app->mutex);
            break;

        case APP_CMD_GAINED_FOCUS:
            LOGI("APP_CMD_GAINED_FOCUS\n");
            pthread_mutex_lock(&android_app->mutex);
            android_app->lifecycleFlags |= NV_APP_STATUS_FOCUSED;
            pthread_cond_broadcast(&android_app->cond);
            pthread_mutex_unlock(&android_app->mutex);
            break;

        case APP_CMD_LOST_FOCUS:
            LOGI("APP_CMD_LOST_FOCUS\n");
            pthread_mutex_lock(&android_app->mutex);
            android_app->lifecycleFlags &= ~NV_APP_STATUS_FOCUSED;
            pthread_cond_broadcast(&android_app->cond);
            pthread_mutex_unlock(&android_app->mutex);
            break;

        case APP_CMD_RESUME:
            LOGI("activityState=%d\n", cmd);
            pthread_mutex_lock(&android_app->mutex);
            android_app->lifecycleFlags |= NV_APP_STATUS_ACTIVE;
            android_app->activityState = cmd;
            pthread_cond_broadcast(&android_app->cond);
            pthread_mutex_unlock(&android_app->mutex);
            break;

        case APP_CMD_START:
            LOGI("activityState=%d\n", cmd);
            pthread_mutex_lock(&android_app->mutex);
            android_app->activityState = cmd;
            pthread_cond_broadcast(&android_app->cond);
            pthread_mutex_unlock(&android_app->mutex);
            break;

        case APP_CMD_PAUSE:
            LOGI("activityState=%d\n", cmd);
            pthread_mutex_lock(&android_app->mutex);
            android_app->lifecycleFlags &= ~NV_APP_STATUS_ACTIVE;
            android_app->activityState = cmd;
            pthread_cond_broadcast(&android_app->cond);
            pthread_mutex_unlock(&android_app->mutex);
            break;

        case APP_CMD_STOP:
            LOGI("activityState=%d\n", cmd);
            pthread_mutex_lock(&android_app->mutex);
            android_app->activityState = cmd;
            pthread_cond_broadcast(&android_app->cond);
            pthread_mutex_unlock(&android_app->mutex);
            break;

        case APP_CMD_CONFIG_CHANGED:
            LOGI("APP_CMD_CONFIG_CHANGED\n");
            AConfiguration_fromAssetManager(android_app->config,
                    android_app->activity->assetManager);
            print_cur_config(android_app);
            break;

        case APP_CMD_DESTROY:
            LOGI("APP_CMD_DESTROY\n");
            android_app->lifecycleFlags &= ~NV_APP_STATUS_RUNNING;
            break;
    }
}