Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "base/file_util.h" | |
| 6 #include "base/logging.h" | |
| 7 #include "base/memory/singleton.h" | |
| 8 #include "base/string_util.h" | |
| 9 #include "base/stringprintf.h" | |
| 10 #include "content/browser/sensors/provider_impl.h" | |
| 11 | |
| 12 #include <vector> | |
| 13 | |
| 14 #include <fcntl.h> | |
| 15 #include <unistd.h> | |
| 16 | |
| 17 // TODO: The thread safety varies from tolerable (normal operation) to | |
| 18 // non-existent (delete). Need to fix that. | |
| 19 | |
| 20 namespace sensors { | |
| 21 | |
| 22 class ConnectionImpl : public Connection { | |
| 23 public: | |
| 24 ConnectionImpl(ProviderImpl* provider, Listener* listener) | |
| 25 : provider_(provider), listener_(listener), | |
| 26 listener_proxy_(base::MessageLoopProxy::CreateForCurrentThread()) { | |
| 27 } | |
| 28 | |
| 29 virtual void Start(Channel channel, const std::string& data) { | |
| 30 provider_->ConnectionStarted(this, channel, data); | |
| 31 } | |
| 32 | |
| 33 virtual void Stop(Channel channel) { | |
| 34 provider_->ConnectionStopped(this, channel); | |
| 35 } | |
| 36 | |
| 37 virtual void Close() { | |
| 38 provider_->ConnectionClosed(this); | |
| 39 listener_ = NULL; | |
| 40 } | |
| 41 | |
| 42 virtual void FireSensorChanged(Channel channel, const std::string& data) { | |
| 43 if (!listener_proxy_->BelongsToCurrentThread()) { | |
| 44 listener_proxy_->PostTask(FROM_HERE, NewRunnableMethod( | |
| 45 this, &ConnectionImpl::FireSensorChanged, channel, data)); | |
| 46 return; | |
| 47 } | |
| 48 | |
| 49 if (listener_) | |
| 50 listener_->SensorChanged(channel, data); | |
| 51 } | |
| 52 | |
| 53 private: | |
| 54 ProviderImpl* provider_; | |
| 55 Listener* listener_; | |
| 56 scoped_refptr<base::MessageLoopProxy> listener_proxy_; | |
| 57 }; | |
| 58 | |
| 59 ProviderImpl* ProviderImpl::GetInstance() { | |
| 60 return Singleton<ProviderImpl>::get(); | |
| 61 } | |
| 62 | |
| 63 ProviderImpl::ProviderImpl() | |
| 64 : device_fd_(-1), | |
| 65 device_buf_end_(0) { | |
| 66 base::Thread* thread = new base::Thread("sensor provider"); | |
| 67 thread->Start(); | |
| 68 | |
| 69 device_proxy_ = thread->message_loop_proxy(); | |
| 70 | |
| 71 device_proxy_->PostTask(FROM_HERE, | |
| 72 NewRunnableMethod(this, &ProviderImpl::DeviceStart)); | |
| 73 } | |
| 74 | |
| 75 ProviderImpl::~ProviderImpl() { | |
| 76 DCHECK(device_fd_ == -1); | |
| 77 } | |
| 78 | |
| 79 Connection* ProviderImpl::Open(Listener* listener) { | |
| 80 ConnectionImpl* conn = new ConnectionImpl(this, listener); | |
| 81 connections_.AddObserver(conn); | |
| 82 return conn; | |
| 83 } | |
| 84 | |
| 85 void ProviderImpl::FireSensorChanged(Channel channel, const std::string& data) { | |
| 86 FOR_EACH_OBSERVER(ConnectionImpl, connections_, FireSensorChanged(channel, dat a)); | |
| 87 } | |
| 88 | |
| 89 void ProviderImpl::DeviceStart() { | |
| 90 DCHECK(device_proxy_->BelongsToCurrentThread()); | |
| 91 | |
| 92 static const char* kDeviceEventPath = "/dev/device0:event0"; | |
| 93 static const char* kEnableEventPath = | |
| 94 "/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
| |
| 95 | |
| 96 int ret; | |
| 97 | |
| 98 int fd = open(kDeviceEventPath, O_RDONLY, 0); | |
| 99 if (fd < 0) { | |
| 100 LOG(ERROR) << "Failed to open accelerometer: " << strerror(errno); | |
| 101 LOG(ERROR) << "Orientation will be unavailable until Chrome is restarted."; | |
| 102 return; | |
| 103 } | |
| 104 | |
| 105 ret = file_util::WriteFile(FilePath(kEnableEventPath), "1\n", 2); | |
| 106 if (ret < 0) { | |
| 107 LOG(ERROR) << "Failed to enable accelerometer: " << strerror(errno); | |
| 108 LOG(ERROR) << "Orientation will be unavailable until Chrome is restarted."; | |
| 109 return; | |
| 110 } | |
| 111 | |
| 112 device_fd_ = fd; | |
| 113 device_proxy_->PostDelayedTask(FROM_HERE, | |
| 114 NewRunnableMethod(this, &ProviderImpl::DeviceRead), 1000); | |
| 115 } | |
| 116 | |
| 117 struct iio_event { | |
| 118 uint32 code; | |
| 119 uint32 unused; | |
| 120 uint64 time; | |
| 121 }; | |
| 122 | |
| 123 void ProviderImpl::DeviceRead() { | |
| 124 DCHECK(device_proxy_->BelongsToCurrentThread()); | |
| 125 | |
| 126 if (!DoDeviceRead()) { | |
| 127 LOG(ERROR) << "Orientation will be unavailable until Chrome is restarted."; | |
| 128 return; | |
| 129 } | |
| 130 | |
| 131 device_proxy_->PostTask(FROM_HERE, | |
| 132 NewRunnableMethod(this, &ProviderImpl::DeviceRead)); | |
| 133 } | |
| 134 | |
| 135 bool ProviderImpl::DoDeviceRead() { | |
| 136 DCHECK(device_proxy_->BelongsToCurrentThread()); | |
| 137 DCHECK(device_fd_ != -1); | |
| 138 | |
| 139 ssize_t rv = read(device_fd_, device_buf_ + device_buf_end_, | |
| 140 sizeof(device_buf_) - device_buf_end_); | |
| 141 if (rv < 0) { | |
| 142 if (errno == EAGAIN || errno == EWOULDBLOCK) | |
| 143 return true; // Do not have any data to read | |
| 144 | |
| 145 LOG(ERROR) << "Failed to read accelerometer events: " << strerror(errno); | |
| 146 return false; | |
| 147 } | |
| 148 device_buf_end_ += rv; | |
| 149 | |
| 150 if (device_buf_end_ < kIIOMessageSize) | |
| 151 return true; // Do not have a complete message yet | |
| 152 | |
| 153 device_buf_end_ = 0; | |
| 154 | |
| 155 struct iio_event* event = reinterpret_cast<struct iio_event*>(device_buf_); | |
| 156 | |
| 157 // HACK: These orientations are rearranged from their definitions in the | |
| 158 // accelerometer driver so that the development devices report their | |
| 159 // orientation correctly. This will eventually be configured in the | |
| 160 // sensor manager, and the data received by Chrome will be correct. | |
| 161 ScreenOrientationChange change; | |
| 162 switch (event->code >> 8) { | |
| 163 case 0: change.upward = ScreenOrientationChange::TOP; break; | |
| 164 case 1: change.upward = ScreenOrientationChange::BOTTOM; break; | |
| 165 case 2: change.upward = ScreenOrientationChange::RIGHT; break; | |
| 166 case 3: change.upward = ScreenOrientationChange::LEFT; break; | |
| 167 case 4: change.upward = ScreenOrientationChange::FRONT; break; | |
| 168 case 5: change.upward = ScreenOrientationChange::BACK; break; | |
| 169 default: return true; // drop unknown orientation | |
| 170 } | |
| 171 | |
| 172 std::string data(reinterpret_cast<const char*>(&change), sizeof(change)); | |
| 173 FireSensorChanged(kScreenOrientationChannel, data); | |
| 174 return true; | |
| 175 } | |
| 176 | |
| 177 void ProviderImpl::DeviceStop() { | |
| 178 DCHECK(device_proxy_->BelongsToCurrentThread()); | |
| 179 | |
| 180 close(device_fd_); | |
| 181 device_fd_ = -1; | |
| 182 } | |
| 183 | |
| 184 void ProviderImpl::ConnectionClosed(ConnectionImpl* conn) { | |
| 185 connections_.RemoveObserver(conn); | |
| 186 } | |
| 187 | |
| 188 void ProviderImpl::ConnectionStarted(ConnectionImpl* conn, | |
| 189 Channel channel, const std::string& data) { | |
| 190 | |
| 191 connections_.AddObserver(conn); | |
| 192 } | |
| 193 | |
| 194 void ProviderImpl::ConnectionStopped(ConnectionImpl* conn, Channel channel) { | |
| 195 connections_.RemoveObserver(conn); | |
| 196 } | |
| 197 | |
| 198 } // namespace sensors | |
| OLD | NEW |