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
