Search code examples
androidandroid-ndkaccelerometerandroid-looper

ASensorEventQueue_hasEvents returns -1 and ALooper_pollAll returns -4 on basic usage


I am trying to write an android app which uses the Java SDK for the GUI, and the NDK to draw things and read the Linear Acceleration sensor (based of the accelerometer but does not include gravity). Basically, I want to know when the device is being shaken and my app is active.

I am using ASensorEventQueue_hasEvents and ALooper_pollAll in a fairly basic manner, I think, but they return -1 and -4 respectively. These are errors, but I have no clue what they mean or what I could be doing wrong. Any help would be welcome, thanks! Here are some code snips:

To start listening for data from the linear acceleration sensor, I did:

//sensorManager = ASensorManager_getInstance();
sensorManager = ASensorManager_getInstanceForPackage(mypackage);
sensor = ASensorManager_getDefaultSensor(sensorManager, ASENSOR_TYPE_LINEAR_ACCELERATION);
if (sensor == nullptr) {
    return env->NewStringUTF("Linear accelerometer is not present");
}

looper = ALooper_prepare(0);
if (looper == nullptr) {
    return env->NewStringUTF("Could not get looper.");
}

eventQueue = ASensorManager_createEventQueue(sensorManager, looper, EVENT_TYPE_LINEAR_ACCELEROMETER, nullptr, nullptr);
if (eventQueue == nullptr) {
    return env->NewStringUTF("Could not create event queue for sensor");
}

//ASensorEventQueue_disableSensor(eventQueue, sensor);
int minDelay = ASensor_getMinDelay(sensor);
minDelay = std::max(minDelay, MAX_EVENT_REPORT_TIME);

int rc = ASensorEventQueue_registerSensor(eventQueue, sensor, minDelay, minDelay);
rc = ASensorEventQueue_setEventRate(eventQueue, sensor, minDelay);
return env->NewStringUTF("");

And my drawing loop looks like:

    int rc = ASensorEventQueue_enableSensor(eventQueue, sensor);
    std::vector<std::string> results;
    while (!stopDrawing) {
        int event = 0;
        void *data = nullptr;
        int rc;
        rc = ASensorEventQueue_hasEvents(eventQueue); // testing
        rc = ALooper_pollAll(wait_timeout, nullptr, &event, &data);
        if (rc == ALOOPER_POLL_TIMEOUT) {
            waiting += wait_timeout;

            if (waiting > EVENT_LOOP_TIMEOUT) {
                // If no data has been received, we have been waiting for a while, so assume
                // the shaking has stopped
                ASensorEventQueue_disableSensor(eventQueue, sensor);
            }
        } else if (rc == ALOOPER_POLL_ERROR) {
             return env->NewStringUTF("A looper error occurred");
        } else if (rc >= 0 && event == EVENT_TYPE_LINEAR_ACCELEROMETER) {
            std::vector<ASensorEvent> events;
            events.resize(100);
            while (ASensorEventQueue_hasEvents(eventQueue) == 1) {
                ssize_t nbrEvents = ASensorEventQueue_getEvents(eventQueue, events.data(), events.size());
                if (nbrEvents < 0) {
                    // an error has occurred
                    return env->NewStringUTF("");
                }

                float x = 0;
                float y = 0;
                float z = 0;
                for (int i = 0; i < nbrEvents; i++) {
                    x += events[i].acceleration.x;
                    y += events[i].acceleration.y;
                    z += events[i].acceleration.z;
                }

                graphics.updateAcceleration(x, y, z);
            }
        }
        graphics.updateUniformBuffer();
        graphics.drawFrame();
    }

Note: the call to ASensorEventQueue_hasEvents right before ALooper_pollAll was just so that I could see what it was returning since the ALooper_pollAll call always returned an error. When running it in the debugger, I see that hasEvents is returning -1 and pollAll is returning -4. This is happening in SDK versions 24 and 26 (I haven't tried 27 and vulkan is not supported below 24). Any ideas why?


Solution

  • I had the precise symptoms described here, and for me it turned out that I was preparing the looper on a different thread than I was polling on.