diff options
Diffstat (limited to 'hal/gonk/GonkSensor.cpp')
-rw-r--r-- | hal/gonk/GonkSensor.cpp | 861 |
1 files changed, 861 insertions, 0 deletions
diff --git a/hal/gonk/GonkSensor.cpp b/hal/gonk/GonkSensor.cpp new file mode 100644 index 0000000000..7bd2d3c9bf --- /dev/null +++ b/hal/gonk/GonkSensor.cpp @@ -0,0 +1,861 @@ +/* -*- 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 "mozilla/Saturate.h" + +#include "base/basictypes.h" +#include "base/thread.h" +#include "base/task.h" + +#include "GonkSensorsInterface.h" +#include "GonkSensorsPollInterface.h" +#include "GonkSensorsRegistryInterface.h" +#include "Hal.h" +#include "HalLog.h" +#include "HalSensor.h" +#include "hardware/sensors.h" +#include "nsThreadUtils.h" + +using namespace mozilla::hal; + +namespace mozilla { + +// +// Internal implementation +// + +// 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 Runnable +{ +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() override + { + NotifySensorChange(mSensorData); + return NS_OK; + } + +private: + SensorData mSensorData; + AutoTArray<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; + } + } +} + +static void +EnableSensorNotificationsInternal(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( + NewRunnableFunction(PollSensors)); + } + + SetSensorState(aSensor, true); +} + +static void +DisableSensorNotificationsInternal(SensorType aSensor) +{ + if (!sSensorModule) { + return; + } + SetSensorState(aSensor, false); +} + +// +// Daemon +// + +typedef detail::SaturateOp<uint32_t> SaturateOpUint32; + +/** + * The poll notification handler receives all events about sensors and + * sensor events. + */ +class SensorsPollNotificationHandler final + : public GonkSensorsPollNotificationHandler +{ +public: + SensorsPollNotificationHandler(GonkSensorsPollInterface* aPollInterface) + : mPollInterface(aPollInterface) + { + MOZ_ASSERT(mPollInterface); + + mPollInterface->SetNotificationHandler(this); + } + + void EnableSensorsByType(SensorsType aType) + { + if (SaturateOpUint32(mClasses[aType].mActivated)++) { + return; + } + + SensorsDeliveryMode deliveryMode = DefaultSensorsDeliveryMode(aType); + + // Old ref-count for the sensor type was 0, so we + // activate all sensors of the type. + for (size_t i = 0; i < mSensors.Length(); ++i) { + if (mSensors[i].mType == aType && + mSensors[i].mDeliveryMode == deliveryMode) { + mPollInterface->EnableSensor(mSensors[i].mId, nullptr); + mPollInterface->SetPeriod(mSensors[i].mId, DefaultSensorPeriod(aType), + nullptr); + } + } + } + + void DisableSensorsByType(SensorsType aType) + { + if (SaturateOpUint32(mClasses[aType].mActivated)-- != 1) { + return; + } + + SensorsDeliveryMode deliveryMode = DefaultSensorsDeliveryMode(aType); + + // Old ref-count for the sensor type was 1, so we + // deactivate all sensors of the type. + for (size_t i = 0; i < mSensors.Length(); ++i) { + if (mSensors[i].mType == aType && + mSensors[i].mDeliveryMode == deliveryMode) { + mPollInterface->DisableSensor(mSensors[i].mId, nullptr); + } + } + } + + void ClearSensorClasses() + { + for (size_t i = 0; i < MOZ_ARRAY_LENGTH(mClasses); ++i) { + mClasses[i] = SensorsSensorClass(); + } + } + + void ClearSensors() + { + mSensors.Clear(); + } + + // Methods for SensorsPollNotificationHandler + // + + void ErrorNotification(SensorsError aError) override + { + // XXX: Bug 1206056: Try to repair some of the errors or restart cleanly. + } + + void SensorDetectedNotification(int32_t aId, SensorsType aType, + float aRange, float aResolution, + float aPower, int32_t aMinPeriod, + int32_t aMaxPeriod, + SensorsTriggerMode aTriggerMode, + SensorsDeliveryMode aDeliveryMode) override + { + auto i = FindSensorIndexById(aId); + if (i == -1) { + // Add a new sensor... + i = mSensors.Length(); + mSensors.AppendElement(SensorsSensor(aId, aType, aRange, aResolution, + aPower, aMinPeriod, aMaxPeriod, + aTriggerMode, aDeliveryMode)); + } else { + // ...or update an existing one. + mSensors[i] = SensorsSensor(aId, aType, aRange, aResolution, aPower, + aMinPeriod, aMaxPeriod, aTriggerMode, + aDeliveryMode); + } + + mClasses[aType].UpdateFromSensor(mSensors[i]); + + if (mClasses[aType].mActivated && + mSensors[i].mDeliveryMode == DefaultSensorsDeliveryMode(aType)) { + // The new sensor's type is enabled, so enable sensor. + mPollInterface->EnableSensor(aId, nullptr); + mPollInterface->SetPeriod(mSensors[i].mId, DefaultSensorPeriod(aType), + nullptr); + } + } + + void SensorLostNotification(int32_t aId) override + { + auto i = FindSensorIndexById(aId); + if (i != -1) { + mSensors.RemoveElementAt(i); + } + } + + void EventNotification(int32_t aId, const SensorsEvent& aEvent) override + { + auto i = FindSensorIndexById(aId); + if (i == -1) { + HAL_ERR("Sensor %d not registered", aId); + return; + } + + SensorData sensorData; + auto rv = CreateSensorData(aEvent, mClasses[mSensors[i].mType], + sensorData); + if (NS_FAILED(rv)) { + return; + } + + NotifySensorChange(sensorData); + } + +private: + ssize_t FindSensorIndexById(int32_t aId) const + { + for (size_t i = 0; i < mSensors.Length(); ++i) { + if (mSensors[i].mId == aId) { + return i; + } + } + return -1; + } + + uint64_t DefaultSensorPeriod(SensorsType aType) const + { + return aType == SENSORS_TYPE_ACCELEROMETER ? ACCELEROMETER_POLL_RATE + : DEFAULT_DEVICE_POLL_RATE; + } + + SensorsDeliveryMode DefaultSensorsDeliveryMode(SensorsType aType) const + { + if (aType == SENSORS_TYPE_PROXIMITY || + aType == SENSORS_TYPE_SIGNIFICANT_MOTION) { + return SENSORS_DELIVERY_MODE_IMMEDIATE; + } + return SENSORS_DELIVERY_MODE_BEST_EFFORT; + } + + SensorType HardwareSensorToHalSensor(SensorsType aType) const + { + // FIXME: bug 802004, add proper support for the magnetic-field sensor. + switch (aType) { + case SENSORS_TYPE_ORIENTATION: + return SENSOR_ORIENTATION; + case SENSORS_TYPE_ACCELEROMETER: + return SENSOR_ACCELERATION; + case SENSORS_TYPE_PROXIMITY: + return SENSOR_PROXIMITY; + case SENSORS_TYPE_LIGHT: + return SENSOR_LIGHT; + case SENSORS_TYPE_GYROSCOPE: + return SENSOR_GYROSCOPE; + case SENSORS_TYPE_LINEAR_ACCELERATION: + return SENSOR_LINEAR_ACCELERATION; + case SENSORS_TYPE_ROTATION_VECTOR: + return SENSOR_ROTATION_VECTOR; + case SENSORS_TYPE_GAME_ROTATION_VECTOR: + return SENSOR_GAME_ROTATION_VECTOR; + default: + NS_NOTREACHED("Invalid sensors type"); + } + return SENSOR_UNKNOWN; + } + + SensorAccuracyType HardwareStatusToHalAccuracy(SensorsStatus aStatus) const + { + return static_cast<SensorAccuracyType>(aStatus - 1); + } + + nsresult CreateSensorData(const SensorsEvent& aEvent, + const SensorsSensorClass& aSensorClass, + SensorData& aSensorData) const + { + AutoTArray<float, 4> sensorValues; + + auto sensor = HardwareSensorToHalSensor(aEvent.mType); + + if (sensor == SENSOR_UNKNOWN) { + return NS_ERROR_ILLEGAL_VALUE; + } + + aSensorData.sensor() = sensor; + aSensorData.accuracy() = HardwareStatusToHalAccuracy(aEvent.mStatus); + aSensorData.timestamp() = aEvent.mTimestamp; + + if (aSensorData.sensor() == SENSOR_ORIENTATION) { + // 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 + sensorValues.AppendElement(360.0 - radToDeg(aEvent.mData.mFloat[0])); + sensorValues.AppendElement(-radToDeg(aEvent.mData.mFloat[1])); + sensorValues.AppendElement(-radToDeg(aEvent.mData.mFloat[2])); + } else if (aSensorData.sensor() == SENSOR_ACCELERATION) { + sensorValues.AppendElement(aEvent.mData.mFloat[0]); + sensorValues.AppendElement(aEvent.mData.mFloat[1]); + sensorValues.AppendElement(aEvent.mData.mFloat[2]); + } else if (aSensorData.sensor() == SENSOR_PROXIMITY) { + sensorValues.AppendElement(aEvent.mData.mFloat[0]); + sensorValues.AppendElement(aSensorClass.mMinValue); + sensorValues.AppendElement(aSensorClass.mMaxValue); + } else if (aSensorData.sensor() == SENSOR_LINEAR_ACCELERATION) { + sensorValues.AppendElement(aEvent.mData.mFloat[0]); + sensorValues.AppendElement(aEvent.mData.mFloat[1]); + sensorValues.AppendElement(aEvent.mData.mFloat[2]); + } else if (aSensorData.sensor() == SENSOR_GYROSCOPE) { + sensorValues.AppendElement(radToDeg(aEvent.mData.mFloat[0])); + sensorValues.AppendElement(radToDeg(aEvent.mData.mFloat[1])); + sensorValues.AppendElement(radToDeg(aEvent.mData.mFloat[2])); + } else if (aSensorData.sensor() == SENSOR_LIGHT) { + sensorValues.AppendElement(aEvent.mData.mFloat[0]); + } else if (aSensorData.sensor() == SENSOR_ROTATION_VECTOR) { + sensorValues.AppendElement(aEvent.mData.mFloat[0]); + sensorValues.AppendElement(aEvent.mData.mFloat[1]); + sensorValues.AppendElement(aEvent.mData.mFloat[2]); + sensorValues.AppendElement(aEvent.mData.mFloat[3]); + } else if (aSensorData.sensor() == SENSOR_GAME_ROTATION_VECTOR) { + sensorValues.AppendElement(aEvent.mData.mFloat[0]); + sensorValues.AppendElement(aEvent.mData.mFloat[1]); + sensorValues.AppendElement(aEvent.mData.mFloat[2]); + sensorValues.AppendElement(aEvent.mData.mFloat[3]); + } + + aSensorData.values() = sensorValues; + + return NS_OK; + } + + GonkSensorsPollInterface* mPollInterface; + nsTArray<SensorsSensor> mSensors; + SensorsSensorClass mClasses[SENSORS_NUM_TYPES]; +}; + +static StaticAutoPtr<SensorsPollNotificationHandler> sPollNotificationHandler; + +/** + * This is the notifiaction handler for the Sensors interface. If the backend + * crashes, we can restart it from here. + */ +class SensorsNotificationHandler final : public GonkSensorsNotificationHandler +{ +public: + SensorsNotificationHandler(GonkSensorsInterface* aInterface) + : mInterface(aInterface) + { + MOZ_ASSERT(mInterface); + + mInterface->SetNotificationHandler(this); + } + + void BackendErrorNotification(bool aCrashed) override + { + // XXX: Bug 1206056: restart sensorsd + } + +private: + GonkSensorsInterface* mInterface; +}; + +static StaticAutoPtr<SensorsNotificationHandler> sNotificationHandler; + +/** + * |SensorsRegisterModuleResultHandler| implements the result-handler + * callback for registering the Poll service and activating the first + * sensors. If an error occures during the process, the result handler + * disconnects and closes the backend. + */ +class SensorsRegisterModuleResultHandler final + : public GonkSensorsRegistryResultHandler +{ +public: + SensorsRegisterModuleResultHandler( + uint32_t* aSensorsTypeActivated, + GonkSensorsInterface* aInterface) + : mSensorsTypeActivated(aSensorsTypeActivated) + , mInterface(aInterface) + { + MOZ_ASSERT(mSensorsTypeActivated); + MOZ_ASSERT(mInterface); + } + void OnError(SensorsError aError) override + { + GonkSensorsRegistryResultHandler::OnError(aError); // print error message + Disconnect(); // Registering failed, so close the connection completely + } + void RegisterModule(uint32_t aProtocolVersion) override + { + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(!sPollNotificationHandler); + + // Init, step 3: set notification handler for poll service and vice versa + auto pollInterface = mInterface->GetSensorsPollInterface(); + if (!pollInterface) { + Disconnect(); + return; + } + if (NS_FAILED(pollInterface->SetProtocolVersion(aProtocolVersion))) { + Disconnect(); + return; + } + + sPollNotificationHandler = + new SensorsPollNotificationHandler(pollInterface); + + // Init, step 4: activate sensors + for (int i = 0; i < SENSORS_NUM_TYPES; ++i) { + while (mSensorsTypeActivated[i]) { + sPollNotificationHandler->EnableSensorsByType( + static_cast<SensorsType>(i)); + --mSensorsTypeActivated[i]; + } + } + } +public: + void Disconnect() + { + class DisconnectResultHandler final : public GonkSensorsResultHandler + { + public: + void OnError(SensorsError aError) + { + GonkSensorsResultHandler::OnError(aError); // print error message + sNotificationHandler = nullptr; + } + void Disconnect() override + { + sNotificationHandler = nullptr; + } + }; + mInterface->Disconnect(new DisconnectResultHandler()); + } +private: + uint32_t* mSensorsTypeActivated; + GonkSensorsInterface* mInterface; +}; + +/** + * |SensorsConnectResultHandler| implements the result-handler + * callback for starting the Sensors backend. + */ +class SensorsConnectResultHandler final : public GonkSensorsResultHandler +{ +public: + SensorsConnectResultHandler( + uint32_t* aSensorsTypeActivated, + GonkSensorsInterface* aInterface) + : mSensorsTypeActivated(aSensorsTypeActivated) + , mInterface(aInterface) + { + MOZ_ASSERT(mSensorsTypeActivated); + MOZ_ASSERT(mInterface); + } + void OnError(SensorsError aError) override + { + GonkSensorsResultHandler::OnError(aError); // print error message + sNotificationHandler = nullptr; + } + void Connect() override + { + MOZ_ASSERT(NS_IsMainThread()); + + // Init, step 2: register poll service + auto registryInterface = mInterface->GetSensorsRegistryInterface(); + if (!registryInterface) { + return; + } + registryInterface->RegisterModule( + GonkSensorsPollModule::SERVICE_ID, + new SensorsRegisterModuleResultHandler(mSensorsTypeActivated, + mInterface)); + } +private: + uint32_t* mSensorsTypeActivated; + GonkSensorsInterface* mInterface; +}; + +static uint32_t sSensorsTypeActivated[SENSORS_NUM_TYPES]; + +static const SensorsType sSensorsType[] = { + [SENSOR_ORIENTATION] = SENSORS_TYPE_ORIENTATION, + [SENSOR_ACCELERATION] = SENSORS_TYPE_ACCELEROMETER, + [SENSOR_PROXIMITY] = SENSORS_TYPE_PROXIMITY, + [SENSOR_LINEAR_ACCELERATION] = SENSORS_TYPE_LINEAR_ACCELERATION, + [SENSOR_GYROSCOPE] = SENSORS_TYPE_GYROSCOPE, + [SENSOR_LIGHT] = SENSORS_TYPE_LIGHT, + [SENSOR_ROTATION_VECTOR] = SENSORS_TYPE_ROTATION_VECTOR, + [SENSOR_GAME_ROTATION_VECTOR] = SENSORS_TYPE_GAME_ROTATION_VECTOR +}; + +void +EnableSensorNotificationsDaemon(SensorType aSensor) +{ + if ((aSensor < 0) || + (aSensor > static_cast<ssize_t>(MOZ_ARRAY_LENGTH(sSensorsType)))) { + HAL_ERR("Sensor type %d not known", aSensor); + return; // Unsupported sensor type + } + + auto interface = GonkSensorsInterface::GetInstance(); + if (!interface) { + return; + } + + if (sPollNotificationHandler) { + // Everythings already up and running; enable sensor type. + sPollNotificationHandler->EnableSensorsByType(sSensorsType[aSensor]); + return; + } + + ++SaturateOpUint32(sSensorsTypeActivated[sSensorsType[aSensor]]); + + if (sNotificationHandler) { + // We are in the middle of a pending start up; nothing else to do. + return; + } + + // Start up + + MOZ_ASSERT(!sPollNotificationHandler); + MOZ_ASSERT(!sNotificationHandler); + + sNotificationHandler = new SensorsNotificationHandler(interface); + + // Init, step 1: connect to Sensors backend + interface->Connect( + sNotificationHandler, + new SensorsConnectResultHandler(sSensorsTypeActivated, interface)); +} + +void +DisableSensorNotificationsDaemon(SensorType aSensor) +{ + if ((aSensor < 0) || + (aSensor > static_cast<ssize_t>(MOZ_ARRAY_LENGTH(sSensorsType)))) { + HAL_ERR("Sensor type %d not known", aSensor); + return; // Unsupported sensor type + } + + if (sPollNotificationHandler) { + // Everthings up and running; disable sensors type + sPollNotificationHandler->DisableSensorsByType(sSensorsType[aSensor]); + return; + } + + // We might be in the middle of a startup; decrement type's ref-counter. + --SaturateOpUint32(sSensorsTypeActivated[sSensorsType[aSensor]]); + + // TODO: stop sensorsd if all sensors are disabled +} + +// +// Public interface +// + +// TODO: Remove in-Gecko sensors code. Until all devices' base +// images come with sensorsd installed, we have to support the +// in-Gecko implementation as well. So we test for the existance +// of the binary. If it's there, we use it. Otherwise we run the +// old code. +static bool +HasDaemon() +{ + static bool tested; + static bool hasDaemon; + + if (MOZ_UNLIKELY(!tested)) { + hasDaemon = !access("/system/bin/sensorsd", X_OK); + tested = true; + } + + return hasDaemon; +} + +void +EnableSensorNotifications(SensorType aSensor) +{ + if (HasDaemon()) { + EnableSensorNotificationsDaemon(aSensor); + } else { + EnableSensorNotificationsInternal(aSensor); + } +} + +void +DisableSensorNotifications(SensorType aSensor) +{ + if (HasDaemon()) { + DisableSensorNotificationsDaemon(aSensor); + } else { + DisableSensorNotificationsInternal(aSensor); + } +} + +} // hal_impl +} // mozilla |