Index: content/browser/sensors/provider_impl.cc |
diff --git a/content/browser/sensors/provider_impl.cc b/content/browser/sensors/provider_impl.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..2777fb5e1802aae38dbae93358eac1e9305f1aa0 |
--- /dev/null |
+++ b/content/browser/sensors/provider_impl.cc |
@@ -0,0 +1,198 @@ |
+// Copyright (c) 2011 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "base/file_util.h" |
+#include "base/logging.h" |
+#include "base/memory/singleton.h" |
+#include "base/string_util.h" |
+#include "base/stringprintf.h" |
+#include "content/browser/sensors/provider_impl.h" |
+ |
+#include <vector> |
+ |
+#include <fcntl.h> |
+#include <unistd.h> |
+ |
+// TODO: The thread safety varies from tolerable (normal operation) to |
+// non-existent (delete). Need to fix that. |
+ |
+namespace sensors { |
+ |
+class ConnectionImpl : public Connection { |
+ public: |
+ ConnectionImpl(ProviderImpl* provider, Listener* listener) |
+ : provider_(provider), listener_(listener), |
+ listener_proxy_(base::MessageLoopProxy::CreateForCurrentThread()) { |
+ } |
+ |
+ virtual void Start(Channel channel, const std::string& data) { |
+ provider_->ConnectionStarted(this, channel, data); |
+ } |
+ |
+ virtual void Stop(Channel channel) { |
+ provider_->ConnectionStopped(this, channel); |
+ } |
+ |
+ virtual void Close() { |
+ provider_->ConnectionClosed(this); |
+ listener_ = NULL; |
+ } |
+ |
+ virtual void FireSensorChanged(Channel channel, const std::string& data) { |
+ if (!listener_proxy_->BelongsToCurrentThread()) { |
+ listener_proxy_->PostTask(FROM_HERE, NewRunnableMethod( |
+ this, &ConnectionImpl::FireSensorChanged, channel, data)); |
+ return; |
+ } |
+ |
+ if (listener_) |
+ listener_->SensorChanged(channel, data); |
+ } |
+ |
+ private: |
+ ProviderImpl* provider_; |
+ Listener* listener_; |
+ scoped_refptr<base::MessageLoopProxy> listener_proxy_; |
+}; |
+ |
+ProviderImpl* ProviderImpl::GetInstance() { |
+ return Singleton<ProviderImpl>::get(); |
+} |
+ |
+ProviderImpl::ProviderImpl() |
+ : device_fd_(-1), |
+ device_buf_end_(0) { |
+ base::Thread* thread = new base::Thread("sensor provider"); |
+ thread->Start(); |
+ |
+ device_proxy_ = thread->message_loop_proxy(); |
+ |
+ device_proxy_->PostTask(FROM_HERE, |
+ NewRunnableMethod(this, &ProviderImpl::DeviceStart)); |
+} |
+ |
+ProviderImpl::~ProviderImpl() { |
+ DCHECK(device_fd_ == -1); |
+} |
+ |
+Connection* ProviderImpl::Open(Listener* listener) { |
+ ConnectionImpl* conn = new ConnectionImpl(this, listener); |
+ connections_.AddObserver(conn); |
+ return conn; |
+} |
+ |
+void ProviderImpl::FireSensorChanged(Channel channel, const std::string& data) { |
+ FOR_EACH_OBSERVER(ConnectionImpl, connections_, FireSensorChanged(channel, data)); |
+} |
+ |
+void ProviderImpl::DeviceStart() { |
+ DCHECK(device_proxy_->BelongsToCurrentThread()); |
+ |
+ static const char* kDeviceEventPath = "/dev/device0:event0"; |
+ static const char* kEnableEventPath = |
+ "/sys/bus/iio/devices/device0:event0/tilt_change_en"; |
Jói
2011/06/30 19:50:50
This seems device-dependent, or at least POSIX-spe
|
+ |
+ int ret; |
+ |
+ int fd = open(kDeviceEventPath, O_RDONLY, 0); |
+ if (fd < 0) { |
+ LOG(ERROR) << "Failed to open accelerometer: " << strerror(errno); |
+ LOG(ERROR) << "Orientation will be unavailable until Chrome is restarted."; |
+ return; |
+ } |
+ |
+ ret = file_util::WriteFile(FilePath(kEnableEventPath), "1\n", 2); |
+ if (ret < 0) { |
+ LOG(ERROR) << "Failed to enable accelerometer: " << strerror(errno); |
+ LOG(ERROR) << "Orientation will be unavailable until Chrome is restarted."; |
+ return; |
+ } |
+ |
+ device_fd_ = fd; |
+ device_proxy_->PostDelayedTask(FROM_HERE, |
+ NewRunnableMethod(this, &ProviderImpl::DeviceRead), 1000); |
+} |
+ |
+struct iio_event { |
+ uint32 code; |
+ uint32 unused; |
+ uint64 time; |
+}; |
+ |
+void ProviderImpl::DeviceRead() { |
+ DCHECK(device_proxy_->BelongsToCurrentThread()); |
+ |
+ if (!DoDeviceRead()) { |
+ LOG(ERROR) << "Orientation will be unavailable until Chrome is restarted."; |
+ return; |
+ } |
+ |
+ device_proxy_->PostTask(FROM_HERE, |
+ NewRunnableMethod(this, &ProviderImpl::DeviceRead)); |
+} |
+ |
+bool ProviderImpl::DoDeviceRead() { |
+ DCHECK(device_proxy_->BelongsToCurrentThread()); |
+ DCHECK(device_fd_ != -1); |
+ |
+ ssize_t rv = read(device_fd_, device_buf_ + device_buf_end_, |
+ sizeof(device_buf_) - device_buf_end_); |
+ if (rv < 0) { |
+ if (errno == EAGAIN || errno == EWOULDBLOCK) |
+ return true; // Do not have any data to read |
+ |
+ LOG(ERROR) << "Failed to read accelerometer events: " << strerror(errno); |
+ return false; |
+ } |
+ device_buf_end_ += rv; |
+ |
+ if (device_buf_end_ < kIIOMessageSize) |
+ return true; // Do not have a complete message yet |
+ |
+ device_buf_end_ = 0; |
+ |
+ struct iio_event* event = reinterpret_cast<struct iio_event*>(device_buf_); |
+ |
+ // HACK: These orientations are rearranged from their definitions in the |
+ // accelerometer driver so that the development devices report their |
+ // orientation correctly. This will eventually be configured in the |
+ // sensor manager, and the data received by Chrome will be correct. |
+ ScreenOrientationChange change; |
+ switch (event->code >> 8) { |
+ case 0: change.upward = ScreenOrientationChange::TOP; break; |
+ case 1: change.upward = ScreenOrientationChange::BOTTOM; break; |
+ case 2: change.upward = ScreenOrientationChange::RIGHT; break; |
+ case 3: change.upward = ScreenOrientationChange::LEFT; break; |
+ case 4: change.upward = ScreenOrientationChange::FRONT; break; |
+ case 5: change.upward = ScreenOrientationChange::BACK; break; |
+ default: return true; // drop unknown orientation |
+ } |
+ |
+ std::string data(reinterpret_cast<const char*>(&change), sizeof(change)); |
+ FireSensorChanged(kScreenOrientationChannel, data); |
+ return true; |
+} |
+ |
+void ProviderImpl::DeviceStop() { |
+ DCHECK(device_proxy_->BelongsToCurrentThread()); |
+ |
+ close(device_fd_); |
+ device_fd_ = -1; |
+} |
+ |
+void ProviderImpl::ConnectionClosed(ConnectionImpl* conn) { |
+ connections_.RemoveObserver(conn); |
+} |
+ |
+void ProviderImpl::ConnectionStarted(ConnectionImpl* conn, |
+ Channel channel, const std::string& data) { |
+ |
+ connections_.AddObserver(conn); |
+} |
+ |
+void ProviderImpl::ConnectionStopped(ConnectionImpl* conn, Channel channel) { |
+ connections_.RemoveObserver(conn); |
+} |
+ |
+} // namespace sensors |