This story starts to get me totally crazy.

Sorry Dianne ;-), but Craig is right. In AOSP, part of the problem is
that screenOrientation is not set up in the manifest files.

Nevertheless, it still not working. Moreover, I have now a crazy
behavior. Perhaps I'm wrong, but it shows a bug in AOSP.

If I do screenOrientation=sensor for Launcher and
screenOrientation=portrait for Browser in the manifest files, the
following happens:

- I launch the Launcher. It's in landscape mode which is my default
mode as I have a kind of netbook. I move the device, the screen
doesn't rotate.

- I launch the IBM eye application mentioned in the thread.
Acceleration reports x=0, y=8, z=0. The screen is at 90d of the
keyboard. I move the device, the values are changing and they "make
sense".

- I launch the browser. It switches to portrait. So far, everything
makes sense due to the manifest.

- I press the back button, the launcher is now in portrait mode!!!

- I launch the IBM eye application. The screen is still at 90d of the
keyboard. Acceleration reports now x=-8, y=0, z=0!!!!!!!

This is Star Trek! My sensors.c code is below for reference.

Question 1: if I just implement acceleration (but not orientation) in
the sensor, can AOSP rotate the screen when the device rotates? Or do
I need to fake an orientation sensor? I beg you, please answer by yes
or no!

Question 2: at this point, and with the crazy behavior reported above,
I don't think that I have a problem in sensors.c. My guess is that I
have a problem somewhere else in the configuration of my Eclair AOSP,

Grégoire



/* Android driver for the Freescale MMA7455L 3-axis accelerometer
 *
 * Copyright (C) 2010 by Always Innovating, Inc.
 * Author: Gregoire Gentil <[email protected]>
 * Author: GPTechinno - Georges
 * All rights reserved.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of
 * the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 * MA 02111-1307 USA
 *
 */

#define LOG_TAG "Sensors"

#include <hardware/sensors.h>
#include <fcntl.h>
#include <errno.h>
#include <dirent.h>
#include <math.h>
#include <poll.h>
#include <pthread.h>

#include <linux/input.h>
#include <linux/mma7455l.h>

#include <cutils/atomic.h>
#include <cutils/log.h>
#include <cutils/native_handle.h>

/
*****************************************************************************/

#define MAX_NUM_SENSORS 1

#define SUPPORTED_SENSORS  ((1<<MAX_NUM_SENSORS)-1)

#define ID_A  (0)

#define SENSORS_ACCELERATION   (1<<ID_A)

/
*****************************************************************************/

struct sensors_control_context_t {
    struct sensors_control_device_t device;
    int acceld_fd;
    uint32_t active_sensors;
};

struct sensors_data_context_t {
    struct sensors_data_device_t device;
    int events_fd;
    sensors_data_t sensors[MAX_NUM_SENSORS];
    uint32_t pendingSensors;
};

/*
 * The SENSORS Module
 */

static const struct sensor_t sSensorList[] = {
        { "MMA7455L 3-axis Low-g Accelerometer",
                "Freescale",
                1, SENSORS_HANDLE_BASE+ID_A,
                SENSOR_TYPE_ACCELEROMETER, 8.0f*9.81f, 9.81f/64.0f,
5.0f, { } },
};

static int open_sensors(const struct hw_module_t* module, const char*
name,
        struct hw_device_t** device);

static uint32_t sensors__get_sensors_list(struct sensors_module_t*
module,
        struct sensor_t const** list)
{
    *list = sSensorList;
    return sizeof(sSensorList)/sizeof(sSensorList[0]);
}

static struct hw_module_methods_t sensors_module_methods = {
    .open = open_sensors
};

struct sensors_module_t HAL_MODULE_INFO_SYM = {
    .common = {
        .tag = HARDWARE_MODULE_TAG,
        .version_major = 1,
        .version_minor = 0,
        .id = SENSORS_HARDWARE_MODULE_ID,
        .name = "MMA7455L SENSORS Module",
        .author = "The Android Open Source Project",
        .methods = &sensors_module_methods,
    },
    .get_sensors_list = sensors__get_sensors_list
};

float x, y, z;

static int open_input(int mode)
{
    /* scan all input drivers and look for "mma7455l" */
    int fd = -1;
    const char *dirname = "/dev/input";
    char devname[PATH_MAX];
    char *filename;
    DIR *dir;
    struct dirent *de;
    dir = opendir(dirname);
    if(dir == NULL)
        return -1;
    strcpy(devname, dirname);
    filename = devname + strlen(devname);
    *filename++ = '/';
    while((de = readdir(dir))) {
        if(de->d_name[0] == '.' &&
           (de->d_name[1] == '\0' ||
            (de->d_name[1] == '.' && de->d_name[2] == '\0')))
            continue;
        strcpy(filename, de->d_name);
        fd = open(devname, mode);
        if (fd>=0) {
            char name[80];
            if (ioctl(fd, EVIOCGNAME(sizeof(name) - 1), &name) < 1) {
                name[0] = '\0';
            }
            if (!strcmp(name, "MMA7455L")) {
                //LOGD("using %s (name=%s)", devname, name);
                break;
            }
            close(fd);
            fd = -1;
        }
    }
    closedir(dir);

    if (fd < 0) {
        LOGE("Couldn't find or open 'mma7455l' driver (%s)",
strerror(errno));
    }
    return fd;
}

static int open_accel(struct sensors_control_context_t* dev)
{
    if (dev->acceld_fd <= 0) {
        dev->acceld_fd = open_input(O_RDONLY);
        //LOGD("%s, fd=%d", __PRETTY_FUNCTION__, dev->acceld_fd);
        if (dev->acceld_fd >= 0) {
            dev->active_sensors = 0;
        }
    }
    return dev->acceld_fd;
}

static void close_accel(struct sensors_control_context_t* dev)
{
    if (dev->acceld_fd > 0) {
        //LOGD("%s, fd=%d", __PRETTY_FUNCTION__, dev->acceld_fd);
        close(dev->acceld_fd);
        dev->acceld_fd = -1;
    }
}

static void enable_disable(int fd, uint32_t sensors, uint32_t mask)
{
    return;
}

static uint32_t read_sensors_state(int fd)
{
    return SENSORS_ACCELERATION;
}

/
*****************************************************************************/

static native_handle_t* control__open_data_source(struct
sensors_control_context_t *dev)
{
    native_handle_t* handle;
    int fd = open_input(O_RDONLY);
    if (fd < 0) {
        return NULL;
    }

    handle = native_handle_create(1, 0);
    handle->data[0] = fd;
    return handle;
}

static int control__activate(struct sensors_control_context_t *dev,
        int handle, int enabled)
{
    if ((handle<SENSORS_HANDLE_BASE) ||
            (handle>=SENSORS_HANDLE_BASE+MAX_NUM_SENSORS)) {
        return -1;
    }

    uint32_t mask = (1<<handle);
    uint32_t sensors = enabled ? mask : 0;

    uint32_t active = dev->active_sensors;
    uint32_t new_sensors = (active & ~mask) | (sensors & mask);
    uint32_t changed = active ^ new_sensors;
    if (changed) {
        int fd = open_accel(dev);
        if (fd >= 0) {
            if (!active && new_sensors) {
                // force all sensors to be updated
                changed = SUPPORTED_SENSORS;
            }

            enable_disable(fd, new_sensors, changed);

            LOGD("sensors=%08x, real=%08x",
                    new_sensors, read_sensors_state(fd));

            if (active && !new_sensors) {
                // close the driver
                close_accel(dev);
            }
            dev->active_sensors = active = new_sensors;
        } else {
            active = -1;
        }
    }
    return 0;
}

static int control__set_delay(struct sensors_control_context_t *dev,
int32_t ms)
{
    return -1;
}

static int control__wake(struct sensors_control_context_t *dev)
{
    int err = 0;
    int fd = open_input(O_WRONLY);
    if (fd > 0) {
        struct input_event event[1];
        event[0].type = EV_SYN;
        event[0].code = SYN_CONFIG;
        event[0].value = 0;
        err = write(fd, event, sizeof(event));
        LOGD_IF(err<0, "control__wake, err=%d (%s)", errno,
strerror(errno));
        close(fd);
    }
    return err;
}

/
*****************************************************************************/

static int data__data_open(struct sensors_data_context_t *dev,
native_handle_t* handle)
{
    int i;
    memset(&dev->sensors, 0, sizeof(dev->sensors));

    dev->sensors[ID_A].sensor = SENSOR_TYPE_ACCELEROMETER;

    for (i=0 ; i<MAX_NUM_SENSORS ; i++) {
        // by default all sensors have high accuracy
        // (we do this because we don't get an update if the value
doesn't
        // change).
        dev->sensors[i].vector.status = SENSOR_STATUS_ACCURACY_HIGH;
    }
    dev->pendingSensors = 0;
    dev->events_fd = dup(handle->data[0]);
    //LOGD("data__data_open: fd = %d", handle->data[0]);
    native_handle_close(handle);
    native_handle_delete(handle);
    return 0;
}

static int data__data_close(struct sensors_data_context_t *dev)
{
    if (dev->events_fd > 0) {
        //LOGD("(data close) about to close fd=%d", dev->events_fd);
        close(dev->events_fd);
        dev->events_fd = -1;
    }
    return 0;
}

static int pick_sensor(struct sensors_data_context_t *dev,
        sensors_data_t* values)
{
    uint32_t mask = SUPPORTED_SENSORS;
    while (mask) {
        uint32_t i = 31 - __builtin_clz(mask);
        mask &= ~(1<<i);
        if (dev->pendingSensors & (1<<i)) {
            dev->pendingSensors &= ~(1<<i);
            *values = dev->sensors[i];
            values->sensor = (1<<i);
            LOGD_IF(0, "%d [%f, %f, %f]", (1<<i),
                    values->vector.x,
                    values->vector.y,
                    values->vector.z);
            return i;
        }
    }
    LOGE("No sensor to return!!! pendingSensors=%08x", dev-
>pendingSensors);
    // we may end-up in a busy loop, slow things down, just in case.
    usleep(100000);
    return -1;
}

static int data__poll(struct sensors_data_context_t *dev,
sensors_data_t* values)
{
    int fd = dev->events_fd;
    if (fd < 0) {
        LOGE("invalid file descriptor, fd=%d", fd);
        return -1;
    }

    // there are pending sensors, returns them now...
    if (dev->pendingSensors) {
        return pick_sensor(dev, values);
    }

    // wait until we get a complete event for an enabled sensor
    uint32_t new_sensors = 0;
    while (1) {
        /* read the next event */
        struct input_event event;
        int nread = read(fd, &event, sizeof(event));
        if (nread == sizeof(event)) {
            uint32_t v;
            if (event.type == EV_ABS) {
                //LOGD("type: %d code: %d value: %-5d time: %ds",
                //        event.type, event.code, event.value,
                //      (int)event.time.tv_sec);
                switch (event.code) {
                    case ABS_X:
                        new_sensors |= SENSORS_ACCELERATION;
                        x = (float)event.value / 64.0f;
                        if(x >= 1)
                            x = 0.999f;
                        if(x <= -1)
                            x = -0.999f;
                        dev->sensors[ID_A].acceleration.y = -x *
9.81f;
                        break;
                    case ABS_Y:
                        new_sensors |= SENSORS_ACCELERATION;
                        y = (float)event.value / 64.0f;
                        if(y >= 1)
                            y = 0.999;
                        if(y <= -1)
                            y = -0.999;
                        dev->sensors[ID_A].acceleration.x = y * 9.81f;
                        break;
                    case ABS_Z:
                        new_sensors |= SENSORS_ACCELERATION;
                        z = (float)event.value / 64.0f;
                        if(z >= 1)
                            z = 0.999f;
                        if(z <= -1)
                            z = -0.999f;
                        dev->sensors[ID_A].acceleration.z = -z *
9.81f;
                        break;
                }
            } else if (event.type == EV_SYN) {
                if (event.code == SYN_CONFIG) {
                    // we use SYN_CONFIG to signal that we need to
exit the
                    // main loop.
                    //LOGD("got empty message: value=%d",
event.value);
                    return 0x7FFFFFFF;
                }
                if (new_sensors) {
                    dev->pendingSensors = new_sensors;
                    int64_t t = event.time.tv_sec*1000000000LL +
                            event.time.tv_usec*1000;
                    while (new_sensors) {
                        uint32_t i = 31 - __builtin_clz(new_sensors);
                        new_sensors &= ~(1<<i);
                        dev->sensors[i].time = t;
                    }
                    return pick_sensor(dev, values);
                }
            }
        }
    }
}

/
*****************************************************************************/

static int control__close(struct hw_device_t *dev)
{
    struct sensors_control_context_t* ctx = (struct
sensors_control_context_t*)dev;
    if (ctx) {
        if (ctx->acceld_fd > 0)
            close(ctx->acceld_fd);
        free(ctx);
    }
    return 0;
}

static int data__close(struct hw_device_t *dev)
{
    struct sensors_data_context_t* ctx = (struct
sensors_data_context_t*)dev;
    if (ctx) {
        if (ctx->events_fd > 0) {
            //LOGD("(device close) about to close fd=%d", ctx-
>events_fd);
            close(ctx->events_fd);
        }
        free(ctx);
    }
    return 0;
}


/** Open a new instance of a sensor device using name */
static int open_sensors(const struct hw_module_t* module, const char*
name,
        struct hw_device_t** device)
{
    int status = -EINVAL;
    if (!strcmp(name, SENSORS_HARDWARE_CONTROL)) {
        struct sensors_control_context_t *dev;
        dev = malloc(sizeof(*dev));
        memset(dev, 0, sizeof(*dev));
        dev->acceld_fd = -1;
        dev->device.common.tag = HARDWARE_DEVICE_TAG;
        dev->device.common.version = 0;
        dev->device.common.module = module;
        dev->device.common.close = control__close;
        dev->device.open_data_source = control__open_data_source;
        dev->device.activate = control__activate;
        dev->device.set_delay= control__set_delay;
        dev->device.wake = control__wake;
        *device = &dev->device.common;
    } else if (!strcmp(name, SENSORS_HARDWARE_DATA)) {
        struct sensors_data_context_t *dev;
        dev = malloc(sizeof(*dev));
        memset(dev, 0, sizeof(*dev));
        dev->events_fd = -1;
        dev->device.common.tag = HARDWARE_DEVICE_TAG;
        dev->device.common.version = 0;
        dev->device.common.module = module;
        dev->device.common.close = data__close;
        dev->device.data_open = data__data_open;
        dev->device.data_close = data__data_close;
        dev->device.poll = data__poll;
        *device = &dev->device.common;
    }
    return status;
}


On Sep 20, 10:19 am, Dianne Hackborn <[email protected]> wrote:
> The default value of android:screenOrientation allows an app to rotate.
>
> The apps in AOSP are the same code as ships on devices.  (At least stock
> devices like Nexus One and Droid).  They work correctly.
>
>
>
> On Mon, Sep 20, 2010 at 7:52 AM, cneth <[email protected]> wrote:
> > Unless somethings changed very recently, I don't believe the AOSP
> > versions of the default apps have the correct manifest attributes to
> > actually use the sensor.   (i.e. they are missing the
> > android:screenOrientation="sensor" annotation - in fact I just looked
> > at launcher and it specifies nosensor.   Browser does not specify
> > anything about the sensors).
>
> > You have to modify the manifests appropriately yourself.
>
> > Craig
>
> > On Sep 20, 2:37 am, Dianne Hackborn <[email protected]> wrote:
> > > Android has done this since 1.0.  As long as your sensors are working
> > (and
> > > that means reporting good data up through the Java APIs) and you haven't
> > > done anything to turn off rotation (such as reporting a lid open and
> > > configuring that to force a particular rotation), then it will
> > automatically
> > > rotate based on sensors.  Prior to Froyo there are two rotations
> > supported;
> > > as of Froyo 3 are supported (everything except upside down).
>
> > > On Sun, Sep 19, 2010 at 7:04 PM, G2 <[email protected]> wrote:
> > > > Hello,
>
> > > > I wrote a separated thread during the summer about this but I start a
> > > > new one as it has been messed up with another discussion.
>
> > > > We are trying to add rotation of screen based on accelerometer in our
> > > > Android eclair 2.1 device. Kernel driver is working fine and I have
> > > > eventually developed an Android hal sensors driver (based on hardware/
> > > > libhardware/modules/sensors/).
>
> > > > For instance, the application:
>
> > > >http://www.ibm.com/developerworks/opensource/library/os-android-senso.
> > ..
> > > > reports correctly the acceleration (not the orientation) of the
> > > > device.
>
> > > > So my naive question is: what now? Where is some support for screen
> > > > rotation in Android? For instance, is the browser or the launcher
> > > > supposed to rotate (landscape/portrait) depending of the screen
> > > > position? In which Android version? Is there any patch (http://
> > > >www.koushikdutta.com/2008/12/auto-rotate-for-android-browser.html) to
> > > > do this?
>
> > > > Thanks for any clarification,
>
> > > > Grégoire
>
> > > > --
> > > > unsubscribe: 
> > > > [email protected]<android-porting%[email protected]>
> > <android-porting%[email protected]<android-porting%[email protected]>
>
> > > > website:http://groups.google.com/group/android-porting
>
> > > --
> > > Dianne Hackborn
> > > Android framework engineer
> > > [email protected]
>
> > > Note: please don't send private questions to me, as I don't have time to
> > > provide private support, and so won't reply to such e-mails.  All such
> > > questions should be posted on public forums, where I and others can see
> > and
> > > answer them.
>
> > --
> > unsubscribe: 
> > [email protected]<android-porting%[email protected]>
> > website:http://groups.google.com/group/android-porting
>
> --
> Dianne Hackborn
> Android framework engineer
> [email protected]
>
> Note: please don't send private questions to me, as I don't have time to
> provide private support, and so won't reply to such e-mails.  All such
> questions should be posted on public forums, where I and others can see and
> answer them.

-- 
unsubscribe: [email protected]
website: http://groups.google.com/group/android-porting

Reply via email to