mirror of
https://github.com/classilla/tenfourfox.git
synced 2024-09-11 02:56:06 +00:00
336 lines
10 KiB
C++
336 lines
10 KiB
C++
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/* Copyright 2012 Mozilla Foundation and Mozilla contributors
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#include <pthread.h>
|
|
#include <stdio.h>
|
|
|
|
#include "mozilla/DebugOnly.h"
|
|
|
|
#include "base/basictypes.h"
|
|
#include "base/thread.h"
|
|
|
|
#include "Hal.h"
|
|
#include "HalLog.h"
|
|
#include "HalSensor.h"
|
|
#include "hardware/sensors.h"
|
|
#include "nsThreadUtils.h"
|
|
|
|
using namespace mozilla::hal;
|
|
|
|
namespace mozilla {
|
|
|
|
// The value from SensorDevice.h (Android)
|
|
#define DEFAULT_DEVICE_POLL_RATE 200000000 /*200ms*/
|
|
// ProcessOrientation.cpp needs smaller poll rate to detect delay between
|
|
// different orientation angles
|
|
#define ACCELEROMETER_POLL_RATE 66667000 /*66.667ms*/
|
|
|
|
// This is present in Android from API level 18 onwards, which is 4.3. We might
|
|
// be building on something before 4.3, so use a local define for its value
|
|
#define MOZ_SENSOR_TYPE_GAME_ROTATION_VECTOR 15
|
|
|
|
double radToDeg(double a) {
|
|
return a * (180.0 / M_PI);
|
|
}
|
|
|
|
static SensorType
|
|
HardwareSensorToHalSensor(int type)
|
|
{
|
|
switch(type) {
|
|
case SENSOR_TYPE_ORIENTATION:
|
|
return SENSOR_ORIENTATION;
|
|
case SENSOR_TYPE_ACCELEROMETER:
|
|
return SENSOR_ACCELERATION;
|
|
case SENSOR_TYPE_PROXIMITY:
|
|
return SENSOR_PROXIMITY;
|
|
case SENSOR_TYPE_LIGHT:
|
|
return SENSOR_LIGHT;
|
|
case SENSOR_TYPE_GYROSCOPE:
|
|
return SENSOR_GYROSCOPE;
|
|
case SENSOR_TYPE_LINEAR_ACCELERATION:
|
|
return SENSOR_LINEAR_ACCELERATION;
|
|
case SENSOR_TYPE_ROTATION_VECTOR:
|
|
return SENSOR_ROTATION_VECTOR;
|
|
case MOZ_SENSOR_TYPE_GAME_ROTATION_VECTOR:
|
|
return SENSOR_GAME_ROTATION_VECTOR;
|
|
default:
|
|
return SENSOR_UNKNOWN;
|
|
}
|
|
}
|
|
|
|
static SensorAccuracyType
|
|
HardwareStatusToHalAccuracy(int status) {
|
|
return static_cast<SensorAccuracyType>(status);
|
|
}
|
|
|
|
static int
|
|
HalSensorToHardwareSensor(SensorType type)
|
|
{
|
|
switch(type) {
|
|
case SENSOR_ORIENTATION:
|
|
return SENSOR_TYPE_ORIENTATION;
|
|
case SENSOR_ACCELERATION:
|
|
return SENSOR_TYPE_ACCELEROMETER;
|
|
case SENSOR_PROXIMITY:
|
|
return SENSOR_TYPE_PROXIMITY;
|
|
case SENSOR_LIGHT:
|
|
return SENSOR_TYPE_LIGHT;
|
|
case SENSOR_GYROSCOPE:
|
|
return SENSOR_TYPE_GYROSCOPE;
|
|
case SENSOR_LINEAR_ACCELERATION:
|
|
return SENSOR_TYPE_LINEAR_ACCELERATION;
|
|
case SENSOR_ROTATION_VECTOR:
|
|
return SENSOR_TYPE_ROTATION_VECTOR;
|
|
case SENSOR_GAME_ROTATION_VECTOR:
|
|
return MOZ_SENSOR_TYPE_GAME_ROTATION_VECTOR;
|
|
default:
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
static int
|
|
SensorseventStatus(const sensors_event_t& data)
|
|
{
|
|
int type = data.type;
|
|
switch(type) {
|
|
case SENSOR_ORIENTATION:
|
|
return data.orientation.status;
|
|
case SENSOR_LINEAR_ACCELERATION:
|
|
case SENSOR_ACCELERATION:
|
|
return data.acceleration.status;
|
|
case SENSOR_GYROSCOPE:
|
|
return data.gyro.status;
|
|
}
|
|
|
|
return SENSOR_STATUS_UNRELIABLE;
|
|
}
|
|
|
|
class SensorRunnable : public nsRunnable
|
|
{
|
|
public:
|
|
SensorRunnable(const sensors_event_t& data, const sensor_t* sensors, ssize_t size)
|
|
{
|
|
mSensorData.sensor() = HardwareSensorToHalSensor(data.type);
|
|
mSensorData.accuracy() = HardwareStatusToHalAccuracy(SensorseventStatus(data));
|
|
mSensorData.timestamp() = data.timestamp;
|
|
if (mSensorData.sensor() == SENSOR_GYROSCOPE) {
|
|
// libhardware returns gyro as rad. convert.
|
|
mSensorValues.AppendElement(radToDeg(data.data[0]));
|
|
mSensorValues.AppendElement(radToDeg(data.data[1]));
|
|
mSensorValues.AppendElement(radToDeg(data.data[2]));
|
|
} else if (mSensorData.sensor() == SENSOR_PROXIMITY) {
|
|
mSensorValues.AppendElement(data.data[0]);
|
|
mSensorValues.AppendElement(0);
|
|
|
|
// Determine the maxRange for this sensor.
|
|
for (ssize_t i = 0; i < size; i++) {
|
|
if (sensors[i].type == SENSOR_TYPE_PROXIMITY) {
|
|
mSensorValues.AppendElement(sensors[i].maxRange);
|
|
}
|
|
}
|
|
} else if (mSensorData.sensor() == SENSOR_LIGHT) {
|
|
mSensorValues.AppendElement(data.data[0]);
|
|
} else if (mSensorData.sensor() == SENSOR_ROTATION_VECTOR) {
|
|
mSensorValues.AppendElement(data.data[0]);
|
|
mSensorValues.AppendElement(data.data[1]);
|
|
mSensorValues.AppendElement(data.data[2]);
|
|
if (data.data[3] == 0.0) {
|
|
// data.data[3] was optional in Android <= API level 18. It can be computed from 012,
|
|
// but it's better to take the actual value if one is provided. The computation is
|
|
// v = 1 - d[0]*d[0] - d[1]*d[1] - d[2]*d[2]
|
|
// d[3] = v > 0 ? sqrt(v) : 0;
|
|
// I'm assuming that it will be 0 if it's not passed in. (The values form a unit
|
|
// quaternion, so the angle can be computed from the direction vector.)
|
|
float sx = data.data[0], sy = data.data[1], sz = data.data[2];
|
|
float v = 1.0f - sx*sx - sy*sy - sz*sz;
|
|
mSensorValues.AppendElement(v > 0.0f ? sqrt(v) : 0.0f);
|
|
} else {
|
|
mSensorValues.AppendElement(data.data[3]);
|
|
}
|
|
} else if (mSensorData.sensor() == SENSOR_GAME_ROTATION_VECTOR) {
|
|
mSensorValues.AppendElement(data.data[0]);
|
|
mSensorValues.AppendElement(data.data[1]);
|
|
mSensorValues.AppendElement(data.data[2]);
|
|
mSensorValues.AppendElement(data.data[3]);
|
|
} else {
|
|
mSensorValues.AppendElement(data.data[0]);
|
|
mSensorValues.AppendElement(data.data[1]);
|
|
mSensorValues.AppendElement(data.data[2]);
|
|
}
|
|
mSensorData.values() = mSensorValues;
|
|
}
|
|
|
|
~SensorRunnable() {}
|
|
|
|
NS_IMETHOD Run()
|
|
{
|
|
NotifySensorChange(mSensorData);
|
|
return NS_OK;
|
|
}
|
|
|
|
private:
|
|
SensorData mSensorData;
|
|
nsAutoTArray<float, 4> mSensorValues;
|
|
};
|
|
|
|
namespace hal_impl {
|
|
|
|
static DebugOnly<int> sSensorRefCount[NUM_SENSOR_TYPE];
|
|
static base::Thread* sPollingThread;
|
|
static sensors_poll_device_t* sSensorDevice;
|
|
static sensors_module_t* sSensorModule;
|
|
|
|
static void
|
|
PollSensors()
|
|
{
|
|
const size_t numEventMax = 16;
|
|
sensors_event_t buffer[numEventMax];
|
|
const sensor_t* sensors;
|
|
int size = sSensorModule->get_sensors_list(sSensorModule, &sensors);
|
|
|
|
do {
|
|
// didn't check sSensorDevice because already be done on creating pollingThread.
|
|
int n = sSensorDevice->poll(sSensorDevice, buffer, numEventMax);
|
|
if (n < 0) {
|
|
HAL_ERR("Error polling for sensor data (err=%d)", n);
|
|
break;
|
|
}
|
|
|
|
for (int i = 0; i < n; ++i) {
|
|
// FIXME: bug 802004, add proper support for the magnetic field sensor.
|
|
if (buffer[i].type == SENSOR_TYPE_MAGNETIC_FIELD)
|
|
continue;
|
|
|
|
// Bug 938035, transfer HAL data for orientation sensor to meet w3c spec
|
|
// ex: HAL report alpha=90 means East but alpha=90 means West in w3c spec
|
|
if (buffer[i].type == SENSOR_TYPE_ORIENTATION) {
|
|
buffer[i].orientation.azimuth = 360 - buffer[i].orientation.azimuth;
|
|
buffer[i].orientation.pitch = -buffer[i].orientation.pitch;
|
|
buffer[i].orientation.roll = -buffer[i].orientation.roll;
|
|
}
|
|
|
|
if (HardwareSensorToHalSensor(buffer[i].type) == SENSOR_UNKNOWN) {
|
|
// Emulator is broken and gives us events without types set
|
|
int index;
|
|
for (index = 0; index < size; index++) {
|
|
if (sensors[index].handle == buffer[i].sensor) {
|
|
break;
|
|
}
|
|
}
|
|
if (index < size &&
|
|
HardwareSensorToHalSensor(sensors[index].type) != SENSOR_UNKNOWN) {
|
|
buffer[i].type = sensors[index].type;
|
|
} else {
|
|
HAL_LOG("Could not determine sensor type of event");
|
|
continue;
|
|
}
|
|
}
|
|
|
|
NS_DispatchToMainThread(new SensorRunnable(buffer[i], sensors, size));
|
|
}
|
|
} while (true);
|
|
}
|
|
|
|
static void
|
|
SwitchSensor(bool aActivate, sensor_t aSensor, pthread_t aThreadId)
|
|
{
|
|
int index = HardwareSensorToHalSensor(aSensor.type);
|
|
|
|
MOZ_ASSERT(sSensorRefCount[index] || aActivate);
|
|
|
|
sSensorDevice->activate(sSensorDevice, aSensor.handle, aActivate);
|
|
|
|
if (aActivate) {
|
|
if (aSensor.type == SENSOR_TYPE_ACCELEROMETER) {
|
|
sSensorDevice->setDelay(sSensorDevice, aSensor.handle,
|
|
ACCELEROMETER_POLL_RATE);
|
|
} else {
|
|
sSensorDevice->setDelay(sSensorDevice, aSensor.handle,
|
|
DEFAULT_DEVICE_POLL_RATE);
|
|
}
|
|
}
|
|
|
|
if (aActivate) {
|
|
sSensorRefCount[index]++;
|
|
} else {
|
|
sSensorRefCount[index]--;
|
|
}
|
|
}
|
|
|
|
static void
|
|
SetSensorState(SensorType aSensor, bool activate)
|
|
{
|
|
int type = HalSensorToHardwareSensor(aSensor);
|
|
const sensor_t* sensors = nullptr;
|
|
|
|
int size = sSensorModule->get_sensors_list(sSensorModule, &sensors);
|
|
for (ssize_t i = 0; i < size; i++) {
|
|
if (sensors[i].type == type) {
|
|
SwitchSensor(activate, sensors[i], pthread_self());
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
EnableSensorNotifications(SensorType aSensor)
|
|
{
|
|
if (!sSensorModule) {
|
|
hw_get_module(SENSORS_HARDWARE_MODULE_ID,
|
|
(hw_module_t const**)&sSensorModule);
|
|
if (!sSensorModule) {
|
|
HAL_ERR("Can't get sensor HAL module\n");
|
|
return;
|
|
}
|
|
|
|
sensors_open(&sSensorModule->common, &sSensorDevice);
|
|
if (!sSensorDevice) {
|
|
sSensorModule = nullptr;
|
|
HAL_ERR("Can't get sensor poll device from module \n");
|
|
return;
|
|
}
|
|
|
|
sensor_t const* sensors;
|
|
int count = sSensorModule->get_sensors_list(sSensorModule, &sensors);
|
|
for (size_t i=0 ; i<size_t(count) ; i++) {
|
|
sSensorDevice->activate(sSensorDevice, sensors[i].handle, 0);
|
|
}
|
|
}
|
|
|
|
if (!sPollingThread) {
|
|
sPollingThread = new base::Thread("GonkSensors");
|
|
MOZ_ASSERT(sPollingThread);
|
|
// sPollingThread never terminates because poll may never return
|
|
sPollingThread->Start();
|
|
sPollingThread->message_loop()->PostTask(FROM_HERE,
|
|
NewRunnableFunction(PollSensors));
|
|
}
|
|
|
|
SetSensorState(aSensor, true);
|
|
}
|
|
|
|
void
|
|
DisableSensorNotifications(SensorType aSensor)
|
|
{
|
|
if (!sSensorModule) {
|
|
return;
|
|
}
|
|
SetSensorState(aSensor, false);
|
|
}
|
|
|
|
} // hal_impl
|
|
} // mozilla
|