void* SkiaAndroidApp::pthread_main(void* arg) {
    SkDebugf("pthread_main begins");

    auto skiaAndroidApp = (SkiaAndroidApp*)arg;

    // Because JNIEnv is thread sensitive, we need AttachCurrentThread to set our fPThreadEnv
    skiaAndroidApp->fJavaVM->AttachCurrentThread(&(skiaAndroidApp->fPThreadEnv), nullptr);

    ALooper* looper = ALooper_prepare(ALOOPER_PREPARE_ALLOW_NON_CALLBACKS);
    pipe(skiaAndroidApp->fPipes);
    ALooper_addFd(looper, skiaAndroidApp->fPipes[0], LOOPER_ID_MESSAGEPIPE, ALOOPER_EVENT_INPUT,
                  message_callback, skiaAndroidApp);

    skiaAndroidApp->fApp = Application::Create(0, nullptr, skiaAndroidApp);

    double currentTime = 0.0;
    double previousTime = 0.0;
    while (true) {
        const int ident = ALooper_pollAll(0, nullptr, nullptr, nullptr);

        if (ident >= 0) {
            SkDebugf("Unhandled ALooper_pollAll ident=%d !", ident);
        } else {
            previousTime = currentTime;
            currentTime = now_ms();
            skiaAndroidApp->fApp->onIdle(currentTime - previousTime);
        }
    }

    SkDebugf("pthread_main ends");

    return nullptr;
}
static void* android_app_entry(void* param) {
    struct android_app* android_app = (struct android_app*)param;

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

    print_cur_config(android_app);

    android_app->cmdPollSource.id = LOOPER_ID_MAIN;
    android_app->cmdPollSource.app = android_app;
    android_app->cmdPollSource.process = process_cmd;
    android_app->inputPollSource.id = LOOPER_ID_INPUT;
    android_app->inputPollSource.app = android_app;
    android_app->inputPollSource.process = process_input;

    ALooper* looper = ALooper_prepare(ALOOPER_PREPARE_ALLOW_NON_CALLBACKS);
    ALooper_addFd(looper, android_app->msgread, LOOPER_ID_MAIN, ALOOPER_EVENT_INPUT, NULL,
            &android_app->cmdPollSource);
    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);

    android_main(android_app);

    android_app_destroy(android_app);
    return NULL;
}
Beispiel #3
0
JNIEXPORT void JNICALL
Java_net_jlekstrand_wheatley_wayland_Compositor_addToLooperNative(JNIEnv *env,
        jclass cls, jlong nativeHandle)
{
    struct wheatley_compositor *wc =
        (struct wheatley_compositor *)(intptr_t)nativeHandle;
    ALooper *looper;

    if (wc->looper) {
        jni_util_throw_by_name(env, "java/lang/IllegalStateException",
                               "Compositor already assigned to a looper");
        return;
    }

    looper = ALooper_forThread();
    if (looper == NULL) {
        jni_util_throw_by_name(env, "java/lang/RuntimeException",
                               "Current thread does not have a Looper");
        return;
    }

    ALooper_addFd(looper,
                  wl_event_loop_get_fd(wl_display_get_event_loop(wc->display)),
                  ALOOPER_POLL_CALLBACK, ALOOPER_EVENT_INPUT | ALOOPER_EVENT_OUTPUT,
                  wheatley_compositor_ALooper_func, wc);

    wc->looper = looper;
}
static void frontend_android_init(void *data)
{
   JNIEnv *env;
   ALooper *looper;
   jclass class = NULL;
   jobject obj = NULL;
   struct android_app* android_app = (struct android_app*)data;

   if (!android_app)
      return;

   looper = (ALooper*)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;

   slock_lock(android_app->mutex);
   android_app->running = 1;
   scond_broadcast(android_app->cond);
   slock_unlock(android_app->mutex);

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

   RARCH_LOG("Waiting for Android Native Window to be initialized ...\n");

   while (!android_app->window)
   {
      if (!android_run_events(android_app))
      {
         frontend_android_deinit(android_app);
         frontend_android_shutdown(android_app);
         return;
      }
   }

   RARCH_LOG("Android Native Window initialized.\n");

   env = jni_thread_getenv();
   if (!env)
      return;

   GET_OBJECT_CLASS(env, class, android_app->activity->clazz);
   GET_METHOD_ID(env, android_app->getIntent, class, "getIntent", "()Landroid/content/Intent;");
   CALL_OBJ_METHOD(env, obj, android_app->activity->clazz, android_app->getIntent);
#if 0
   GET_METHOD_ID(env, android_app->hasPendingIntent, class, "hasPendingIntent", "()Z");
   GET_METHOD_ID(env, android_app->clearPendingIntent, class, "clearPendingIntent", "()V");
   GET_METHOD_ID(env, android_app->getPendingIntentConfigPath, class, "getPendingIntentConfigPath",
         "()Ljava/lang/String;");
   GET_METHOD_ID(env, android_app->getPendingIntentLibretroPath, class, "getPendingIntentLibretroPath",
         "()Ljava/lang/String;");
   GET_METHOD_ID(env, android_app->getPendingIntentFullPath, class, "getPendingIntentFullPath",
         "()Ljava/lang/String;");
   GET_METHOD_ID(env, android_app->getPendingIntentIME, class, "getPendingIntentIME",
         "()Ljava/lang/String;");
#endif

   GET_OBJECT_CLASS(env, class, obj);
   GET_METHOD_ID(env, android_app->getStringExtra, class, "getStringExtra", "(Ljava/lang/String;)Ljava/lang/String;");
}
Beispiel #5
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;
}
Beispiel #6
0
void* SkiaAndroidApp::pthread_main(void* arg) {
    SkDebugf("pthread_main begins");

    auto skiaAndroidApp = (SkiaAndroidApp*)arg;

    // Because JNIEnv is thread sensitive, we need AttachCurrentThread to set our fPThreadEnv
    skiaAndroidApp->fJavaVM->AttachCurrentThread(&(skiaAndroidApp->fPThreadEnv), nullptr);

    ALooper* looper = ALooper_prepare(ALOOPER_PREPARE_ALLOW_NON_CALLBACKS);
    pipe(skiaAndroidApp->fPipes);
    ALooper_addFd(looper, skiaAndroidApp->fPipes[0], LOOPER_ID_MESSAGEPIPE, ALOOPER_EVENT_INPUT,
                  message_callback, skiaAndroidApp);

    int ident;
    int events;
    struct android_poll_source* source;

    skiaAndroidApp->fApp = Application::Create(0, nullptr, skiaAndroidApp);

    while ((ident = ALooper_pollAll(-1, nullptr, &events, (void**)&source)) >= 0) {
        SkDebugf("ALooper_pollAll ident=%d", ident);
    }

    return nullptr;
}
Device::Device(int32_t id, int fd, std::unique_ptr<DeviceCallback> callback) :
            mId(id), mFd(fd), mDeviceCallback(std::move(callback)) {
    ALooper* aLooper = ALooper_forThread();
    if (aLooper == NULL) {
        LOGE("Could not get ALooper, ALooper_forThread returned NULL");
        aLooper = ALooper_prepare(ALOOPER_PREPARE_ALLOW_NON_CALLBACKS);
    }
    ALooper_addFd(aLooper, fd, 0, ALOOPER_EVENT_INPUT, handleLooperEvents,
                  reinterpret_cast<void*>(this));
}
static void* AndroidEventThreadWorker( void* param )
{
	struct android_app* state = (struct android_app*)param;

	FPlatformProcess::SetThreadAffinityMask(FPlatformAffinity::GetMainGameMask());

	FPlatformMisc::LowLevelOutputDebugString(L"Entering event processing thread engine entry point");

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

	FPlatformMisc::LowLevelOutputDebugString(L"Prepared looper for event thread");

	//Assign the callbacks
	state->onAppCmd = OnAppCommandCB;
	state->onInputEvent = HandleInputCB;

	FPlatformMisc::LowLevelOutputDebugString(L"Passed callback initialization");

	// Acquire sensors
	SensorManager = ASensorManager_getInstance();
	if (NULL != SensorManager)
	{
		// Register for the various sensor events we want. Some
		// may return NULL indicating that the sensor data is not
		// available in the device. For those empty data will eventually
		// get fed into the motion events.
		SensorAccelerometer = ASensorManager_getDefaultSensor(
			SensorManager, ASENSOR_TYPE_ACCELEROMETER);
		SensorGyroscope = ASensorManager_getDefaultSensor(
			SensorManager, ASENSOR_TYPE_GYROSCOPE);
		// Create the queue for events to arrive.
		SensorQueue = ASensorManager_createEventQueue(
			SensorManager, state->looper, LOOPER_ID_USER, HandleSensorEvents, NULL);
	}

	FPlatformMisc::LowLevelOutputDebugString(L"Passed sensor initialization");

	//continue to process events until the engine is shutting down
	while (!GIsRequestingExit)
	{
//		FPlatformMisc::LowLevelOutputDebugString(L"AndroidEventThreadWorker");

		AndroidProcessEvents(state);

		sleep(EventRefreshRate);		// this is really 0 since it takes int seconds.
	}

	UE_LOG(LogAndroid, Log, TEXT("Exiting"));

	return NULL;
}
	void message_dispatcher::prepare()
	{
		scoped_lock lock(m_mutex);
		m_looper = ALooper_prepare(ALOOPER_PREPARE_ALLOW_NON_CALLBACKS);
		if (!m_looper)
			throw std::runtime_error("cannot create the internal looper");
		ALooper_addFd(m_looper, m_readfd, MSG_ID_SYSTEM, ALOOPER_EVENT_INPUT, NULL, NULL);
		if (m_iqueue) {
			attach_queue(m_iqueue);
		}
	}
Beispiel #10
0
// Called before main() to initialize JNI bindings
static void orxAndroid_Init(JNIEnv* mEnv, jobject jActivity)
{
    LOGI("orxAndroid_Init()");

    jclass objClass;

    orxAndroid_JNI_SetupThread();

    sstAndroid.mActivity = mEnv->NewGlobalRef(jActivity);

    objClass = mEnv->FindClass("org/orx/lib/OrxActivity");
    sstAndroid.midGetRotation = mEnv->GetMethodID(objClass, "getRotation","()I");
    sstAndroid.midGetDeviceIds = mEnv->GetMethodID(objClass, "getDeviceIds", "()[I");

    if(!sstAndroid.midGetRotation
       || !sstAndroid.midGetDeviceIds) {
        __android_log_print(ANDROID_LOG_WARN, "Orx", "Couldn't locate Java callbacks, check that they're named and typed correctly");
    }

    // setup AssetManager
    jmethodID midGetAssets = mEnv->GetMethodID(objClass, "getAssets", "()Landroid/content/res/AssetManager;");
    jobject jAssetManager = mEnv->CallObjectMethod(jActivity, midGetAssets);
    sstAndroid.jAssetManager = mEnv->NewGlobalRef(jAssetManager);
    sstAndroid.poAssetManager = AAssetManager_fromJava(mEnv, sstAndroid.jAssetManager);

    mEnv->DeleteLocalRef(objClass);
    mEnv->DeleteLocalRef(jActivity);
    mEnv->DeleteLocalRef(jAssetManager);

    sstAndroid.looper = ALooper_prepare(ALOOPER_PREPARE_ALLOW_NON_CALLBACKS);

    ALooper_addFd(sstAndroid.looper, sstAndroid.pipeCmd[0], LOOPER_ID_MAIN, ALOOPER_EVENT_INPUT, NULL, NULL);
    ALooper_addFd(sstAndroid.looper, sstAndroid.pipeKeyEvent[0], LOOPER_ID_KEY_EVENT, ALOOPER_EVENT_INPUT, NULL, NULL);
    ALooper_addFd(sstAndroid.looper, sstAndroid.pipeTouchEvent[0], LOOPER_ID_TOUCH_EVENT, ALOOPER_EVENT_INPUT, NULL, NULL);
    ALooper_addFd(sstAndroid.looper, sstAndroid.pipeJoystickEvent[0], LOOPER_ID_JOYSTICK_EVENT, ALOOPER_EVENT_INPUT, NULL, NULL);

    LOGI("orxAndroid_Init() finished!");
}
void* SkiaAndroidApp::pthread_main(void* arg) {
    SkDebugf("pthread_main begins");

    auto skiaAndroidApp = (SkiaAndroidApp*)arg;

    // Because JNIEnv is thread sensitive, we need AttachCurrentThread to set our fPThreadEnv
    skiaAndroidApp->fJavaVM->AttachCurrentThread(&(skiaAndroidApp->fPThreadEnv), nullptr);

    ALooper* looper = ALooper_prepare(ALOOPER_PREPARE_ALLOW_NON_CALLBACKS);
    pipe(skiaAndroidApp->fPipes);
    ALooper_addFd(looper, skiaAndroidApp->fPipes[0], LOOPER_ID_MESSAGEPIPE, ALOOPER_EVENT_INPUT,
                  message_callback, skiaAndroidApp);

    static const char* gCmdLine[] = {
        "viewer",
        // TODO: figure out how to use am start with extra params to pass in additional arguments at
        // runtime. Or better yet make an in app switch to enable
        // "--atrace",
    };

    skiaAndroidApp->fApp = Application::Create(SK_ARRAY_COUNT(gCmdLine),
                                               const_cast<char**>(gCmdLine),
                                               skiaAndroidApp);

    while (true) {
        const int ident = ALooper_pollAll(0, nullptr, nullptr, nullptr);

        if (ident >= 0) {
            SkDebugf("Unhandled ALooper_pollAll ident=%d !", ident);
        } else {
            skiaAndroidApp->fApp->onIdle();
        }
    }

    SkDebugf("pthread_main ends");

    return nullptr;
}
JNIEXPORT jboolean JNICALL Java_edu_ucla_nesl_sigma_base_SigmaJNI_waitForMessage
    (JNIEnv *env, jclass _class, jint fd) {
  ALooper* looper = ALooper_prepare(ALOOPER_PREPARE_ALLOW_NON_CALLBACKS);
  ALOGD("waitForMessage: pollOnce looper@%d fd@%d", (int)looper, fd);
  ALooper_addFd(looper, fd, fd, ALOOPER_EVENT_INPUT, NULL, NULL);

  int events;
  int result = ALooper_pollOnce(-1, NULL, &events, NULL);
  if (result == ALOOPER_POLL_ERROR) {
      ALOGE("waitForMessage error (errno=%d)", errno);
      result = -1337; // unknown error, so we make up one
      return JNI_FALSE;
  }
  if (events & ALOOPER_EVENT_HANGUP) {
      // the other-side has died
      ALOGE("waitForMessage error HANGUP");
      result = -1337; // unknown error, so we make up one
      return JNI_FALSE;
  }

  return JNI_TRUE;

  ALOGD("waitForMessage: got something.");
}
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);
}
Beispiel #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();
}
Beispiel #15
0
static void* android_app_entry(void* param) {
    LOGV("+android_app_entry");
    struct android_app* android_app = (struct android_app*)param;

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

    print_cur_config(android_app);

    android_app->cmdPollSource.id = LOOPER_ID_MAIN;
    android_app->cmdPollSource.app = android_app;
    android_app->cmdPollSource.process = process_cmd;
    android_app->inputPollSource.id = LOOPER_ID_INPUT;
    android_app->inputPollSource.app = android_app;
    android_app->inputPollSource.process = process_input;

    ALooper* looper = ALooper_prepare(ALOOPER_PREPARE_ALLOW_NON_CALLBACKS);
    ALooper_addFd(looper, android_app->msgread, LOOPER_ID_MAIN, ALOOPER_EVENT_INPUT, NULL,
            &android_app->cmdPollSource);
    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);
    
    std::string sargv;
    
    // Load command line from ARGV parameter
    JNIEnv *env = GetEnvAttachThread(android_app->activity->vm);
    if(env) {
        jobject me = android_app->activity->clazz;
        
        jclass acl = env->GetObjectClass(me); //class pointer of NativeActivity
        jmethodID giid = env->GetMethodID(acl, "getIntent", "()Landroid/content/Intent;");
        jobject intent = env->CallObjectMethod(me, giid); //Got our intent
        
        jclass icl = env->GetObjectClass(intent); //class pointer of Intent
        jmethodID gseid = env->GetMethodID(icl, "getStringExtra", "(Ljava/lang/String;)Ljava/lang/String;");
        
        jstring jsARGV = (jstring)env->CallObjectMethod(intent, gseid, env->NewStringUTF("ARGV"));
        
        
        if(jsARGV) {
            const char *chARGV = env->GetStringUTFChars(jsARGV, 0);
            if(chARGV) {
                sargv = std::string(chARGV);
                LOGI("ARGV: pango %s", chARGV);
            }
            env->ReleaseStringUTFChars(jsARGV, chARGV);    
        }
        
        android_app->activity->vm->DetachCurrentThread();
    }

    // Set up argv/argc to pass to users main
    std::vector<std::string> vargv;
    vargv.push_back("pango");
    
    // Parse parameters from ARGV android intent parameter
    std::istringstream iss(sargv);
    std::copy(std::istream_iterator<std::string>(iss),
             std::istream_iterator<std::string>(),
             std::back_inserter<std::vector<std::string> >(vargv));    

    char* argv[vargv.size()+1];
    for(size_t ac = 0; ac < vargv.size(); ++ac) {
        argv[ac] = new char[vargv[ac].size()];
        strcpy( argv[ac], vargv[ac].c_str() );
    }
    argv[vargv.size()] = NULL;
    
    // Call users standard main entry point.
    main(vargv.size(), argv);
    
    // Clean up parameters
    for(size_t ac = 0; ac < vargv.size(); ++ac) {
        delete[] argv[ac];
    }    
    
    android_app_destroy(android_app);
    
    LOGV("-android_app_entry");
    
    return NULL;
}